<commit_before>package multihash

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha512"
	"errors"
	"fmt"

	blake2b "github.com/minio/blake2b-simd"
	sha256 "github.com/minio/sha256-simd"
	murmur3 "github.com/spaolacci/murmur3"
	blake2s "golang.org/x/crypto/blake2s"
	sha3 "golang.org/x/crypto/sha3"
)

// ErrSumNotSupported is returned when the Sum function code is not implemented
var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib maintainer.")

var ErrLenTooLarge = errors.New("requested length was too large for digest")

// HashFunc is a hash function that hashes data into digest.
//
// The length is the size the digest will be truncated to. While the hash
// function isn't responsible for truncating the digest, it may want to error if
// the length is invalid for the hash function (e.g., truncation would make the
// hash useless).
type HashFunc func(data []byte, length int) (digest []byte, err error)

// funcTable maps multicodec values to hash functions.
var funcTable = make(map[uint64]HashFunc)

// Sum obtains the cryptographic sum of a given buffer. The length parameter
// indicates the length of the resulting digest and passing a negative value
// use default length values for the selected hash function.
func Sum(data []byte, code uint64, length int) (Multihash, error) {
	if !ValidCode(code) {
		return nil, fmt.Errorf("invalid multihash code %d", code)
	}

	if length < 0 {
		var ok bool
		length, ok = DefaultLengths[code]
		if !ok {
			return nil, fmt.Errorf("no default length for code %d", code)
		}
	}

	hashFunc, ok := funcTable[code]
	if !ok {
		return nil, ErrSumNotSupported
	}

	d, err := hashFunc(data, length)
	if err != nil {
		return nil, err
	}
	if len(d) < length {
		return nil, ErrLenTooLarge
	}

	if length >= 0 {
		d = d[:length]
	}
	return Encode(d, code)
}

func sumBlake2s(data []byte, size int) ([]byte, error) {
	if size != 32 {
		return nil, fmt.Errorf("unsupported length for blake2s: %d", size)
	}
	d := blake2s.Sum256(data)
	return d[:], nil
}
func sumBlake2b(data []byte, size int) ([]byte, error) {
	hasher, err := blake2b.New(&blake2b.Config{Size: uint8(size)})
	if err != nil {
		return nil, err
	}

	if _, err := hasher.Write(data); err != nil {
		return nil, err
	}

	return hasher.Sum(nil)[:], nil
}

func sumID(data []byte, length int) ([]byte, error) {
	if length >= 0 && length != len(data) {
		return nil, fmt.Errorf("the length of the identity hash (%d) must be equal to the length of the data (%d)",
			length, len(data))

	}
	return data, nil
}

func sumSHA1(data []byte, length int) ([]byte, error) {
	a := sha1.Sum(data)
	return a[0:20], nil
}

func sumSHA256(data []byte, length int) ([]byte, error) {
	a := sha256.Sum256(data)
	return a[0:32], nil
}

func sumMD5(data []byte, length int) ([]byte, error) {
	a := md5.Sum(data)
	return a[0:md5.Size], nil
}

func sumDoubleSHA256(data []byte, length int) ([]byte, error) {
	val, _ := sumSHA256(data, len(data))
	return sumSHA256(val, len(val))
}

func sumSHA512(data []byte, length int) ([]byte, error) {
	a := sha512.Sum512(data)
	return a[0:64], nil
}
func sumKeccak256(data []byte, length int) ([]byte, error) {
	h := sha3.NewLegacyKeccak256()
	h.Write(data)
	return h.Sum(nil), nil
}

func sumKeccak512(data []byte, length int) ([]byte, error) {
	h := sha3.NewLegacyKeccak512()
	h.Write(data)
	return h.Sum(nil), nil
}

func sumSHA3_512(data []byte, length int) ([]byte, error) {
	a := sha3.Sum512(data)
	return a[:], nil
}

func sumMURMUR3(data []byte, length int) ([]byte, error) {
	number := murmur3.Sum32(data)
	bytes := make([]byte, 4)
	for i := range bytes {
		bytes[i] = byte(number & 0xff)
		number >>= 8
	}
	return bytes, nil
}

func sumSHAKE128(data []byte, length int) ([]byte, error) {
	bytes := make([]byte, 32)
	sha3.ShakeSum128(bytes, data)
	return bytes, nil
}

func sumSHAKE256(data []byte, length int) ([]byte, error) {
	bytes := make([]byte, 64)
	sha3.ShakeSum256(bytes, data)
	return bytes, nil
}

func sumSHA3_384(data []byte, length int) ([]byte, error) {
	a := sha3.Sum384(data)
	return a[:], nil
}

func sumSHA3_256(data []byte, length int) ([]byte, error) {
	a := sha3.Sum256(data)
	return a[:], nil
}

func sumSHA3_224(data []byte, length int) ([]byte, error) {
	a := sha3.Sum224(data)
	return a[:], nil
}

func registerStdlibHashFuncs() {
	RegisterHashFunc(IDENTITY, sumID)
	RegisterHashFunc(SHA1, sumSHA1)
	RegisterHashFunc(SHA2_512, sumSHA512)
	RegisterHashFunc(MD5, sumMD5)
}

func registerNonStdlibHashFuncs() {
	RegisterHashFunc(SHA2_256, sumSHA256)
	RegisterHashFunc(DBL_SHA2_256, sumDoubleSHA256)

	RegisterHashFunc(KECCAK_256, sumKeccak256)
	RegisterHashFunc(KECCAK_512, sumKeccak512)

	RegisterHashFunc(SHA3_224, sumSHA3_224)
	RegisterHashFunc(SHA3_256, sumSHA3_256)
	RegisterHashFunc(SHA3_384, sumSHA3_384)
	RegisterHashFunc(SHA3_512, sumSHA3_512)

	RegisterHashFunc(MURMUR3_128, sumMURMUR3)

	RegisterHashFunc(SHAKE_128, sumSHAKE128)
	RegisterHashFunc(SHAKE_256, sumSHAKE256)

	// Blake family of hash functions
	// BLAKE2S
	for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ {
		size := int(c - BLAKE2S_MIN + 1)
		RegisterHashFunc(c, func(buf []byte, _ int) ([]byte, error) {
			return sumBlake2s(buf, size)
		})
	}
	// BLAKE2B
	for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ {
		size := int(c - BLAKE2B_MIN + 1)
		RegisterHashFunc(c, func(buf []byte, _ int) ([]byte, error) {
			return sumBlake2b(buf, size)
		})
	}
}

func init() {
	registerStdlibHashFuncs()
	registerNonStdlibHashFuncs()
}

// RegisterHashFunc adds an entry to the package-level code -> hash func map.
// The hash function must return at least the requested number of bytes. If it
// returns more, the hash will be truncated.
func RegisterHashFunc(code uint64, hashFunc HashFunc) error {
	if !ValidCode(code) {
		return fmt.Errorf("code %v not valid", code)
	}

	_, ok := funcTable[code]
	if ok {
		return fmt.Errorf("hash func for code %v already registered", code)
	}

	funcTable[code] = hashFunc
	return nil
}
<commit_msg>feat: reduce blake2b allocations by special-casing the 256/512 variants<commit_after>package multihash

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha512"
	"errors"
	"fmt"

	blake2b "github.com/minio/blake2b-simd"
	sha256 "github.com/minio/sha256-simd"
	murmur3 "github.com/spaolacci/murmur3"
	blake2s "golang.org/x/crypto/blake2s"
	sha3 "golang.org/x/crypto/sha3"
)

// ErrSumNotSupported is returned when the Sum function code is not implemented
var ErrSumNotSupported = errors.New("Function not implemented. Complain to lib maintainer.")

var ErrLenTooLarge = errors.New("requested length was too large for digest")

// HashFunc is a hash function that hashes data into digest.
//
// The length is the size the digest will be truncated to. While the hash
// function isn't responsible for truncating the digest, it may want to error if
// the length is invalid for the hash function (e.g., truncation would make the
// hash useless).
type HashFunc func(data []byte, length int) (digest []byte, err error)

// funcTable maps multicodec values to hash functions.
var funcTable = make(map[uint64]HashFunc)

// Sum obtains the cryptographic sum of a given buffer. The length parameter
// indicates the length of the resulting digest and passing a negative value
// use default length values for the selected hash function.
func Sum(data []byte, code uint64, length int) (Multihash, error) {
	if !ValidCode(code) {
		return nil, fmt.Errorf("invalid multihash code %d", code)
	}

	if length < 0 {
		var ok bool
		length, ok = DefaultLengths[code]
		if !ok {
			return nil, fmt.Errorf("no default length for code %d", code)
		}
	}

	hashFunc, ok := funcTable[code]
	if !ok {
		return nil, ErrSumNotSupported
	}

	d, err := hashFunc(data, length)
	if err != nil {
		return nil, err
	}
	if len(d) < length {
		return nil, ErrLenTooLarge
	}

	if length >= 0 {
		d = d[:length]
	}
	return Encode(d, code)
}

func sumBlake2s(data []byte, size int) ([]byte, error) {
	if size != 32 {
		return nil, fmt.Errorf("unsupported length for blake2s: %d", size)
	}
	d := blake2s.Sum256(data)
	return d[:], nil
}
func sumBlake2b(data []byte, size int) ([]byte, error) {
	// special case these lengths to avoid allocations.
	switch size {
	case 32:
		hash := blake2b.Sum256(data)
		return hash[:], nil
	case 64:
		hash := blake2b.Sum512(data)
		return hash[:], nil
	}

	// Ok, allocate away.
	hasher, err := blake2b.New(&blake2b.Config{Size: uint8(size)})
	if err != nil {
		return nil, err
	}

	if _, err := hasher.Write(data); err != nil {
		return nil, err
	}

	return hasher.Sum(nil)[:], nil
}

func sumID(data []byte, length int) ([]byte, error) {
	if length >= 0 && length != len(data) {
		return nil, fmt.Errorf("the length of the identity hash (%d) must be equal to the length of the data (%d)",
			length, len(data))

	}
	return data, nil
}

func sumSHA1(data []byte, length int) ([]byte, error) {
	a := sha1.Sum(data)
	return a[0:20], nil
}

func sumSHA256(data []byte, length int) ([]byte, error) {
	a := sha256.Sum256(data)
	return a[0:32], nil
}

func sumMD5(data []byte, length int) ([]byte, error) {
	a := md5.Sum(data)
	return a[0:md5.Size], nil
}

func sumDoubleSHA256(data []byte, length int) ([]byte, error) {
	val, _ := sumSHA256(data, len(data))
	return sumSHA256(val, len(val))
}

func sumSHA512(data []byte, length int) ([]byte, error) {
	a := sha512.Sum512(data)
	return a[0:64], nil
}
func sumKeccak256(data []byte, length int) ([]byte, error) {
	h := sha3.NewLegacyKeccak256()
	h.Write(data)
	return h.Sum(nil), nil
}

func sumKeccak512(data []byte, length int) ([]byte, error) {
	h := sha3.NewLegacyKeccak512()
	h.Write(data)
	return h.Sum(nil), nil
}

func sumSHA3_512(data []byte, length int) ([]byte, error) {
	a := sha3.Sum512(data)
	return a[:], nil
}

func sumMURMUR3(data []byte, length int) ([]byte, error) {
	number := murmur3.Sum32(data)
	bytes := make([]byte, 4)
	for i := range bytes {
		bytes[i] = byte(number & 0xff)
		number >>= 8
	}
	return bytes, nil
}

func sumSHAKE128(data []byte, length int) ([]byte, error) {
	bytes := make([]byte, 32)
	sha3.ShakeSum128(bytes, data)
	return bytes, nil
}

func sumSHAKE256(data []byte, length int) ([]byte, error) {
	bytes := make([]byte, 64)
	sha3.ShakeSum256(bytes, data)
	return bytes, nil
}

func sumSHA3_384(data []byte, length int) ([]byte, error) {
	a := sha3.Sum384(data)
	return a[:], nil
}

func sumSHA3_256(data []byte, length int) ([]byte, error) {
	a := sha3.Sum256(data)
	return a[:], nil
}

func sumSHA3_224(data []byte, length int) ([]byte, error) {
	a := sha3.Sum224(data)
	return a[:], nil
}

func registerStdlibHashFuncs() {
	RegisterHashFunc(IDENTITY, sumID)
	RegisterHashFunc(SHA1, sumSHA1)
	RegisterHashFunc(SHA2_512, sumSHA512)
	RegisterHashFunc(MD5, sumMD5)
}

func registerNonStdlibHashFuncs() {
	RegisterHashFunc(SHA2_256, sumSHA256)
	RegisterHashFunc(DBL_SHA2_256, sumDoubleSHA256)

	RegisterHashFunc(KECCAK_256, sumKeccak256)
	RegisterHashFunc(KECCAK_512, sumKeccak512)

	RegisterHashFunc(SHA3_224, sumSHA3_224)
	RegisterHashFunc(SHA3_256, sumSHA3_256)
	RegisterHashFunc(SHA3_384, sumSHA3_384)
	RegisterHashFunc(SHA3_512, sumSHA3_512)

	RegisterHashFunc(MURMUR3_128, sumMURMUR3)

	RegisterHashFunc(SHAKE_128, sumSHAKE128)
	RegisterHashFunc(SHAKE_256, sumSHAKE256)

	// Blake family of hash functions
	// BLAKE2S
	for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ {
		size := int(c - BLAKE2S_MIN + 1)
		RegisterHashFunc(c, func(buf []byte, _ int) ([]byte, error) {
			return sumBlake2s(buf, size)
		})
	}
	// BLAKE2B
	for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ {
		size := int(c - BLAKE2B_MIN + 1)
		RegisterHashFunc(c, func(buf []byte, _ int) ([]byte, error) {
			return sumBlake2b(buf, size)
		})
	}
}

func init() {
	registerStdlibHashFuncs()
	registerNonStdlibHashFuncs()
}

// RegisterHashFunc adds an entry to the package-level code -> hash func map.
// The hash function must return at least the requested number of bytes. If it
// returns more, the hash will be truncated.
func RegisterHashFunc(code uint64, hashFunc HashFunc) error {
	if !ValidCode(code) {
		return fmt.Errorf("code %v not valid", code)
	}

	_, ok := funcTable[code]
	if ok {
		return fmt.Errorf("hash func for code %v already registered", code)
	}

	funcTable[code] = hashFunc
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Unknwon
//
// 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 Seago is a high productive and modular design web framework in Go.
package seago

import (
	"io"
	"log"
	"net/http"
	"os"
	"reflect"
	"strings"

	"github.com/seago/utils"

	"github.com/seago/seago/inject"
)

func Version() string {
	return "0.0.1"
}

// Handler can be any callable function.
// Seago attempts to inject services into the handler's argument list,
// and panics if an argument could not be fullfilled via dependency injection.
type Handler interface{}

// validateHandler makes sure a handler is a callable function,
// and panics if it is not.
func validateHandler(handler Handler) {
	if reflect.TypeOf(handler).Kind() != reflect.Func {
		panic("Web handler must be a callable function")
	}
}

// Seago represents the top level web application.
// inject.Injector methods can be invoked to map services on a global level.
type Seago struct {
	inject.Injector
	befores  []BeforeHandler
	handlers []Handler
	action   Handler

	urlPrefix string // For suburl support.
	*Router

	logger *log.Logger
}

// NewWithLogger creates a bare bones Seago instance.
// Use this method if you want to have full control over the middleware that is used.
// You can specify logger output writer with this function.
func NewWithLogger(out io.Writer) *Seago {
	m := &Seago{
		Injector: inject.New(),
		action:   func() {},
		Router:   NewRouter(),
		logger:   log.New(out, "[SEAGO] ", 0),
	}
	m.Router.m = m
	m.Map(m.logger)
	m.Map(defaultReturnHandler())
	m.notFound = func(resp http.ResponseWriter, req *http.Request) {
		c := m.createContext(resp, req)
		c.handlers = append(c.handlers, http.NotFound)
		c.run()
	}
	return m
}

// New creates a bare bones Seago instance.
// Use this method if you want to have full control over the middleware that is used.
func New() *Seago {
	return NewWithLogger(os.Stdout)
}

// Classic creates a classic Macaron with some basic default middleware:
// Web.Logger, Web.Recovery and Web.Static.
func Classic() *Seago {
	m := New()
	m.Use(Logger())
	m.Use(Recovery())
	m.Use(Static("public"))
	return m
}

// Handlers sets the entire middleware stack with the given Handlers.
// This will clear any current middleware handlers,
// and panics if any of the handlers is not a callable function
func (m *Seago) Handlers(handlers ...Handler) {
	m.handlers = make([]Handler, 0)
	for _, handler := range handlers {
		m.Use(handler)
	}
}

// Action sets the handler that will be called after all the middleware has been invoked.
// This is set to macaron.Router in a macaron.Classic().
func (m *Seago) Action(handler Handler) {
	validateHandler(handler)
	m.action = handler
}

// BeforeHandler represents a handler executes at beginning of every request.
// Macaron stops future process when it returns true.
type BeforeHandler func(rw http.ResponseWriter, req *http.Request) bool

func (m *Seago) Before(handler BeforeHandler) {
	m.befores = append(m.befores, handler)
}

// Use adds a middleware Handler to the stack,
// and panics if the handler is not a callable func.
// Middleware Handlers are invoked in the order that they are added.
func (m *Seago) Use(handler Handler) {
	validateHandler(handler)
	m.handlers = append(m.handlers, handler)
}

func (m *Seago) createContext(rw http.ResponseWriter, req *http.Request) *Context {
	c := &Context{
		Injector: inject.New(),
		handlers: m.handlers,
		action:   m.action,
		index:    0,
		Router:   m.Router,
		Request:  Request{req},
		Response: NewResponseWriter(rw),
		Data:     make(map[string]interface{}),
		statics:  make(map[string]*http.Dir),
	}
	c.SetParent(m)
	c.Map(c)
	c.MapTo(c.Response, (*http.ResponseWriter)(nil))
	c.Map(req)
	return c
}

// ServeHTTP is the HTTP Entry point for a Macaron instance.
// Useful if you want to control your own HTTP server.
// Be aware that none of middleware will run without registering any router.
func (m *Seago) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	req.URL.Path = strings.TrimPrefix(req.URL.Path, m.urlPrefix)
	for _, h := range m.befores {
		if h(rw, req) {
			return
		}
	}
	m.Router.ServeHTTP(rw, req)
}

func GetDefaultListenInfo() (string, int) {
	host := os.Getenv("HOST")
	if len(host) == 0 {
		host = "0.0.0.0"
	}
	port := utils.StrTo(os.Getenv("PORT")).MustInt()
	if port == 0 {
		port = 4000
	}
	return host, port
}

// Run the http server. Listening on os.GetEnv("PORT") or 4000 by default.
func (m *Seago) Run(args ...interface{}) {
	host, port := GetDefaultListenInfo()
	if len(args) == 1 {
		switch arg := args[0].(type) {
		case string:
			host = arg
		case int:
			port = arg
		}
	} else if len(args) >= 2 {
		if arg, ok := args[0].(string); ok {
			host = arg
		}
		if arg, ok := args[1].(int); ok {
			port = arg
		}
	}

	addr := host + ":" + utils.ToStr(port)
	logger := m.Injector.GetVal(reflect.TypeOf(m.logger)).Interface().(*log.Logger)
	logger.Printf("listening on %s (%s)\n", addr, Env)
	logger.Fatalln(http.ListenAndServe(addr, m))
}

// SetURLPrefix sets URL prefix of router layer, so that it support suburl.
func (m *Seago) SetURLPrefix(prefix string) {
	m.urlPrefix = prefix
}

// ____   ____            .__      ___.   .__
// \   \ /   /____ _______|__|____ \_ |__ |  |   ____   ______
//  \   Y   /\__  \\_  __ \  \__  \ | __ \|  | _/ __ \ /  ___/
//   \     /  / __ \|  | \/  |/ __ \| \_\ \  |_\  ___/ \___ \
//    \___/  (____  /__|  |__(____  /___  /____/\___  >____  >
//                \/              \/    \/          \/     \/

const (
	DEV  string = "development"
	PROD string = "production"
	TEST string = "test"
)

var (
	// Env is the environment that Macaron is executing in.
	// The MACARON_ENV is read on initialization to set this variable.
	Env = DEV

	// Path of work directory.
	Root string

	// Flash applies to current request.
	FlashNow bool
)

func setENV(e string) {
	if len(e) > 0 {
		Env = e
	}
}

func init() {
	setENV(os.Getenv("MACARON_ENV"))
	var err error
	Root, err = os.Getwd()
	if err != nil {
		panic(err)
	}
}
<commit_msg>修改ENV名<commit_after>// Copyright 2014 Unknwon
//
// 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 Seago is a high productive and modular design web framework in Go.
package seago

import (
	"io"
	"log"
	"net/http"
	"os"
	"reflect"
	"strings"

	"github.com/seago/utils"

	"github.com/seago/seago/inject"
)

func Version() string {
	return "0.0.1"
}

// Handler can be any callable function.
// Seago attempts to inject services into the handler's argument list,
// and panics if an argument could not be fullfilled via dependency injection.
type Handler interface{}

// validateHandler makes sure a handler is a callable function,
// and panics if it is not.
func validateHandler(handler Handler) {
	if reflect.TypeOf(handler).Kind() != reflect.Func {
		panic("Web handler must be a callable function")
	}
}

// Seago represents the top level web application.
// inject.Injector methods can be invoked to map services on a global level.
type Seago struct {
	inject.Injector
	befores  []BeforeHandler
	handlers []Handler
	action   Handler

	urlPrefix string // For suburl support.
	*Router

	logger *log.Logger
}

// NewWithLogger creates a bare bones Seago instance.
// Use this method if you want to have full control over the middleware that is used.
// You can specify logger output writer with this function.
func NewWithLogger(out io.Writer) *Seago {
	m := &Seago{
		Injector: inject.New(),
		action:   func() {},
		Router:   NewRouter(),
		logger:   log.New(out, "[SEAGO] ", 0),
	}
	m.Router.m = m
	m.Map(m.logger)
	m.Map(defaultReturnHandler())
	m.notFound = func(resp http.ResponseWriter, req *http.Request) {
		c := m.createContext(resp, req)
		c.handlers = append(c.handlers, http.NotFound)
		c.run()
	}
	return m
}

// New creates a bare bones Seago instance.
// Use this method if you want to have full control over the middleware that is used.
func New() *Seago {
	return NewWithLogger(os.Stdout)
}

// Classic creates a classic Macaron with some basic default middleware:
// Web.Logger, Web.Recovery and Web.Static.
func Classic() *Seago {
	m := New()
	m.Use(Logger())
	m.Use(Recovery())
	m.Use(Static("public"))
	return m
}

// Handlers sets the entire middleware stack with the given Handlers.
// This will clear any current middleware handlers,
// and panics if any of the handlers is not a callable function
func (m *Seago) Handlers(handlers ...Handler) {
	m.handlers = make([]Handler, 0)
	for _, handler := range handlers {
		m.Use(handler)
	}
}

// Action sets the handler that will be called after all the middleware has been invoked.
// This is set to macaron.Router in a macaron.Classic().
func (m *Seago) Action(handler Handler) {
	validateHandler(handler)
	m.action = handler
}

// BeforeHandler represents a handler executes at beginning of every request.
// Macaron stops future process when it returns true.
type BeforeHandler func(rw http.ResponseWriter, req *http.Request) bool

func (m *Seago) Before(handler BeforeHandler) {
	m.befores = append(m.befores, handler)
}

// Use adds a middleware Handler to the stack,
// and panics if the handler is not a callable func.
// Middleware Handlers are invoked in the order that they are added.
func (m *Seago) Use(handler Handler) {
	validateHandler(handler)
	m.handlers = append(m.handlers, handler)
}

func (m *Seago) createContext(rw http.ResponseWriter, req *http.Request) *Context {
	c := &Context{
		Injector: inject.New(),
		handlers: m.handlers,
		action:   m.action,
		index:    0,
		Router:   m.Router,
		Request:  Request{req},
		Response: NewResponseWriter(rw),
		Data:     make(map[string]interface{}),
		statics:  make(map[string]*http.Dir),
	}
	c.SetParent(m)
	c.Map(c)
	c.MapTo(c.Response, (*http.ResponseWriter)(nil))
	c.Map(req)
	return c
}

// ServeHTTP is the HTTP Entry point for a Macaron instance.
// Useful if you want to control your own HTTP server.
// Be aware that none of middleware will run without registering any router.
func (m *Seago) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	req.URL.Path = strings.TrimPrefix(req.URL.Path, m.urlPrefix)
	for _, h := range m.befores {
		if h(rw, req) {
			return
		}
	}
	m.Router.ServeHTTP(rw, req)
}

func GetDefaultListenInfo() (string, int) {
	host := os.Getenv("HOST")
	if len(host) == 0 {
		host = "0.0.0.0"
	}
	port := utils.StrTo(os.Getenv("PORT")).MustInt()
	if port == 0 {
		port = 4000
	}
	return host, port
}

// Run the http server. Listening on os.GetEnv("PORT") or 4000 by default.
func (m *Seago) Run(args ...interface{}) {
	host, port := GetDefaultListenInfo()
	if len(args) == 1 {
		switch arg := args[0].(type) {
		case string:
			host = arg
		case int:
			port = arg
		}
	} else if len(args) >= 2 {
		if arg, ok := args[0].(string); ok {
			host = arg
		}
		if arg, ok := args[1].(int); ok {
			port = arg
		}
	}

	addr := host + ":" + utils.ToStr(port)
	logger := m.Injector.GetVal(reflect.TypeOf(m.logger)).Interface().(*log.Logger)
	logger.Printf("listening on %s (%s)\n", addr, Env)
	logger.Fatalln(http.ListenAndServe(addr, m))
}

// SetURLPrefix sets URL prefix of router layer, so that it support suburl.
func (m *Seago) SetURLPrefix(prefix string) {
	m.urlPrefix = prefix
}

// ____   ____            .__      ___.   .__
// \   \ /   /____ _______|__|____ \_ |__ |  |   ____   ______
//  \   Y   /\__  \\_  __ \  \__  \ | __ \|  | _/ __ \ /  ___/
//   \     /  / __ \|  | \/  |/ __ \| \_\ \  |_\  ___/ \___ \
//    \___/  (____  /__|  |__(____  /___  /____/\___  >____  >
//                \/              \/    \/          \/     \/

const (
	DEV  string = "development"
	PROD string = "production"
	TEST string = "test"
)

var (
	// Env is the environment that Macaron is executing in.
	// The MACARON_ENV is read on initialization to set this variable.
	Env = DEV

	// Path of work directory.
	Root string

	// Flash applies to current request.
	FlashNow bool
)

func setENV(e string) {
	if len(e) > 0 {
		Env = e
	}
}

func init() {
	setENV(os.Getenv("SEAGO_ENV"))
	var err error
	Root, err = os.Getwd()
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package openrtb2

import (
	"encoding/json"

	"github.com/mxmCherry/openrtb/v16/adcom1"
)

// 4.3.19 Object: Bid
//
// A SeatBid object contains one or more Bid objects, each of which relates to a specific impression in the bid request via the impid attribute and constitutes an offer to buy that impression for a given price.
//
// For each bid, the nurl attribute contains the win notice URL.
// If the bidder wins the impression, the exchange calls this notice URL to inform the bidder of the win and to convey certain information using substitution macros (see Section 4.4) such as the clearing price.
// The win notice return or the adm attribute can be used to serve markup (see Section 4.3).
// In either case, the exchange will also apply the aforementioned substitution to any macros found in the markup.
//
// BEST PRACTICE: The essential function of the win notice is to inform a bidder that they won an auction.
// It does not necessarily imply ad delivery, creative viewability, or billability.
// Exchanges are highly encouraged to publish to their bidders their event triggers, billing policies, and any other meaning they attach to the win notice.
// Also, please refer to Section 7.2 for additional guidance on expirations.
//
// BEST PRACTICE: Firing of the billing notice should be server-side and as “close” as possible to where the exchange books revenue in order to minimize discrepancies between exchange and bidder.
//
// BEST PRACTICE: For VAST Video, the IAB prescribes that the VAST impression event is the official signal that the impression is billable.
// If the burl attribute is specified, it too should be fired at the same time if the exchange is adhering to this policy.
// However, subtle technical issues may lead to additional discrepancies and bidders are cautioned to avoid this scenario.
//
// Several other attributes are used for ad quality checks or enforcing publisher restrictions.
// These include the advertiser domain via adomain, a non-cache-busted URL to an image representative of the content of the campaign via iurl, an ID of the campaign and of the creative within the campaign via cid and crid respectively, an array of creative attribute via attr, and the dimensions via h and w.
// If the bid pertains to a private marketplace deal, the dealid attribute is used to reference that agreement from the bid request.
type Bid struct {

	// Attribute:
	//   id
	// Type:
	//   string; required
	// Description:
	//   Bidder generated bid ID to assist with logging/tracking.
	ID string `json:"id"`

	// Attribute:
	//   impid
	// Type:
	//   string; required
	// Description:
	//   ID of the Imp object in the related bid request.
	ImpID string `json:"impid"`

	// Attribute:
	//   price
	// Type:
	//   float; required
	// Description:
	//   Bid price expressed as CPM although the actual transaction is
	//   for a unit impression only. Note that while the type indicates
	//   float, integer math is highly recommended when handling
	//   currencies (e.g., BigDecimal in Java).
	Price float64 `json:"price"`

	// Attribute:
	//   nurl
	// Type:
	//   string
	// Description:
	//   Win notice URL called by the exchange if the bid wins (not
	//   necessarily indicative of a delivered, viewed, or billable ad);
	//   optional means of serving ad markup. Substitution macros
	//   (Section 4.4) may be included in both the URL and optionally
	//   returned markup.
	NURL string `json:"nurl,omitempty"`

	// Attribute:
	//   burl
	// Type:
	//   string
	// Description:
	//   Billing notice URL called by the exchange when a winning bid
	//   becomes billable based on exchange-specific business policy
	//   (e.g., typically delivered, viewed, etc.). Substitution macros
	//   (Section 4.4) may be included.
	BURL string `json:"burl,omitempty"`

	// Attribute:
	//   lurl
	// Type:
	//   string
	// Description:
	//   Loss notice URL called by the exchange when a bid is known to
	//   have been lost. Substitution macros (Section 4.4) may be
	//   included. Exchange-specific policy may preclude support for
	//   loss notices or the disclosure of winning clearing prices
	//   resulting in ${AUCTION_PRICE} macros being removed (i.e.,
	//   replaced with a zero-length string).
	LURL string `json:"lurl,omitempty"`

	// Attribute:
	//   adm
	// Type:
	//   string
	// Description:
	//   Optional means of conveying ad markup in case the bid wins;
	//   supersedes the win notice if markup is included in both.
	//   Substitution macros (Section 4.4) may be included.
	AdM string `json:"adm,omitempty"`

	// Attribute:
	//   adid
	// Type:
	//   string
	// Description:
	//   ID of a preloaded ad to be served if the bid wins.
	AdID string `json:"adid,omitempty"`

	// Attribute:
	//   adomain
	// Type:
	//   string array
	// Description:
	//   Advertiser domain for block list checking (e.g., “ford.com”).
	//   This can be an array of for the case of rotating creatives.
	//   Exchanges can mandate that only one domain is allowed.
	ADomain []string `json:"adomain,omitempty"`

	// Attribute:
	//   bundle
	// Type:
	//   string
	// Description:
	//   A platform-specific application identifier intended to be
	//   unique to the app and independent of the exchange. On
	//   Android, this should be a bundle or package name (e.g.,
	//   com.foo.mygame). On iOS, it is a numeric ID.
	Bundle string `json:"bundle,omitempty"`

	// Attribute:
	//   iurl
	// Type:
	//   string
	// Description:
	//   URL without cache-busting to an image that is representative
	//   of the content of the campaign for ad quality/safety checking.
	IURL string `json:"iurl,omitempty"`

	// Attribute:
	//   cid
	// Type:
	//   string
	// Description:
	//   Campaign ID to assist with ad quality checking; the collection
	//   of creatives for which iurl should be representative.
	CID string `json:"cid,omitempty"`

	// Attribute:
	//   crid
	// Type:
	//   string
	// Description:
	//   Creative ID to assist with ad quality checking
	CrID string `json:"crid,omitempty"`

	// Attribute:
	//   tactic
	// Type:
	//   string
	// Description:
	//   Tactic ID to enable buyers to label bids for reporting to the
	//   exchange the tactic through which their bid was submitted.
	//   The specific usage and meaning of the tactic ID should be
	//   communicated between buyer and exchanges a priori.
	Tactic string `json:"tactic,omitempty"`

	// Attribute:
	//   cattax
	// Type:
	//   integer
	// Description:
	//   The taxonomy in use. Refer to the AdCOM 1.0 list List: Category
	//   Taxonomies for values.
	CatTax adcom1.CategoryTaxonomy `json:"cattax,omitempty"`

	// Attribute:
	//   cat
	// Type:
	//   string array
	// Description:
	//   IAB content categories of the creative. The taxonomy to be
	//   used is defined by the cattax field. If no cattax field is supplied
	//   IAB Content Category Taxonomy 1.0 is assumed.
	Cat []string `json:"cat,omitempty"`

	// Attribute:
	//   attr
	// Type:
	//   integer array
	// Description:
	//   Set of attributes describing the creative. Refer to List: Creative
	//   Attributes in AdCOM 1.0.
	Attr []adcom1.CreativeAttribute `json:"attr,omitempty"`

	// Attribute:
	//   apis
	// Type:
	//   integer array
	// Description:
	//   List of supported APIs for the markup. If an API is not explicitly
	//   listed, it is assumed to be unsupported. Refer to List: API
	//   Frameworks in AdCOM 1.0.
	APIs int64 `json:"apis,omitempty"`

	// Attribute:
	//   api
	// Type:
	//   integer; DEPRECATED
	// Description:
	//   NOTE: Deprecated in favor of the apis integer array.
	//   API required by the markup if applicable. Refer to List: API
	//   Frameworks in AdCOM 1.0.
	API int64 `json:"api,omitempty"`

	// Attribute:
	//   protocol
	// Type:
	//   integer
	// Description:
	//   Video response protocol of the markup if applicable. Refer to
	//   List: Creative Subtypes - Audio/Video in AdCOM 1.0.
	Protocol adcom1.MediaCreativeSubtype `json:"protocol,omitempty"`

	// Attribute:
	//   qagmediarating
	// Type:
	//   integer
	// Description:
	//   Media rating per IQG guidelines. Refer to List: Media Ratings in
	//  AdCOM 1.0.
	QAGMediaRating int8 `json:"qagmediarating,omitempty"`

	// Attribute:
	//   language
	// Type:
	//   string
	// Description:
	//   Language of the creative using ISO-639-1-alpha-2. The nonstandard code “xx” may also be used if the creative has no
	//   linguistic content (e.g., a banner with just a company logo).
	//   Only one of language or langb should be present.
	Language string `json:"language,omitempty"`

	// Attribute:
	//   langb
	// Type:
	//   string
	// Description:
	//   Language of the creative using IETF BCP 47. Only one of
	//   language or langb should be present
	LangB string `json:"langb,omitempty"`

	// Attribute:
	//   dealid
	// Type:
	//   string
	// Description:
	//   Reference to the deal.id from the bid request if this bid
	//   pertains to a private marketplace direct deal.
	DealID string `json:"dealid,omitempty"`

	// Attribute:
	//   w
	// Type:
	//   integer
	// Description:
	//   Width of the creative in device independent pixels (DIPS).
	W int64 `json:"w,omitempty"`

	// Attribute:
	//   h
	// Type:
	//   integer
	// Description:
	//   Height of the creative in device independent pixels (DIPS).
	H int64 `json:"h,omitempty"`

	// Attribute:
	//   wratio
	// Type:
	//   integer
	// Description:
	//   Relative width of the creative when expressing size as a ratio.
	//   Required for Flex Ads.
	WRatio int64 `json:"wratio,omitempty"`

	// Attribute:
	//   hratio
	// Type:
	//   integer
	// Description:
	//   Relative height of the creative when expressing size as a ratio.
	//   Required for Flex Ads.
	HRatio int64 `json:"hratio,omitempty"`

	// Attribute:
	//   exp
	// Type:
	//   integer
	// Description:
	//   Advisory as to the number of seconds the bidder is willing to
	//   wait between the auction and the actual impression.
	Exp int64 `json:"exp,omitempty"`

	// Attribute:
	//   dur
	// Type:
	//   integer
	// Description:
	//   Duration of the video or audio creative in seconds.
	Dur int64 `json:"dur,omitempty"`

	// Attribute:
	//   mtype
	// Type:
	//   integer
	// Description:
	//   Type of the creative markup so that it can properly be
	//   associated with the right sub-object of the BidRequest.Imp.
	//   Values:
	//   1 = Banner
	//   2 = Video
	//   3 = Audio
	//   4 = Native
	MType int8 `json:"mtype,omitempty"`

	// Attribute:
	//   slotinpod
	// Type:
	//   integer
	// Description:
	//   Indicates that the bid response is only eligible for a specific
	//   position within a video or audio ad pod (e.g. first position,
	//   last position, or any). Refer to List: Slot Position in Pod in
	//   AdCOM 1.0 for guidance on the use of this field.
	SlotInPod adcom1.SlotPositionInPod `json:"slotinpod,omitempty"`

	// Attribute:
	//   ext
	// Type:
	//   object
	// Description:
	//   Placeholder for bidder-specific extensions to OpenRTB
	Ext json.RawMessage `json:"ext,omitempty"`
}
<commit_msg>Added Note For Attr Enum<commit_after>package openrtb2

import (
	"encoding/json"

	"github.com/mxmCherry/openrtb/v16/adcom1"
)

// 4.3.19 Object: Bid
//
// A SeatBid object contains one or more Bid objects, each of which relates to a specific impression in the bid request via the impid attribute and constitutes an offer to buy that impression for a given price.
//
// For each bid, the nurl attribute contains the win notice URL.
// If the bidder wins the impression, the exchange calls this notice URL to inform the bidder of the win and to convey certain information using substitution macros (see Section 4.4) such as the clearing price.
// The win notice return or the adm attribute can be used to serve markup (see Section 4.3).
// In either case, the exchange will also apply the aforementioned substitution to any macros found in the markup.
//
// BEST PRACTICE: The essential function of the win notice is to inform a bidder that they won an auction.
// It does not necessarily imply ad delivery, creative viewability, or billability.
// Exchanges are highly encouraged to publish to their bidders their event triggers, billing policies, and any other meaning they attach to the win notice.
// Also, please refer to Section 7.2 for additional guidance on expirations.
//
// BEST PRACTICE: Firing of the billing notice should be server-side and as “close” as possible to where the exchange books revenue in order to minimize discrepancies between exchange and bidder.
//
// BEST PRACTICE: For VAST Video, the IAB prescribes that the VAST impression event is the official signal that the impression is billable.
// If the burl attribute is specified, it too should be fired at the same time if the exchange is adhering to this policy.
// However, subtle technical issues may lead to additional discrepancies and bidders are cautioned to avoid this scenario.
//
// Several other attributes are used for ad quality checks or enforcing publisher restrictions.
// These include the advertiser domain via adomain, a non-cache-busted URL to an image representative of the content of the campaign via iurl, an ID of the campaign and of the creative within the campaign via cid and crid respectively, an array of creative attribute via attr, and the dimensions via h and w.
// If the bid pertains to a private marketplace deal, the dealid attribute is used to reference that agreement from the bid request.
type Bid struct {

	// Attribute:
	//   id
	// Type:
	//   string; required
	// Description:
	//   Bidder generated bid ID to assist with logging/tracking.
	ID string `json:"id"`

	// Attribute:
	//   impid
	// Type:
	//   string; required
	// Description:
	//   ID of the Imp object in the related bid request.
	ImpID string `json:"impid"`

	// Attribute:
	//   price
	// Type:
	//   float; required
	// Description:
	//   Bid price expressed as CPM although the actual transaction is
	//   for a unit impression only. Note that while the type indicates
	//   float, integer math is highly recommended when handling
	//   currencies (e.g., BigDecimal in Java).
	Price float64 `json:"price"`

	// Attribute:
	//   nurl
	// Type:
	//   string
	// Description:
	//   Win notice URL called by the exchange if the bid wins (not
	//   necessarily indicative of a delivered, viewed, or billable ad);
	//   optional means of serving ad markup. Substitution macros
	//   (Section 4.4) may be included in both the URL and optionally
	//   returned markup.
	NURL string `json:"nurl,omitempty"`

	// Attribute:
	//   burl
	// Type:
	//   string
	// Description:
	//   Billing notice URL called by the exchange when a winning bid
	//   becomes billable based on exchange-specific business policy
	//   (e.g., typically delivered, viewed, etc.). Substitution macros
	//   (Section 4.4) may be included.
	BURL string `json:"burl,omitempty"`

	// Attribute:
	//   lurl
	// Type:
	//   string
	// Description:
	//   Loss notice URL called by the exchange when a bid is known to
	//   have been lost. Substitution macros (Section 4.4) may be
	//   included. Exchange-specific policy may preclude support for
	//   loss notices or the disclosure of winning clearing prices
	//   resulting in ${AUCTION_PRICE} macros being removed (i.e.,
	//   replaced with a zero-length string).
	LURL string `json:"lurl,omitempty"`

	// Attribute:
	//   adm
	// Type:
	//   string
	// Description:
	//   Optional means of conveying ad markup in case the bid wins;
	//   supersedes the win notice if markup is included in both.
	//   Substitution macros (Section 4.4) may be included.
	AdM string `json:"adm,omitempty"`

	// Attribute:
	//   adid
	// Type:
	//   string
	// Description:
	//   ID of a preloaded ad to be served if the bid wins.
	AdID string `json:"adid,omitempty"`

	// Attribute:
	//   adomain
	// Type:
	//   string array
	// Description:
	//   Advertiser domain for block list checking (e.g., “ford.com”).
	//   This can be an array of for the case of rotating creatives.
	//   Exchanges can mandate that only one domain is allowed.
	ADomain []string `json:"adomain,omitempty"`

	// Attribute:
	//   bundle
	// Type:
	//   string
	// Description:
	//   A platform-specific application identifier intended to be
	//   unique to the app and independent of the exchange. On
	//   Android, this should be a bundle or package name (e.g.,
	//   com.foo.mygame). On iOS, it is a numeric ID.
	Bundle string `json:"bundle,omitempty"`

	// Attribute:
	//   iurl
	// Type:
	//   string
	// Description:
	//   URL without cache-busting to an image that is representative
	//   of the content of the campaign for ad quality/safety checking.
	IURL string `json:"iurl,omitempty"`

	// Attribute:
	//   cid
	// Type:
	//   string
	// Description:
	//   Campaign ID to assist with ad quality checking; the collection
	//   of creatives for which iurl should be representative.
	CID string `json:"cid,omitempty"`

	// Attribute:
	//   crid
	// Type:
	//   string
	// Description:
	//   Creative ID to assist with ad quality checking
	CrID string `json:"crid,omitempty"`

	// Attribute:
	//   tactic
	// Type:
	//   string
	// Description:
	//   Tactic ID to enable buyers to label bids for reporting to the
	//   exchange the tactic through which their bid was submitted.
	//   The specific usage and meaning of the tactic ID should be
	//   communicated between buyer and exchanges a priori.
	Tactic string `json:"tactic,omitempty"`

	// Attribute:
	//   cattax
	// Type:
	//   integer
	// Description:
	//   The taxonomy in use. Refer to the AdCOM 1.0 list List: Category
	//   Taxonomies for values.
	CatTax adcom1.CategoryTaxonomy `json:"cattax,omitempty"`

	// Attribute:
	//   cat
	// Type:
	//   string array
	// Description:
	//   IAB content categories of the creative. The taxonomy to be
	//   used is defined by the cattax field. If no cattax field is supplied
	//   IAB Content Category Taxonomy 1.0 is assumed.
	Cat []string `json:"cat,omitempty"`

	// Attribute:
	//   attr
	// Type:
	//   integer array
	// Description:
	//   Set of attributes describing the creative. Refer to List: Creative
	//   Attributes in AdCOM 1.0.
	// Note:
	//   OpenRTB <=2.5 defined only attributes with IDs 1..17.
	Attr []adcom1.CreativeAttribute `json:"attr,omitempty"`

	// Attribute:
	//   apis
	// Type:
	//   integer array
	// Description:
	//   List of supported APIs for the markup. If an API is not explicitly
	//   listed, it is assumed to be unsupported. Refer to List: API
	//   Frameworks in AdCOM 1.0.
	APIs int64 `json:"apis,omitempty"`

	// Attribute:
	//   api
	// Type:
	//   integer; DEPRECATED
	// Description:
	//   NOTE: Deprecated in favor of the apis integer array.
	//   API required by the markup if applicable. Refer to List: API
	//   Frameworks in AdCOM 1.0.
	API int64 `json:"api,omitempty"`

	// Attribute:
	//   protocol
	// Type:
	//   integer
	// Description:
	//   Video response protocol of the markup if applicable. Refer to
	//   List: Creative Subtypes - Audio/Video in AdCOM 1.0.
	Protocol adcom1.MediaCreativeSubtype `json:"protocol,omitempty"`

	// Attribute:
	//   qagmediarating
	// Type:
	//   integer
	// Description:
	//   Media rating per IQG guidelines. Refer to List: Media Ratings in
	//  AdCOM 1.0.
	QAGMediaRating int8 `json:"qagmediarating,omitempty"`

	// Attribute:
	//   language
	// Type:
	//   string
	// Description:
	//   Language of the creative using ISO-639-1-alpha-2. The nonstandard code “xx” may also be used if the creative has no
	//   linguistic content (e.g., a banner with just a company logo).
	//   Only one of language or langb should be present.
	Language string `json:"language,omitempty"`

	// Attribute:
	//   langb
	// Type:
	//   string
	// Description:
	//   Language of the creative using IETF BCP 47. Only one of
	//   language or langb should be present
	LangB string `json:"langb,omitempty"`

	// Attribute:
	//   dealid
	// Type:
	//   string
	// Description:
	//   Reference to the deal.id from the bid request if this bid
	//   pertains to a private marketplace direct deal.
	DealID string `json:"dealid,omitempty"`

	// Attribute:
	//   w
	// Type:
	//   integer
	// Description:
	//   Width of the creative in device independent pixels (DIPS).
	W int64 `json:"w,omitempty"`

	// Attribute:
	//   h
	// Type:
	//   integer
	// Description:
	//   Height of the creative in device independent pixels (DIPS).
	H int64 `json:"h,omitempty"`

	// Attribute:
	//   wratio
	// Type:
	//   integer
	// Description:
	//   Relative width of the creative when expressing size as a ratio.
	//   Required for Flex Ads.
	WRatio int64 `json:"wratio,omitempty"`

	// Attribute:
	//   hratio
	// Type:
	//   integer
	// Description:
	//   Relative height of the creative when expressing size as a ratio.
	//   Required for Flex Ads.
	HRatio int64 `json:"hratio,omitempty"`

	// Attribute:
	//   exp
	// Type:
	//   integer
	// Description:
	//   Advisory as to the number of seconds the bidder is willing to
	//   wait between the auction and the actual impression.
	Exp int64 `json:"exp,omitempty"`

	// Attribute:
	//   dur
	// Type:
	//   integer
	// Description:
	//   Duration of the video or audio creative in seconds.
	Dur int64 `json:"dur,omitempty"`

	// Attribute:
	//   mtype
	// Type:
	//   integer
	// Description:
	//   Type of the creative markup so that it can properly be
	//   associated with the right sub-object of the BidRequest.Imp.
	//   Values:
	//   1 = Banner
	//   2 = Video
	//   3 = Audio
	//   4 = Native
	MType int8 `json:"mtype,omitempty"`

	// Attribute:
	//   slotinpod
	// Type:
	//   integer
	// Description:
	//   Indicates that the bid response is only eligible for a specific
	//   position within a video or audio ad pod (e.g. first position,
	//   last position, or any). Refer to List: Slot Position in Pod in
	//   AdCOM 1.0 for guidance on the use of this field.
	SlotInPod adcom1.SlotPositionInPod `json:"slotinpod,omitempty"`

	// Attribute:
	//   ext
	// Type:
	//   object
	// Description:
	//   Placeholder for bidder-specific extensions to OpenRTB
	Ext json.RawMessage `json:"ext,omitempty"`
}
<|endoftext|>


<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 graph_test

import (
	"testing"

	. "github.com/jacobsa/ogletest"
)

func TestTraverse(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type TraverseTest struct {
}

var _ SetUpTestSuiteInterface = &TraverseTest{}
var _ TearDownTestSuiteInterface = &TraverseTest{}

func init() { RegisterTestSuite(&TraverseTest{}) }

func (t *TraverseTest) SetUpTestSuite() {
	panic("TODO: GOMAXPROCS")
}

func (t *TraverseTest) TearDownTestSuite() {
	panic("TODO: GOMAXPROCS")
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *TraverseTest) EmptyGraph() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) SimpleRootedTree() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) SimpleDAG() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) MultipleConnectedComponents() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) LargeRootedTree() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) VisitorReturnsError() {
	AssertFalse(true, "TODO")
}
<commit_msg>TraverseTest.TearDownTestSuite<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 graph_test

import (
	"runtime"
	"testing"

	. "github.com/jacobsa/ogletest"
)

func TestTraverse(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type TraverseTest struct {
}

var _ SetUpTestSuiteInterface = &TraverseTest{}

func init() { RegisterTestSuite(&TraverseTest{}) }

func (t *TraverseTest) SetUpTestSuite() {
	// Ensure that we get real parallelism where available.
	runtime.GOMAXPROCS(runtime.NumCPU())
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *TraverseTest) EmptyGraph() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) SimpleRootedTree() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) SimpleDAG() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) MultipleConnectedComponents() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) LargeRootedTree() {
	AssertFalse(true, "TODO")
}

func (t *TraverseTest) VisitorReturnsError() {
	AssertFalse(true, "TODO")
}
<|endoftext|>


<commit_before>package builder

import (
	"fmt"
	"strings"
	"testing"

	"github.com/gernest/ngorm/dialects/ql"
	"github.com/gernest/ngorm/fixture"
	"github.com/gernest/ngorm/search"
)

func TestGroup(t *testing.T) {
	e := fixture.TestEngine()
	s := GroupSQL(e)
	if s != "" {
		t.Errorf("expected an empty string got %s", s)
	}
	by := "location"
	search.Group(e, by)
	s = GroupSQL(e)
	expect := " GROUP BY " + by
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

}

func TestLimitAndOffsetSQL(t *testing.T) {
	e := fixture.TestEngine()
	e.Dialect = ql.Memory()
	limit := 2
	offset := 4
	search.Limit(e, limit)
	search.Offset(e, offset)
	expect := fmt.Sprintf(" LIMIT %d OFFSET %d", limit, offset)
	s := LimitAndOffsetSQL(e)
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

}

func TestPrepareQuerySQL(t *testing.T) {
	e := fixture.TestEngine()
	e.Dialect = ql.Memory()
	search.Limit(e, 1)
	search.Where(e, "name=?", "gernest")
	var user fixture.User
	s, err := PrepareQuerySQL(e, &user)
	if err != nil {
		//t.Error(err)
	}
	fmt.Println(s)
}

func TestWhere(t *testing.T) {
	e := fixture.TestEngine()
	e.Dialect = ql.Memory()

	// Where using Plain SQL
	search.Where(e, "name=?", "gernest")
	var user fixture.User
	s, err := Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect := "(name=$1)"
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// IN
	search.Where(e, "name in (?)", []string{"jinzhu", "jinzhu 2"})
	s, err = Where(e, &user, e.Search.WhereConditions[1])
	if err != nil {
		t.Fatal(err)
	}
	expect = "(name in ($2,$3))"
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// LIKE
	search.Where(e, "name LIKE ?", "%jin%")
	s, err = Where(e, &user, e.Search.WhereConditions[2])
	if err != nil {
		t.Fatal(err)
	}
	expect = "(name LIKE $4)"
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// AND
	search.Where(e, "name = ? AND age >= ?", "jinzhu", "22")
	s, err = Where(e, &user, e.Search.WhereConditions[3])
	if err != nil {
		t.Fatal(err)
	}
	expect = "(name = $5 AND age >= $6)"
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Where with  Map
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, map[string]interface{}{"name": "jinzhu", "age": 20})
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."name"`
	if !strings.Contains(s, expect) {
		t.Errorf("expected %s to containe %s", s, expect)
	}

	// Map when value is nil
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, map[string]interface{}{"name": "jinzhu", "age": nil})
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expected := `("users"."age" IS NULL)`
	if !strings.Contains(s, expected) {
		t.Errorf("expected %s to contain %s", s, expected)
	}

	// Primary Key
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, 10)
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."id" = $1)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	/// Slice of primary Keys
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, []int64{20, 21, 22})
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."id" IN ($1,$2,$3))`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Struct
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, &fixture.User{Name: "jinzhu", Age: 20})
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."age" = $1) AND ("users"."name" = $2)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}
}

func TestNot(t *testing.T) {
	e := fixture.TestEngine()
	e.Dialect = ql.Memory()

	search.Not(e, "name", "gernest")
	var user fixture.User
	s, err := Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect := `("users"."name" <> $1)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Not in
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, "name", []string{"jinzhu", "jinzhu 2"})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."name" NOT IN ($1,$2))`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Not in slice of primary keys
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, []int64{1, 2, 3})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}

	expect = `("users"."id" NOT IN ($1,$2,$3))`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Not in with empty slice
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, []int64{})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}

	expect = ``
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Struct
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, &fixture.Email{Email: "jinzhu"})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}

	expect = `("users"."email" <> $1)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

}
<commit_msg>[builder] Add more tests in TestNot<commit_after>package builder

import (
	"fmt"
	"strings"
	"testing"

	"github.com/gernest/ngorm/dialects/ql"
	"github.com/gernest/ngorm/fixture"
	"github.com/gernest/ngorm/search"
)

func TestGroup(t *testing.T) {
	e := fixture.TestEngine()
	s := GroupSQL(e)
	if s != "" {
		t.Errorf("expected an empty string got %s", s)
	}
	by := "location"
	search.Group(e, by)
	s = GroupSQL(e)
	expect := " GROUP BY " + by
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

}

func TestLimitAndOffsetSQL(t *testing.T) {
	e := fixture.TestEngine()
	e.Dialect = ql.Memory()
	limit := 2
	offset := 4
	search.Limit(e, limit)
	search.Offset(e, offset)
	expect := fmt.Sprintf(" LIMIT %d OFFSET %d", limit, offset)
	s := LimitAndOffsetSQL(e)
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

}

func TestPrepareQuerySQL(t *testing.T) {
	e := fixture.TestEngine()
	e.Dialect = ql.Memory()
	search.Limit(e, 1)
	search.Where(e, "name=?", "gernest")
	var user fixture.User
	s, err := PrepareQuerySQL(e, &user)
	if err != nil {
		//t.Error(err)
	}
	fmt.Println(s)
}

func TestWhere(t *testing.T) {
	e := fixture.TestEngine()
	e.Dialect = ql.Memory()

	// Where using Plain SQL
	search.Where(e, "name=?", "gernest")
	var user fixture.User
	s, err := Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect := "(name=$1)"
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// IN
	search.Where(e, "name in (?)", []string{"jinzhu", "jinzhu 2"})
	s, err = Where(e, &user, e.Search.WhereConditions[1])
	if err != nil {
		t.Fatal(err)
	}
	expect = "(name in ($2,$3))"
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// LIKE
	search.Where(e, "name LIKE ?", "%jin%")
	s, err = Where(e, &user, e.Search.WhereConditions[2])
	if err != nil {
		t.Fatal(err)
	}
	expect = "(name LIKE $4)"
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// AND
	search.Where(e, "name = ? AND age >= ?", "jinzhu", "22")
	s, err = Where(e, &user, e.Search.WhereConditions[3])
	if err != nil {
		t.Fatal(err)
	}
	expect = "(name = $5 AND age >= $6)"
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Where with  Map
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, map[string]interface{}{"name": "jinzhu", "age": 20})
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."name"`
	if !strings.Contains(s, expect) {
		t.Errorf("expected %s to containe %s", s, expect)
	}

	// Map when value is nil
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, map[string]interface{}{"name": "jinzhu", "age": nil})
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expected := `("users"."age" IS NULL)`
	if !strings.Contains(s, expected) {
		t.Errorf("expected %s to contain %s", s, expected)
	}

	// Primary Key
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, 10)
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."id" = $1)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	/// Slice of primary Keys
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, []int64{20, 21, 22})
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."id" IN ($1,$2,$3))`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Struct
	e.Search.WhereConditions = nil
	e.Scope.SQLVars = nil
	search.Where(e, &fixture.User{Name: "jinzhu", Age: 20})
	s, err = Where(e, &user, e.Search.WhereConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."age" = $1) AND ("users"."name" = $2)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}
}

func TestNot(t *testing.T) {
	e := fixture.TestEngine()
	e.Dialect = ql.Memory()

	search.Not(e, "name", "gernest")
	var user fixture.User
	s, err := Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect := `("users"."name" <> $1)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Not in
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, "name", []string{"jinzhu", "jinzhu 2"})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."name" NOT IN ($1,$2))`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Not in slice of primary keys
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, []int64{1, 2, 3})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}

	expect = `("users"."id" NOT IN ($1,$2,$3))`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Not in with empty slice
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, []int64{})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}

	expect = ``
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Struct
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, &fixture.Email{Email: "jinzhu"})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}

	expect = `("users"."email" <> $1)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

	// Map when value is nil
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, map[string]interface{}{"name": "jinzhu", "age": nil})
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expected := `("users"."age" IS NOT NULL)`
	if !strings.Contains(s, expected) {
		t.Errorf("expected %s to contain %s", s, expected)
	}

	// Primary Key
	e.Search.NotConditions = nil
	e.Scope.SQLVars = nil
	search.Not(e, 10)
	s, err = Not(e, &user, e.Search.NotConditions[0])
	if err != nil {
		t.Fatal(err)
	}
	expect = `("users"."id" <> 10)`
	if s != expect {
		t.Errorf("expected %s got %s", expect, s)
	}

}
<|endoftext|>


<commit_before>package iobit

import (
	"encoding/binary"
	"errors"
)

type Writer struct {
	dst   []uint8
	cache uint64
	fill  uint
	err   error
}

type bigEndian struct{}
type littleEndian struct{}

var (
	ErrOverflow  = errors.New("bit overflow")
	ErrUnderflow = errors.New("bit underflow")
	BigEndian    bigEndian
	LittleEndian littleEndian
)

func NewWriter(dst []uint8) *Writer {
	return &Writer{dst: dst}
}

func (w *Writer) flushCache(bits uint) {
	if w.fill+bits <= 64 {
		return
	}
	if len(w.dst) < 4 {
		w.err = ErrOverflow
		return
	}
	binary.BigEndian.PutUint32(w.dst, uint32(w.cache>>32))
	w.dst = w.dst[4:]
	w.cache <<= 32
	w.fill -= 32
}

func (w *Writer) writeCache(bits uint, val uint32) {
	u := uint64(val)
	u &= ^(^uint64(0) << bits)
	u <<= 64 - w.fill - bits
	w.cache |= u
	w.fill += bits
}

func (bigEndian) PutUint32(w *Writer, bits uint, val uint32) {
	w.flushCache(bits)
	w.writeCache(bits, val)
}

func (littleEndian) PutUint32(w *Writer, bits uint, val uint32) {
	w.flushCache(bits)
	for bits > 8 {
		w.writeCache(8, val)
		val >>= 8
		bits -= 8
	}
	w.writeCache(bits, val)
}

func (bigEndian) PutUint64(w *Writer, bits uint, val uint64) {
	if bits > 32 {
		bits -= 32
		BigEndian.PutUint32(w, 32, uint32(val>>bits))
		val &= 0xFFFFFFFF
	}
	BigEndian.PutUint32(w, bits, uint32(val))
}

func (littleEndian) PutUint64(w *Writer, bits uint, val uint64) {
	if bits > 32 {
		LittleEndian.PutUint32(w, 32, uint32(val&0xFFFFFFFF))
		bits -= 32
		val >>= 32
	}
	LittleEndian.PutUint32(w, bits, uint32(val))
}

func (w *Writer) Flush() error {
	for w.fill >= 8 && len(w.dst) > 0 {
		w.dst[0] = uint8(w.cache >> 56)
		w.dst = w.dst[1:]
		w.cache <<= 8
		w.fill -= 8
	}
	if w.err == nil && w.fill != 0 {
		w.err = ErrOverflow
		if len(w.dst) != 0 {
			w.err = ErrUnderflow
		}
	}
	return w.err
}

func (w *Writer) Write(p []uint8) (int, error) {
	w.Flush()
	n := copy(w.dst, p)
	w.dst = w.dst[n:]
	if n != len(p) {
		w.err = ErrOverflow
	}
	return n, w.err
}
<commit_msg>writer: store current index rather than last error<commit_after>package iobit

import (
	"encoding/binary"
	"errors"
)

type Writer struct {
	dst   []uint8
	cache uint64
	fill  uint
	idx   int
}

type bigEndian struct{}
type littleEndian struct{}

var (
	ErrOverflow  = errors.New("bit overflow")
	ErrUnderflow = errors.New("bit underflow")
	BigEndian    bigEndian
	LittleEndian littleEndian
)

func NewWriter(dst []uint8) *Writer {
	return &Writer{dst: dst}
}

func (w *Writer) flushCache(bits uint) {
	if w.fill+bits <= 64 {
		return
	}
	if w.idx+4 <= len(w.dst) {
		binary.BigEndian.PutUint32(w.dst[w.idx:], uint32(w.cache>>32))
	}
	w.idx += 4
	w.cache <<= 32
	w.fill -= 32
}

func (w *Writer) writeCache(bits uint, val uint32) {
	u := uint64(val)
	u &= ^(^uint64(0) << bits)
	u <<= 64 - w.fill - bits
	w.cache |= u
	w.fill += bits
}

func (bigEndian) PutUint32(w *Writer, bits uint, val uint32) {
	w.flushCache(bits)
	w.writeCache(bits, val)
}

func (littleEndian) PutUint32(w *Writer, bits uint, val uint32) {
	w.flushCache(bits)
	for bits > 8 {
		w.writeCache(8, val)
		val >>= 8
		bits -= 8
	}
	w.writeCache(bits, val)
}

func (bigEndian) PutUint64(w *Writer, bits uint, val uint64) {
	if bits > 32 {
		bits -= 32
		BigEndian.PutUint32(w, 32, uint32(val>>bits))
		val &= 0xFFFFFFFF
	}
	BigEndian.PutUint32(w, bits, uint32(val))
}

func (littleEndian) PutUint64(w *Writer, bits uint, val uint64) {
	if bits > 32 {
		LittleEndian.PutUint32(w, 32, uint32(val&0xFFFFFFFF))
		bits -= 32
		val >>= 32
	}
	LittleEndian.PutUint32(w, bits, uint32(val))
}

func (w *Writer) Flush() error {
	for w.fill >= 8 && w.idx < len(w.dst) {
		w.dst[w.idx] = uint8(w.cache >> 56)
		w.idx += 1
		w.cache <<= 8
		w.fill -= 8
	}
	if w.idx+int(w.fill) > len(w.dst) {
		return ErrOverflow
	}
	if w.fill != 0 {
		return ErrUnderflow
	}
	return nil
}

func (w *Writer) Write(p []uint8) (int, error) {
	err := w.Flush()
	if err != nil {
		return 0, err
	}
	n := 0
	if w.idx < len(w.dst) {
		n = copy(w.dst[w.idx:], p)
	}
	w.idx += len(p)
	if n != len(p) {
		return n, ErrOverflow
	}
	return n, nil
}
<|endoftext|>


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

package yacr

import (
	"bufio"
	"encoding"
	"errors"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"unsafe"
)

// Writer provides an interface for writing CSV data
// (compatible with rfc4180 and extended with the option of having a separator other than ",").
// Successive calls to the Write method will automatically insert the separator.
// The EndOfRecord method tells when a line break is inserted.
type Writer struct {
	b      *bufio.Writer
	sep    byte                 // values separator
	quoted bool                 // specify if values should be quoted (when they contain a separator, a double-quote or a newline)
	sor    bool                 // true at start of record
	err    error                // sticky error.
	bs     []byte               // byte slice used to write string with minimal/no alloc/copy
	hb     *reflect.SliceHeader // header of bs

	UseCRLF bool // True to use \r\n as the line terminator
}

// DefaultWriter creates a "standard" CSV writer (separator is comma and quoted mode active)
func DefaultWriter(wr io.Writer) *Writer {
	return NewWriter(wr, ',', true)
}

// NewWriter returns a new CSV writer.
func NewWriter(w io.Writer, sep byte, quoted bool) *Writer {
	wr := &Writer{b: bufio.NewWriter(w), sep: sep, quoted: quoted, sor: true}
	wr.hb = (*reflect.SliceHeader)(unsafe.Pointer(&wr.bs))
	return wr
}

// WriteRecord ensures that values are quoted when needed.
// It's like fmt.Println.
func (w *Writer) WriteRecord(values ...interface{}) bool {
	for _, v := range values {
		if !w.WriteValue(v) {
			return false
		}
	}
	w.EndOfRecord()
	return w.err == nil
}

// WriteValue ensures that value is quoted when needed.
// Value's type/kind is used to encode value to text.
func (w *Writer) WriteValue(value interface{}) bool {
	switch value := value.(type) {
	case nil:
		return w.Write([]byte{})
	case string:
		return w.WriteString(value)
	case int:
		return w.WriteString(strconv.Itoa(value))
	case int32:
		return w.WriteString(strconv.FormatInt(int64(value), 10))
	case int64:
		return w.WriteString(strconv.FormatInt(value, 10))
	case bool:
		return w.WriteString(strconv.FormatBool(value))
	case float32:
		return w.WriteString(strconv.FormatFloat(float64(value), 'f', -1, 32))
	case float64:
		return w.WriteString(strconv.FormatFloat(value, 'f', -1, 64))
	case []byte:
		return w.Write(value)
	case encoding.TextMarshaler: // time.Time
		if text, err := value.MarshalText(); err != nil {
			w.setErr(err)
			w.Write([]byte{}) // TODO Validate: write an empty field
			return false
		} else {
			return w.Write(text) // please, ignore golint
		}
	default:
		return w.writeReflect(value)
	}
}

// WriteReflect ensures that value is quoted when needed.
// Value's (reflect) Kind is used to encode value to text.
func (w *Writer) writeReflect(value interface{}) bool {
	v := reflect.ValueOf(value)
	switch v.Kind() {
	case reflect.String:
		return w.WriteString(v.String())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return w.WriteString(strconv.FormatInt(v.Int(), 10))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return w.WriteString(strconv.FormatUint(v.Uint(), 10))
	case reflect.Bool:
		return w.WriteString(strconv.FormatBool(v.Bool()))
	case reflect.Float32, reflect.Float64:
		return w.WriteString(strconv.FormatFloat(v.Float(), 'f', -1, v.Type().Bits()))
	default:
		w.setErr(fmt.Errorf("unsupported type: %T, %v", value, value))
		w.Write([]byte{}) // TODO Validate: write an empty field
		return false
	}
}

// WriteString ensures that value is quoted when needed.
func (w *Writer) WriteString(value string) bool {
	// To avoid making a copy...
	hs := (*reflect.StringHeader)(unsafe.Pointer(&value))
	w.hb.Data = hs.Data
	w.hb.Len = hs.Len
	w.hb.Cap = hs.Len
	return w.Write(w.bs)
}

var (
	// ErrNewLine is the error returned when a value contains a newline in unquoted mode.
	ErrNewLine = errors.New("yacr.Writer: newline character in value")
	// ErrSeparator is the error returned when a value contains a separator in unquoted mode.
	ErrSeparator = errors.New("yacr.Writer: separator in value")
)

// Write ensures that value is quoted when needed.
func (w *Writer) Write(value []byte) bool {
	if w.err != nil {
		return false
	}
	if !w.sor {
		w.setErr(w.b.WriteByte(w.sep))
	}
	// In quoted mode, value is enclosed between quotes if it contains sep, quote or \n.
	if w.quoted {
		last := 0
		for i, c := range value {
			switch c {
			case '"', '\r', '\n', w.sep:
			default:
				continue
			}
			if last == 0 {
				w.setErr(w.b.WriteByte('"'))
			}
			if _, err := w.b.Write(value[last : i+1]); err != nil {
				w.setErr(err)
			}
			if c == '"' {
				w.setErr(w.b.WriteByte(c)) // escaped with another double quote
			}
			last = i + 1
		}
		if _, err := w.b.Write(value[last:]); err != nil {
			w.setErr(err)
		}
		if last != 0 {
			w.setErr(w.b.WriteByte('"'))
		}
	} else {
		// check that value does not contain sep or \n
		for _, c := range value {
			switch c {
			case '\n':
				w.setErr(ErrNewLine)
				return false
			case w.sep:
				w.setErr(ErrSeparator)
				return false
			default:
				continue
			}
		}
		if _, err := w.b.Write(value); err != nil {
			w.setErr(err)
		}
	}
	w.sor = false
	return w.err == nil
}

// EndOfRecord tells when a line break must be inserted.
func (w *Writer) EndOfRecord() {
	if w.UseCRLF {
		w.setErr(w.b.WriteByte('\r'))
	}
	w.setErr(w.b.WriteByte('\n'))
	w.sor = true
}

// Flush ensures the writer's buffer is flushed.
func (w *Writer) Flush() {
	w.setErr(w.b.Flush())
}

// Err returns the first error that was encountered by the Writer.
func (w *Writer) Err() error {
	return w.err
}

// setErr records the first error encountered.
func (w *Writer) setErr(err error) {
	if w.err == nil {
		w.err = err
	}
}
<commit_msg>Added a WriteHeader method<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package yacr

import (
	"bufio"
	"encoding"
	"errors"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"unsafe"
)

// Writer provides an interface for writing CSV data
// (compatible with rfc4180 and extended with the option of having a separator other than ",").
// Successive calls to the Write method will automatically insert the separator.
// The EndOfRecord method tells when a line break is inserted.
type Writer struct {
	b      *bufio.Writer
	sep    byte                 // values separator
	quoted bool                 // specify if values should be quoted (when they contain a separator, a double-quote or a newline)
	sor    bool                 // true at start of record
	err    error                // sticky error.
	bs     []byte               // byte slice used to write string with minimal/no alloc/copy
	hb     *reflect.SliceHeader // header of bs

	UseCRLF bool // True to use \r\n as the line terminator
}

// DefaultWriter creates a "standard" CSV writer (separator is comma and quoted mode active)
func DefaultWriter(wr io.Writer) *Writer {
	return NewWriter(wr, ',', true)
}

// NewWriter returns a new CSV writer.
func NewWriter(w io.Writer, sep byte, quoted bool) *Writer {
	wr := &Writer{b: bufio.NewWriter(w), sep: sep, quoted: quoted, sor: true}
	wr.hb = (*reflect.SliceHeader)(unsafe.Pointer(&wr.bs))
	return wr
}

// WriteRecord ensures that values are quoted when needed.
// It's like fmt.Println.
func (w *Writer) WriteRecord(values ...interface{}) bool {
	for _, v := range values {
		if !w.WriteValue(v) {
			return false
		}
	}
	w.EndOfRecord()
	return w.err == nil
}

// WriteValue ensures that value is quoted when needed.
// Value's type/kind is used to encode value to text.
func (w *Writer) WriteValue(value interface{}) bool {
	switch value := value.(type) {
	case nil:
		return w.Write([]byte{})
	case string:
		return w.WriteString(value)
	case int:
		return w.WriteString(strconv.Itoa(value))
	case int32:
		return w.WriteString(strconv.FormatInt(int64(value), 10))
	case int64:
		return w.WriteString(strconv.FormatInt(value, 10))
	case bool:
		return w.WriteString(strconv.FormatBool(value))
	case float32:
		return w.WriteString(strconv.FormatFloat(float64(value), 'f', -1, 32))
	case float64:
		return w.WriteString(strconv.FormatFloat(value, 'f', -1, 64))
	case []byte:
		return w.Write(value)
	case encoding.TextMarshaler: // time.Time
		if text, err := value.MarshalText(); err != nil {
			w.setErr(err)
			w.Write([]byte{}) // TODO Validate: write an empty field
			return false
		} else {
			return w.Write(text) // please, ignore golint
		}
	default:
		return w.writeReflect(value)
	}
}

// WriteReflect ensures that value is quoted when needed.
// Value's (reflect) Kind is used to encode value to text.
func (w *Writer) writeReflect(value interface{}) bool {
	v := reflect.ValueOf(value)
	switch v.Kind() {
	case reflect.String:
		return w.WriteString(v.String())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return w.WriteString(strconv.FormatInt(v.Int(), 10))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return w.WriteString(strconv.FormatUint(v.Uint(), 10))
	case reflect.Bool:
		return w.WriteString(strconv.FormatBool(v.Bool()))
	case reflect.Float32, reflect.Float64:
		return w.WriteString(strconv.FormatFloat(v.Float(), 'f', -1, v.Type().Bits()))
	default:
		w.setErr(fmt.Errorf("unsupported type: %T, %v", value, value))
		w.Write([]byte{}) // TODO Validate: write an empty field
		return false
	}
}

// WriteString ensures that value is quoted when needed.
func (w *Writer) WriteString(value string) bool {
	// To avoid making a copy...
	hs := (*reflect.StringHeader)(unsafe.Pointer(&value))
	w.hb.Data = hs.Data
	w.hb.Len = hs.Len
	w.hb.Cap = hs.Len
	return w.Write(w.bs)
}

// WriteHeader writes a header. Headers are always strings
func (w *Writer) WriteHeader(headers []string) bool {

	for _, s := range headers {
		if !w.WriteString(s) {
			return false
		}
	}
	w.EndOfRecord()
	return w.err == nil
}

var (
	// ErrNewLine is the error returned when a value contains a newline in unquoted mode.
	ErrNewLine = errors.New("yacr.Writer: newline character in value")
	// ErrSeparator is the error returned when a value contains a separator in unquoted mode.
	ErrSeparator = errors.New("yacr.Writer: separator in value")
)

// Write ensures that value is quoted when needed.
func (w *Writer) Write(value []byte) bool {
	if w.err != nil {
		return false
	}
	if !w.sor {
		w.setErr(w.b.WriteByte(w.sep))
	}
	// In quoted mode, value is enclosed between quotes if it contains sep, quote or \n.
	if w.quoted {
		last := 0
		for i, c := range value {
			switch c {
			case '"', '\r', '\n', w.sep:
			default:
				continue
			}
			if last == 0 {
				w.setErr(w.b.WriteByte('"'))
			}
			if _, err := w.b.Write(value[last : i+1]); err != nil {
				w.setErr(err)
			}
			if c == '"' {
				w.setErr(w.b.WriteByte(c)) // escaped with another double quote
			}
			last = i + 1
		}
		if _, err := w.b.Write(value[last:]); err != nil {
			w.setErr(err)
		}
		if last != 0 {
			w.setErr(w.b.WriteByte('"'))
		}
	} else {
		// check that value does not contain sep or \n
		for _, c := range value {
			switch c {
			case '\n':
				w.setErr(ErrNewLine)
				return false
			case w.sep:
				w.setErr(ErrSeparator)
				return false
			default:
				continue
			}
		}
		if _, err := w.b.Write(value); err != nil {
			w.setErr(err)
		}
	}
	w.sor = false
	return w.err == nil
}

// EndOfRecord tells when a line break must be inserted.
func (w *Writer) EndOfRecord() {
	if w.UseCRLF {
		w.setErr(w.b.WriteByte('\r'))
	}
	w.setErr(w.b.WriteByte('\n'))
	w.sor = true
}

// Flush ensures the writer's buffer is flushed.
func (w *Writer) Flush() {
	w.setErr(w.b.Flush())
}

// Err returns the first error that was encountered by the Writer.
func (w *Writer) Err() error {
	return w.err
}

// setErr records the first error encountered.
func (w *Writer) setErr(err error) {
	if w.err == nil {
		w.err = err
	}
}
<|endoftext|>


<commit_before>// Copyright 2016, RadiantBlue Technologies, 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 pzse

import (
	"encoding/json"
	//"fmt"
	//"io"
	//"io/ioutil"
	//"mime"
	"net/http"
	"os"
	"strconv"
	"testing"

	"github.com/venicegeo/pzsvc-lib"
)

func TestParseConfiguration(t *testing.T) {
	configs, planOuts, authEnv := getTestConfigList()
	holdEnv := os.Getenv(authEnv)
	os.Setenv(authEnv, "pzsvc-exec")
	for i, config := range configs {
		planOut := planOuts[i]
		runOut := ParseConfig(&config)
		if planOut.AuthKey != runOut.AuthKey {
			t.Error(`TestParseConfiguration: AuthKey mismatch on run #` + strconv.Itoa(i) +
				`.  actual: ` + runOut.AuthKey + `.  expected: ` + planOut.AuthKey + `.`)
		}
		if planOut.PortStr != runOut.PortStr {
			t.Error(`TestParseConfiguration: PortStr mismatch on run #` + strconv.Itoa(i) +
				`.  actual: ` + runOut.PortStr + `.  expected: ` + planOut.PortStr + `.`)
		}
		if planOut.Version != runOut.Version {
			t.Error(`TestParseConfiguration: Version mismatch on run #` + strconv.Itoa(i) +
				`.  actual: ` + runOut.Version + `.  expected: ` + planOut.Version + `.`)
		}
		if planOut.CanFile != runOut.CanFile {
			t.Error(`TestParseConfiguration: CanFile mismatch on run #` + strconv.Itoa(i) +
				`.  actual: ` + strconv.FormatBool(runOut.CanFile) +
				`.  expected: ` + strconv.FormatBool(planOut.CanFile) + `.`)
		}
	}
	os.Setenv(authEnv, holdEnv)
}

func TestExecute(t *testing.T) {
	config := getTestConfigWorkable()
	parsConfig := ParseConfig(&config)
	testResList := []string{"", `{"data":{"jobId":"testID"}}`, `{"data":{"status":"Success", "Result":{"message":"testStatus", "dataId":"testId"}}}`}
	pzsvc.SetMockClient(testResList, 200)

	w, _, _ := pzsvc.GetMockResponseWriter()
	r := http.Request{}
	r.Method = "POST"
	inpObj := InpStruct{Command: "-l",
		InExtFiles: []string{"https://avatars0.githubusercontent.com/u/15457149?v=3&s=200"},
		InExtNames: []string{"icon.png"},
		OutTiffs:   []string{"icon.png"},
		PzAuth:     "aaa"}

	byts, err := json.Marshal(inpObj)
	if err != nil {
		t.Error(`TestExecute: failed to marshal static object.  errStr: ` + err.Error())
	}

	r.Body = pzsvc.GetMockReadCloser(string(byts))
	/*
		r.Form = map[string][]string{}
		r.Form.Add("cmd", "-l")
		r.Form.Add("inFileURLs", "https://avatars0.githubusercontent.com/u/15457149?v=3&s=200")
		r.Form.Add("inExtFileNames", "icon.png")
		r.Form.Add("outTiffs", "icon.png")
		r.Form.Add("authKey", "aaaa")
	*/
	outObj := Execute(w, &r, config, parsConfig.AuthKey, parsConfig.Version, parsConfig.CanFile, parsConfig.ProcPool)

	if outObj.Errors != nil {
		for _, errStr := range outObj.Errors {
			t.Error(`TestExecute: Generated Error: ` + errStr)
		}
	}
}
<commit_msg>a touch of comment clean-up<commit_after>// Copyright 2016, RadiantBlue Technologies, 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 pzse

import (
	"encoding/json"
	//"fmt"
	//"io"
	//"io/ioutil"
	//"mime"
	"net/http"
	"os"
	"strconv"
	"testing"

	"github.com/venicegeo/pzsvc-lib"
)

func TestParseConfiguration(t *testing.T) {
	configs, planOuts, authEnv := getTestConfigList()
	holdEnv := os.Getenv(authEnv)
	os.Setenv(authEnv, "pzsvc-exec")
	for i, config := range configs {
		planOut := planOuts[i]
		runOut := ParseConfig(&config)
		if planOut.AuthKey != runOut.AuthKey {
			t.Error(`TestParseConfiguration: AuthKey mismatch on run #` + strconv.Itoa(i) +
				`.  actual: ` + runOut.AuthKey + `.  expected: ` + planOut.AuthKey + `.`)
		}
		if planOut.PortStr != runOut.PortStr {
			t.Error(`TestParseConfiguration: PortStr mismatch on run #` + strconv.Itoa(i) +
				`.  actual: ` + runOut.PortStr + `.  expected: ` + planOut.PortStr + `.`)
		}
		if planOut.Version != runOut.Version {
			t.Error(`TestParseConfiguration: Version mismatch on run #` + strconv.Itoa(i) +
				`.  actual: ` + runOut.Version + `.  expected: ` + planOut.Version + `.`)
		}
		if planOut.CanFile != runOut.CanFile {
			t.Error(`TestParseConfiguration: CanFile mismatch on run #` + strconv.Itoa(i) +
				`.  actual: ` + strconv.FormatBool(runOut.CanFile) +
				`.  expected: ` + strconv.FormatBool(planOut.CanFile) + `.`)
		}
	}
	os.Setenv(authEnv, holdEnv)
}

func TestExecute(t *testing.T) {
	config := getTestConfigWorkable()
	parsConfig := ParseConfig(&config)
	testResList := []string{"", `{"data":{"jobId":"testID"}}`, `{"data":{"status":"Success", "Result":{"message":"testStatus", "dataId":"testId"}}}`}
	pzsvc.SetMockClient(testResList, 200)

	w, _, _ := pzsvc.GetMockResponseWriter()
	r := http.Request{}
	r.Method = "POST"
	inpObj := InpStruct{Command: "-l",
		InExtFiles: []string{"https://avatars0.githubusercontent.com/u/15457149?v=3&s=200"},
		InExtNames: []string{"icon.png"},
		OutTiffs:   []string{"icon.png"},
		PzAuth:     "aaa"}

	byts, err := json.Marshal(inpObj)
	if err != nil {
		t.Error(`TestExecute: failed to marshal static object.  errStr: ` + err.Error())
	}

	r.Body = pzsvc.GetMockReadCloser(string(byts))
	outObj := Execute(w, &r, config, parsConfig.AuthKey, parsConfig.Version, parsConfig.CanFile, parsConfig.ProcPool)

	if outObj.Errors != nil {
		for _, errStr := range outObj.Errors {
			t.Error(`TestExecute: Generated Error: ` + errStr)
		}
	}
}
<|endoftext|>


<commit_before>package shp

import (
	"encoding/binary"
	"io"
	"log"
	"math"
	"os"
	"reflect"
	"strconv"
)

// Writer is the type that is used to write a new shapefile.
type Writer struct {
	filename     string
	shp          *os.File
	shx          *os.File
	GeometryType ShapeType
	num          int32
	bbox         Box

	dbf             *os.File
	dbfFields       []Field
	dbfHeaderLength int16
	dbfRecordLength int16
}

// Create returns a point to new Writer and the first error that was
// encountered. In case an error occurred the returned Writer point will be nil
// This also creates a corresponding SHX file. It is important to use Close()
// when done because that method writes all the headers for each file (SHP, SHX
// and DBF).
func Create(filename string, t ShapeType) (*Writer, error) {
	filename = filename[0 : len(filename)-3]
	shp, err := os.Create(filename + "shp")
	if err != nil {
		return nil, err
	}
	shx, err := os.Create(filename + "shx")
	if err != nil {
		return nil, err
	}
	shp.Seek(100, os.SEEK_SET)
	shx.Seek(100, os.SEEK_SET)
	w := &Writer{
		filename:     filename,
		shp:          shp,
		shx:          shx,
		GeometryType: t,
	}
	return w, nil
}

// Write shape to the Shapefile. This also creates
// a record in the SHX file and DBF file (if it is
// initialized). Returns the index of the written object
// which can be used in WriteAttribute.
func (w *Writer) Write(shape Shape) int32 {
	// increate bbox
	if w.num == 0 {
		w.bbox = shape.BBox()
	} else {
		w.bbox.Extend(shape.BBox())
	}

	w.num++
	binary.Write(w.shp, binary.BigEndian, w.num)
	w.shp.Seek(4, os.SEEK_CUR)
	start, _ := w.shp.Seek(0, os.SEEK_CUR)
	binary.Write(w.shp, binary.LittleEndian, w.GeometryType)
	shape.write(w.shp)
	finish, _ := w.shp.Seek(0, os.SEEK_CUR)
	length := int32(math.Floor((float64(finish) - float64(start)) / 2.0))
	w.shp.Seek(start-4, os.SEEK_SET)
	binary.Write(w.shp, binary.BigEndian, length)
	w.shp.Seek(finish, os.SEEK_SET)

	// write shx
	binary.Write(w.shx, binary.BigEndian, int32((start-8)/2))
	binary.Write(w.shx, binary.BigEndian, length)

	// write empty record to dbf
	if w.dbf != nil {
		w.writeEmptyRecord()
	}

	return w.num - 1
}

// Close closes the Writer. This must be used at the end of
// the transaction because it writes the correct headers
// to the SHP/SHX and DBF files before closing.
func (w *Writer) Close() {
	w.writeHeader(w.shx)
	w.writeHeader(w.shp)
	w.shp.Close()
	w.shx.Close()

	if w.dbf == nil {
		w.SetFields([]Field{})
	}
	w.writeDbfHeader(w.dbf)
	w.dbf.Close()
}

// Writes SHP/SHX headers to specified file.
func (w *Writer) writeHeader(ws io.WriteSeeker) {
	filelength, _ := ws.Seek(0, os.SEEK_END)
	if filelength == 0 {
		filelength = 100
	}
	ws.Seek(0, os.SEEK_SET)
	// file code
	binary.Write(ws, binary.BigEndian, []int32{9994, 0, 0, 0, 0, 0})
	// file length
	binary.Write(ws, binary.BigEndian, int32(filelength/2))
	// version and shape type
	binary.Write(ws, binary.LittleEndian, []int32{1000, int32(w.GeometryType)})
	// bounding box
	binary.Write(ws, binary.LittleEndian, w.bbox)
	// elevation, measure
	binary.Write(ws, binary.LittleEndian, []float64{0.0, 0.0, 0.0, 0.0})
}

// Write DBF header.
func (w *Writer) writeDbfHeader(file *os.File) {
	file.Seek(0, 0)
	// version, year (YEAR-1990), month, day
	binary.Write(file, binary.LittleEndian, []byte{3, 24, 5, 3})
	// number of records
	binary.Write(file, binary.LittleEndian, w.num)
	// header length, record length
	binary.Write(file, binary.LittleEndian, []int16{w.dbfHeaderLength, w.dbfRecordLength})
	// padding
	binary.Write(file, binary.LittleEndian, make([]byte, 20))

	for _, field := range w.dbfFields {
		binary.Write(file, binary.LittleEndian, field)
	}

	// end with return
	file.WriteString("\r")
}

// SetFields sets field values in the DBF. This initializes the DBF file and
// should be used prior to writing any attributes.
func (w *Writer) SetFields(fields []Field) {
	if w.dbf != nil {
		log.Fatal("Cannot set fields in existing dbf")
	}

	var err error
	w.dbf, err = os.Create(w.filename + "dbf")
	if err != nil {
		log.Fatal("Failed to open " + w.filename + ".dbf")
	}
	w.dbfFields = fields

	// calculate record length
	w.dbfRecordLength = int16(1)
	for _, field := range w.dbfFields {
		w.dbfRecordLength += int16(field.Size)
	}

	// header lengh
	w.dbfHeaderLength = int16(len(w.dbfFields)*32 + 33)

	// fill header space with empty bytes for now
	buf := make([]byte, w.dbfHeaderLength)
	binary.Write(w.dbf, binary.LittleEndian, buf)

	// write empty records
	for n := int32(0); n < w.num; n++ {
		w.writeEmptyRecord()
	}
}

// Writes an empty record to the end of the DBF. This
// works by seeking to the end of the file and writing
// dbfRecordLength number of bytes. The first byte is a
// space that indicates a new record.
func (w *Writer) writeEmptyRecord() {
	w.dbf.Seek(0, os.SEEK_END)
	buf := make([]byte, w.dbfRecordLength)
	buf[0] = ' '
	binary.Write(w.dbf, binary.LittleEndian, buf)
}

// WriteAttribute writes value for field into the given row in the DBF. Row
// number should be the same as the order the Shape was written to the
// Shapefile. The field value corresponds the the field in the splice used in
// SetFields.
func (w *Writer) WriteAttribute(row int, field int, value interface{}) {
	var buf []byte
	switch reflect.TypeOf(value).Kind() {
	case reflect.Int:
		buf = []byte(strconv.Itoa(value.(int)))
	case reflect.Float64:
		precision := w.dbfFields[field].Precision
		buf = []byte(strconv.FormatFloat(value.(float64), 'f', int(precision), 64))
	case reflect.String:
		buf = []byte(value.(string))
	default:
		log.Fatal("Unsupported value type:", reflect.TypeOf(value))
	}

	if w.dbf == nil {
		log.Fatal("Initialize DBF by using SetFields first")
	}

	seekTo := 1 + int64(w.dbfHeaderLength) + (int64(row) * int64(w.dbfRecordLength))
	for n := 0; n < field; n++ {
		seekTo += int64(w.dbfFields[n].Size)
	}
	w.dbf.Seek(seekTo, os.SEEK_SET)
	binary.Write(w.dbf, binary.LittleEndian, buf)
}

// BBox returns the bounding box of the Writer.
func (w *Writer) BBox() Box {
	return w.bbox
}
<commit_msg>Make writeDbfHeader use io.WriteSeeker as suggested by interfacer<commit_after>package shp

import (
	"encoding/binary"
	"io"
	"log"
	"math"
	"os"
	"reflect"
	"strconv"
)

// Writer is the type that is used to write a new shapefile.
type Writer struct {
	filename     string
	shp          *os.File
	shx          *os.File
	GeometryType ShapeType
	num          int32
	bbox         Box

	dbf             *os.File
	dbfFields       []Field
	dbfHeaderLength int16
	dbfRecordLength int16
}

// Create returns a point to new Writer and the first error that was
// encountered. In case an error occurred the returned Writer point will be nil
// This also creates a corresponding SHX file. It is important to use Close()
// when done because that method writes all the headers for each file (SHP, SHX
// and DBF).
func Create(filename string, t ShapeType) (*Writer, error) {
	filename = filename[0 : len(filename)-3]
	shp, err := os.Create(filename + "shp")
	if err != nil {
		return nil, err
	}
	shx, err := os.Create(filename + "shx")
	if err != nil {
		return nil, err
	}
	shp.Seek(100, os.SEEK_SET)
	shx.Seek(100, os.SEEK_SET)
	w := &Writer{
		filename:     filename,
		shp:          shp,
		shx:          shx,
		GeometryType: t,
	}
	return w, nil
}

// Write shape to the Shapefile. This also creates
// a record in the SHX file and DBF file (if it is
// initialized). Returns the index of the written object
// which can be used in WriteAttribute.
func (w *Writer) Write(shape Shape) int32 {
	// increate bbox
	if w.num == 0 {
		w.bbox = shape.BBox()
	} else {
		w.bbox.Extend(shape.BBox())
	}

	w.num++
	binary.Write(w.shp, binary.BigEndian, w.num)
	w.shp.Seek(4, os.SEEK_CUR)
	start, _ := w.shp.Seek(0, os.SEEK_CUR)
	binary.Write(w.shp, binary.LittleEndian, w.GeometryType)
	shape.write(w.shp)
	finish, _ := w.shp.Seek(0, os.SEEK_CUR)
	length := int32(math.Floor((float64(finish) - float64(start)) / 2.0))
	w.shp.Seek(start-4, os.SEEK_SET)
	binary.Write(w.shp, binary.BigEndian, length)
	w.shp.Seek(finish, os.SEEK_SET)

	// write shx
	binary.Write(w.shx, binary.BigEndian, int32((start-8)/2))
	binary.Write(w.shx, binary.BigEndian, length)

	// write empty record to dbf
	if w.dbf != nil {
		w.writeEmptyRecord()
	}

	return w.num - 1
}

// Close closes the Writer. This must be used at the end of
// the transaction because it writes the correct headers
// to the SHP/SHX and DBF files before closing.
func (w *Writer) Close() {
	w.writeHeader(w.shx)
	w.writeHeader(w.shp)
	w.shp.Close()
	w.shx.Close()

	if w.dbf == nil {
		w.SetFields([]Field{})
	}
	w.writeDbfHeader(w.dbf)
	w.dbf.Close()
}

// writeHeader wrires SHP/SHX headers to ws.
func (w *Writer) writeHeader(ws io.WriteSeeker) {
	filelength, _ := ws.Seek(0, os.SEEK_END)
	if filelength == 0 {
		filelength = 100
	}
	ws.Seek(0, os.SEEK_SET)
	// file code
	binary.Write(ws, binary.BigEndian, []int32{9994, 0, 0, 0, 0, 0})
	// file length
	binary.Write(ws, binary.BigEndian, int32(filelength/2))
	// version and shape type
	binary.Write(ws, binary.LittleEndian, []int32{1000, int32(w.GeometryType)})
	// bounding box
	binary.Write(ws, binary.LittleEndian, w.bbox)
	// elevation, measure
	binary.Write(ws, binary.LittleEndian, []float64{0.0, 0.0, 0.0, 0.0})
}

// writeDbfHeader writes a DBF header to ws.
func (w *Writer) writeDbfHeader(ws io.WriteSeeker) {
	ws.Seek(0, 0)
	// version, year (YEAR-1990), month, day
	binary.Write(ws, binary.LittleEndian, []byte{3, 24, 5, 3})
	// number of records
	binary.Write(ws, binary.LittleEndian, w.num)
	// header length, record length
	binary.Write(ws, binary.LittleEndian, []int16{w.dbfHeaderLength, w.dbfRecordLength})
	// padding
	binary.Write(ws, binary.LittleEndian, make([]byte, 20))

	for _, field := range w.dbfFields {
		binary.Write(ws, binary.LittleEndian, field)
	}

	// end with return
	ws.Write([]byte("\r"))
}

// SetFields sets field values in the DBF. This initializes the DBF file and
// should be used prior to writing any attributes.
func (w *Writer) SetFields(fields []Field) {
	if w.dbf != nil {
		log.Fatal("Cannot set fields in existing dbf")
	}

	var err error
	w.dbf, err = os.Create(w.filename + "dbf")
	if err != nil {
		log.Fatal("Failed to open " + w.filename + ".dbf")
	}
	w.dbfFields = fields

	// calculate record length
	w.dbfRecordLength = int16(1)
	for _, field := range w.dbfFields {
		w.dbfRecordLength += int16(field.Size)
	}

	// header lengh
	w.dbfHeaderLength = int16(len(w.dbfFields)*32 + 33)

	// fill header space with empty bytes for now
	buf := make([]byte, w.dbfHeaderLength)
	binary.Write(w.dbf, binary.LittleEndian, buf)

	// write empty records
	for n := int32(0); n < w.num; n++ {
		w.writeEmptyRecord()
	}
}

// Writes an empty record to the end of the DBF. This
// works by seeking to the end of the file and writing
// dbfRecordLength number of bytes. The first byte is a
// space that indicates a new record.
func (w *Writer) writeEmptyRecord() {
	w.dbf.Seek(0, os.SEEK_END)
	buf := make([]byte, w.dbfRecordLength)
	buf[0] = ' '
	binary.Write(w.dbf, binary.LittleEndian, buf)
}

// WriteAttribute writes value for field into the given row in the DBF. Row
// number should be the same as the order the Shape was written to the
// Shapefile. The field value corresponds the the field in the splice used in
// SetFields.
func (w *Writer) WriteAttribute(row int, field int, value interface{}) {
	var buf []byte
	switch reflect.TypeOf(value).Kind() {
	case reflect.Int:
		buf = []byte(strconv.Itoa(value.(int)))
	case reflect.Float64:
		precision := w.dbfFields[field].Precision
		buf = []byte(strconv.FormatFloat(value.(float64), 'f', int(precision), 64))
	case reflect.String:
		buf = []byte(value.(string))
	default:
		log.Fatal("Unsupported value type:", reflect.TypeOf(value))
	}

	if w.dbf == nil {
		log.Fatal("Initialize DBF by using SetFields first")
	}

	seekTo := 1 + int64(w.dbfHeaderLength) + (int64(row) * int64(w.dbfRecordLength))
	for n := 0; n < field; n++ {
		seekTo += int64(w.dbfFields[n].Size)
	}
	w.dbf.Seek(seekTo, os.SEEK_SET)
	binary.Write(w.dbf, binary.LittleEndian, buf)
}

// BBox returns the bounding box of the Writer.
func (w *Writer) BBox() Box {
	return w.bbox
}
<|endoftext|>