<commit_before>package pd1

import (
	"encoding/binary"
	"fmt"
	"sort"
	"time"

	"github.com/influxdb/influxdb/tsdb"
)

const (
	// EncodingPacked is a bit-packed format
	EncodingPacked = 0
	// EncodingRLE is a run-length encoded format
	EncodingRLE = 1
	// EncodingUncompressed is a non-compressed format
	EncodingUncompressed = 2
)

type Value interface {
	Time() time.Time
	UnixNano() int64
	Value() interface{}
	Size() int
}

func NewValue(t time.Time, value interface{}) Value {
	switch v := value.(type) {
	case int64:
		return &Int64Value{time: t, value: v}
	case float64:
		return &FloatValue{time: t, value: v}
		// case bool:
		// 	return &BoolValue{time: t, value: v}
		// case string:
		// 	return &StringValue{time: t, value: v}
	}
	return &EmptyValue{}
}

type EmptyValue struct {
}

func (e *EmptyValue) UnixNano() int64    { return tsdb.EOF }
func (e *EmptyValue) Time() time.Time    { return time.Unix(0, tsdb.EOF) }
func (e *EmptyValue) Value() interface{} { return nil }
func (e *EmptyValue) Size() int          { return 0 }

// Values represented a time ascending sorted collection of Value types.
// the underlying type should be the same across all values, but the interface
// makes the code cleaner.
type Values []Value

func (v Values) MinTime() int64 {
	return v[0].Time().UnixNano()
}

func (v Values) MaxTime() int64 {
	return v[len(v)-1].Time().UnixNano()
}

func (v Values) Encode(buf []byte) []byte {
	switch v[0].(type) {
	case *FloatValue:
		a := make([]*FloatValue, len(v))
		for i, vv := range v {
			a[i] = vv.(*FloatValue)
		}
		return EncodeFloatBlock(buf, a)

	case *Int64Value:
		a := make([]*Int64Value, len(v))
		for i, vv := range v {
			a[i] = vv.(*Int64Value)
		}
		return EncodeInt64Block(buf, a)

		// TODO: add support for other types
	}

	return nil
}

func (v Values) DecodeSameTypeBlock(block []byte) Values {
	switch v[0].(type) {
	case *FloatValue:
		a, _ := DecodeFloatBlock(block)
		return a
	case *Int64Value:
		a, _ := DecodeInt64Block(block)
		return a

		// TODO: add support for other types
	}
	return nil
}

// DecodeBlock takes a byte array and will decode into values of the appropriate type
// based on the block
func DecodeBlock(block []byte) (Values, error) {
	// TODO: add support for other block types
	return DecodeFloatBlock(block)
}

// Deduplicate returns a new Values slice with any values
// that have the same  timestamp removed. The Value that appears
// last in the slice is the one that is kept. The returned slice is in ascending order
func (v Values) Deduplicate() Values {
	m := make(map[int64]Value)
	for _, val := range v {
		m[val.UnixNano()] = val
	}

	a := make([]Value, 0, len(m))
	for _, val := range m {
		a = append(a, val)
	}
	sort.Sort(Values(a))

	return a
}

// Sort methods
func (a Values) Len() int           { return len(a) }
func (a Values) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a Values) Less(i, j int) bool { return a[i].Time().UnixNano() < a[j].Time().UnixNano() }

type FloatValue struct {
	time  time.Time
	value float64
}

func (f *FloatValue) Time() time.Time {
	return f.time
}

func (f *FloatValue) UnixNano() int64 {
	return f.time.UnixNano()
}

func (f *FloatValue) Value() interface{} {
	return f.value
}

func (f *FloatValue) Size() int {
	return 16
}

func EncodeFloatBlock(buf []byte, values []*FloatValue) []byte {
	if len(values) == 0 {
		return []byte{}
	}

	// A float block is encoded using different compression strategies
	// for timestamps and values.

	// Encode values using Gorilla float compression
	venc := NewFloatEncoder()

	// Encode timestamps using an adaptive encoder that uses delta-encoding,
	// frame-or-reference and run length encoding.
	tsenc := NewTimeEncoder()

	for _, v := range values {
		tsenc.Write(v.Time())
		venc.Push(v.value)
	}
	venc.Finish()

	// Encoded timestamp values
	tb, err := tsenc.Bytes()
	if err != nil {
		panic(err.Error())
	}
	// Encoded float values
	vb := venc.Bytes()

	// Preprend the first timestamp of the block in the first 8 bytes
	return append(u64tob(uint64(values[0].Time().UnixNano())),
		packBlock(tb, vb)...)
}

func DecodeFloatBlock(block []byte) ([]Value, error) {
	// The first 8 bytes is the minimum timestamp of the block
	tb, vb := unpackBlock(block[8:])

	// Setup our timestamp and value decoders
	dec := NewTimeDecoder(tb)
	iter, err := NewFloatDecoder(vb)
	if err != nil {
		return nil, err
	}

	// Decode both a timestamp and value
	var a []Value
	for dec.Next() && iter.Next() {
		ts := dec.Read()
		v := iter.Values()
		a = append(a, &FloatValue{ts, v})
	}

	return a, nil
}

type BoolValue struct {
	time  time.Time
	value bool
}

func EncodeBoolBlock(buf []byte, values []BoolValue) []byte {
	return nil
}

func DecodeBoolBlock(block []byte) ([]BoolValue, error) {
	return nil, nil
}

type Int64Value struct {
	time  time.Time
	value int64
}

func (v *Int64Value) Time() time.Time {
	return v.time
}

func (v *Int64Value) Value() interface{} {
	return v.value
}

func (f *Int64Value) UnixNano() int64 {
	return f.time.UnixNano()
}

func (v *Int64Value) Size() int {
	return 16
}

func (v *Int64Value) String() string { return fmt.Sprintf("%v", v.value) }

func EncodeInt64Block(buf []byte, values []*Int64Value) []byte {
	tsEnc := NewTimeEncoder()
	vEnc := NewInt64Encoder()
	for _, v := range values {
		tsEnc.Write(v.Time())
		vEnc.Write(v.value)
	}

	// Encoded timestamp values
	tb, err := tsEnc.Bytes()
	if err != nil {
		panic(err.Error())
	}
	// Encoded int64 values
	vb, err := vEnc.Bytes()
	if err != nil {
		panic(err.Error())
	}

	// Preprend the first timestamp of the block in the first 8 bytes
	return append(u64tob(uint64(values[0].Time().UnixNano())),
		packBlock(tb, vb)...)
}

func DecodeInt64Block(block []byte) ([]Value, error) {
	// The first 8 bytes is the minimum timestamp of the block
	tb, vb := unpackBlock(block[8:])

	// Setup our timestamp and value decoders
	tsDec := NewTimeDecoder(tb)
	vDec := NewInt64Decoder(vb)

	// Decode both a timestamp and value
	var a []Value
	for tsDec.Next() && vDec.Next() {
		ts := tsDec.Read()
		v := vDec.Read()
		a = append(a, &Int64Value{ts, v})
	}

	return a, nil
}

type StringValue struct {
	time  time.Time
	value string
}

func EncodeStringBlock(buf []byte, values []StringValue) []byte {
	return nil
}

func packBlock(ts []byte, values []byte) []byte {
	// We encode the length of the timestamp block using a variable byte encoding.
	// This allows small byte slices to take up 1 byte while larger ones use 2 or more.
	b := make([]byte, 10)
	i := binary.PutUvarint(b, uint64(len(ts)))

	// block is <len timestamp bytes>, <ts bytes>, <value bytes>
	block := append(b[:i], ts...)

	// We don't encode the value length because we know it's the rest of the block after
	// the timestamp block.
	return append(block, values...)
}

func unpackBlock(buf []byte) (ts, values []byte) {
	// Unpack the timestamp block length
	tsLen, i := binary.Uvarint(buf)

	// Unpack the timestamp bytes
	ts = buf[int(i) : int(i)+int(tsLen)]

	// Unpack the value bytes
	values = buf[int(i)+int(tsLen):]
	return
}

// ZigZagEncode converts a int64 to a uint64 by zig zagging negative and positive values
// across even and odd numbers.  Eg. [0,-1,1,-2] becomes [0, 1, 2, 3]
func ZigZagEncode(x int64) uint64 {
	return uint64(uint64(x<<1) ^ uint64((int64(x) >> 63)))
}

// ZigZagDecode converts a previously zigzag encoded uint64 back to a int64
func ZigZagDecode(v uint64) int64 {
	return int64((v >> 1) ^ uint64((int64(v&1)<<63)>>63))
}
<commit_msg>Keep track of the type of the block encoded<commit_after>package pd1

import (
	"encoding/binary"
	"fmt"
	"sort"
	"time"

	"github.com/influxdb/influxdb/tsdb"
)

const (
	// EncodingPacked is a bit-packed format
	EncodingPacked = 0
	// EncodingRLE is a run-length encoded format
	EncodingRLE = 1
	// EncodingUncompressed is a non-compressed format
	EncodingUncompressed = 2

	// BlockFloat64 designates a block encodes float64 values
	BlockFloat64 = 0

	// BlockInt64 designates a block encodes int64 values
	BlockInt64 = 1

	// BlockBool designates a block encodes bool values
	BlockBool = 2

	// BlockString designates a block encodes string values
	BlockString = 3
)

type Value interface {
	Time() time.Time
	UnixNano() int64
	Value() interface{}
	Size() int
}

func NewValue(t time.Time, value interface{}) Value {
	switch v := value.(type) {
	case int64:
		return &Int64Value{time: t, value: v}
	case float64:
		return &FloatValue{time: t, value: v}
		// case bool:
		// 	return &BoolValue{time: t, value: v}
		// case string:
		// 	return &StringValue{time: t, value: v}
	}
	return &EmptyValue{}
}

type EmptyValue struct {
}

func (e *EmptyValue) UnixNano() int64    { return tsdb.EOF }
func (e *EmptyValue) Time() time.Time    { return time.Unix(0, tsdb.EOF) }
func (e *EmptyValue) Value() interface{} { return nil }
func (e *EmptyValue) Size() int          { return 0 }

// Values represented a time ascending sorted collection of Value types.
// the underlying type should be the same across all values, but the interface
// makes the code cleaner.
type Values []Value

func (v Values) MinTime() int64 {
	return v[0].Time().UnixNano()
}

func (v Values) MaxTime() int64 {
	return v[len(v)-1].Time().UnixNano()
}

func (v Values) Encode(buf []byte) []byte {
	switch v[0].(type) {
	case *FloatValue:
		a := make([]*FloatValue, len(v))
		for i, vv := range v {
			a[i] = vv.(*FloatValue)
		}
		return encodeFloatBlock(buf, a)

	case *Int64Value:
		a := make([]*Int64Value, len(v))
		for i, vv := range v {
			a[i] = vv.(*Int64Value)
		}
		return encodeInt64Block(buf, a)

		// TODO: add support for other types
	}

	return nil
}

func (v Values) DecodeSameTypeBlock(block []byte) Values {
	switch v[0].(type) {
	case *FloatValue:
		a, _ := decodeFloatBlock(block)
		return a
	case *Int64Value:
		a, _ := decodeInt64Block(block)
		return a

		// TODO: add support for other types
	}
	return nil
}

// DecodeBlock takes a byte array and will decode into values of the appropriate type
// based on the block
func DecodeBlock(block []byte) (Values, error) {
	if len(block) == 0 {
		return Values{}, nil
	}

	blockType := block[8]
	switch blockType {
	case BlockFloat64:
		return decodeFloatBlock(block)
	case BlockInt64:
		return decodeInt64Block(block)
	case BlockBool:
		// return decodeBoolBlock(block)
	case BlockString:
		// return decodeStringBlock(block)
	default:
	}

	// TODO: add support for other block types
	return nil, fmt.Errorf("unknown block type: %d", blockType)
}

// Deduplicate returns a new Values slice with any values
// that have the same  timestamp removed. The Value that appears
// last in the slice is the one that is kept. The returned slice is in ascending order
func (v Values) Deduplicate() Values {
	m := make(map[int64]Value)
	for _, val := range v {
		m[val.UnixNano()] = val
	}

	a := make([]Value, 0, len(m))
	for _, val := range m {
		a = append(a, val)
	}
	sort.Sort(Values(a))

	return a
}

// Sort methods
func (a Values) Len() int           { return len(a) }
func (a Values) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a Values) Less(i, j int) bool { return a[i].Time().UnixNano() < a[j].Time().UnixNano() }

type FloatValue struct {
	time  time.Time
	value float64
}

func (f *FloatValue) Time() time.Time {
	return f.time
}

func (f *FloatValue) UnixNano() int64 {
	return f.time.UnixNano()
}

func (f *FloatValue) Value() interface{} {
	return f.value
}

func (f *FloatValue) Size() int {
	return 16
}

func encodeFloatBlock(buf []byte, values []*FloatValue) []byte {
	if len(values) == 0 {
		return nil
	}

	// A float block is encoded using different compression strategies
	// for timestamps and values.

	// Encode values using Gorilla float compression
	venc := NewFloatEncoder()

	// Encode timestamps using an adaptive encoder that uses delta-encoding,
	// frame-or-reference and run length encoding.
	tsenc := NewTimeEncoder()

	for _, v := range values {
		tsenc.Write(v.Time())
		venc.Push(v.value)
	}
	venc.Finish()

	// Encoded timestamp values
	tb, err := tsenc.Bytes()
	if err != nil {
		panic(err.Error())
	}
	// Encoded float values
	vb := venc.Bytes()

	// Preprend the first timestamp of the block in the first 8 bytes and the block
	// in the next byte, followed by the block
	block := packBlockHeader(values[0].Time(), BlockFloat64)
	block = append(block, packBlock(tb, vb)...)
	return block
}

func decodeFloatBlock(block []byte) ([]Value, error) {
	// The first 8 bytes is the minimum timestamp of the block
	block = block[8:]

	// Block type is the next block, make sure we actually have a float block
	blockType := block[0]
	if blockType != BlockFloat64 {
		return nil, fmt.Errorf("invalid block type: exp %d, got %d", BlockFloat64, blockType)
	}
	block = block[1:]

	tb, vb := unpackBlock(block)

	// Setup our timestamp and value decoders
	dec := NewTimeDecoder(tb)
	iter, err := NewFloatDecoder(vb)
	if err != nil {
		return nil, err
	}

	// Decode both a timestamp and value
	var a []Value
	for dec.Next() && iter.Next() {
		ts := dec.Read()
		v := iter.Values()
		a = append(a, &FloatValue{ts, v})
	}

	return a, nil
}

type BoolValue struct {
	time  time.Time
	value bool
}

func encodeBoolBlock(buf []byte, values []BoolValue) []byte {
	return nil
}

func eecodeBoolBlock(block []byte) ([]BoolValue, error) {
	return nil, nil
}

type Int64Value struct {
	time  time.Time
	value int64
}

func (v *Int64Value) Time() time.Time {
	return v.time
}

func (v *Int64Value) Value() interface{} {
	return v.value
}

func (f *Int64Value) UnixNano() int64 {
	return f.time.UnixNano()
}

func (v *Int64Value) Size() int {
	return 16
}

func (v *Int64Value) String() string { return fmt.Sprintf("%v", v.value) }

func encodeInt64Block(buf []byte, values []*Int64Value) []byte {
	tsEnc := NewTimeEncoder()
	vEnc := NewInt64Encoder()
	for _, v := range values {
		tsEnc.Write(v.Time())
		vEnc.Write(v.value)
	}

	// Encoded timestamp values
	tb, err := tsEnc.Bytes()
	if err != nil {
		panic(err.Error())
	}
	// Encoded int64 values
	vb, err := vEnc.Bytes()
	if err != nil {
		panic(err.Error())
	}

	// Preprend the first timestamp of the block in the first 8 bytes
	block := packBlockHeader(values[0].Time(), BlockInt64)
	return append(block, packBlock(tb, vb)...)
}

func decodeInt64Block(block []byte) ([]Value, error) {
	// slice off the first 8 bytes (min timestmap for the block)
	block = block[8:]

	blockType := block[0]
	if blockType != BlockInt64 {
		return nil, fmt.Errorf("invalid block type: exp %d, got %d", BlockInt64, blockType)
	}

	block = block[1:]

	// The first 8 bytes is the minimum timestamp of the block
	tb, vb := unpackBlock(block)

	// Setup our timestamp and value decoders
	tsDec := NewTimeDecoder(tb)
	vDec := NewInt64Decoder(vb)

	// Decode both a timestamp and value
	var a []Value
	for tsDec.Next() && vDec.Next() {
		ts := tsDec.Read()
		v := vDec.Read()
		a = append(a, &Int64Value{ts, v})
	}

	return a, nil
}

type StringValue struct {
	time  time.Time
	value string
}

func encodeStringBlock(buf []byte, blockType byte, values []StringValue) []byte {
	return nil
}

func packBlockHeader(firstTime time.Time, blockType byte) []byte {
	return append(u64tob(uint64(firstTime.UnixNano())), blockType)
}

func packBlock(ts []byte, values []byte) []byte {
	// We encode the length of the timestamp block using a variable byte encoding.
	// This allows small byte slices to take up 1 byte while larger ones use 2 or more.
	b := make([]byte, 10)
	i := binary.PutUvarint(b, uint64(len(ts)))

	// block is <len timestamp bytes>, <ts bytes>, <value bytes>
	block := append(b[:i], ts...)

	// We don't encode the value length because we know it's the rest of the block after
	// the timestamp block.
	return append(block, values...)
}

func unpackBlock(buf []byte) (ts, values []byte) {
	// Unpack the timestamp block length
	tsLen, i := binary.Uvarint(buf)

	// Unpack the timestamp bytes
	ts = buf[int(i) : int(i)+int(tsLen)]

	// Unpack the value bytes
	values = buf[int(i)+int(tsLen):]
	return
}

// ZigZagEncode converts a int64 to a uint64 by zig zagging negative and positive values
// across even and odd numbers.  Eg. [0,-1,1,-2] becomes [0, 1, 2, 3]
func ZigZagEncode(x int64) uint64 {
	return uint64(uint64(x<<1) ^ uint64((int64(x) >> 63)))
}

// ZigZagDecode converts a previously zigzag encoded uint64 back to a int64
func ZigZagDecode(v uint64) int64 {
	return int64((v >> 1) ^ uint64((int64(v&1)<<63)>>63))
}
<|endoftext|>


<commit_before>package broker

import (
	"flag"
	"log"
	"net/url"
	"os"
	"time"

	"github.com/heroku/busl/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
	"github.com/heroku/busl/util"
)

var (
	redisUrl           = flag.String("redisUrl", os.Getenv("REDIS_URL"), "URL of the redis server")
	redisServer        *url.URL
	redisPool          *redis.Pool
	redisKeyExpire     = 60 // redis uses seconds for EXPIRE
	redisChannelExpire = redisKeyExpire * 5
)

func init() {
	flag.Parse()
	redisServer, _ = url.Parse(*redisUrl)
	redisPool = newPool(redisServer)

	conn := redisPool.Get()
	defer conn.Close()
}

func newPool(server *url.URL) *redis.Pool {
	cleanServerURL := *server
	cleanServerURL.User = nil
	log.Printf("connecting to redis: %s", cleanServerURL)
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 4 * time.Minute,
		Dial: func() (c redis.Conn, err error) {
			c, err = redis.Dial("tcp", server.Host)
			if err != nil {
				return
			}

			if server.User == nil {
				return
			}

			pw, pwset := server.User.Password()
			if !pwset {
				return
			}

			if _, err = c.Do("AUTH", pw); err != nil {
				c.Close()
				return
			}
			return
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

type channel string

func (c channel) id() string {
	return string(c)
}

func (c channel) wildcardId() string {
	return string(c) + "*"
}

func (c channel) doneId() string {
	return string(c) + "done"
}

func (c channel) killId() string {
	return string(c) + "kill"
}

type RedisRegistrar struct{}

func NewRedisRegistrar() *RedisRegistrar {
	registrar := &RedisRegistrar{}

	return registrar
}

func (rr *RedisRegistrar) Register(channel string) (err error) {
	conn := redisPool.Get()
	defer conn.Close()

	_, err = conn.Do("SETEX", channel, redisChannelExpire, make([]byte, 0))
	if err != nil {
		util.CountWithData("RedisRegistrar.Register.error", 1, "error=%s", err)
		return
	}
	return
}

func (rr *RedisRegistrar) IsRegistered(channel string) (registered bool) {
	conn := redisPool.Get()
	defer conn.Close()

	exists, err := redis.Bool(conn.Do("EXISTS", channel))
	if err != nil {
		util.CountWithData("RedisRegistrar.IsRegistered.error", 1, "error=%s", err)
		return false
	}

	return exists
}

func Get(channel string) ([]byte, error) {
	conn := redisPool.Get()
	defer conn.Close()

	return redis.Bytes(conn.Do("GET", channel))
}
<commit_msg>Use channel.id to prevent ID changes from breaking it<commit_after>package broker

import (
	"flag"
	"log"
	"net/url"
	"os"
	"time"

	"github.com/heroku/busl/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
	"github.com/heroku/busl/util"
)

var (
	redisUrl           = flag.String("redisUrl", os.Getenv("REDIS_URL"), "URL of the redis server")
	redisServer        *url.URL
	redisPool          *redis.Pool
	redisKeyExpire     = 60 // redis uses seconds for EXPIRE
	redisChannelExpire = redisKeyExpire * 5
)

func init() {
	flag.Parse()
	redisServer, _ = url.Parse(*redisUrl)
	redisPool = newPool(redisServer)

	conn := redisPool.Get()
	defer conn.Close()
}

func newPool(server *url.URL) *redis.Pool {
	cleanServerURL := *server
	cleanServerURL.User = nil
	log.Printf("connecting to redis: %s", cleanServerURL)
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 4 * time.Minute,
		Dial: func() (c redis.Conn, err error) {
			c, err = redis.Dial("tcp", server.Host)
			if err != nil {
				return
			}

			if server.User == nil {
				return
			}

			pw, pwset := server.User.Password()
			if !pwset {
				return
			}

			if _, err = c.Do("AUTH", pw); err != nil {
				c.Close()
				return
			}
			return
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

type channel string

func (c channel) id() string {
	return string(c)
}

func (c channel) wildcardId() string {
	return string(c) + "*"
}

func (c channel) doneId() string {
	return string(c) + "done"
}

func (c channel) killId() string {
	return string(c) + "kill"
}

type RedisRegistrar struct{}

func NewRedisRegistrar() *RedisRegistrar {
	registrar := &RedisRegistrar{}

	return registrar
}

func (rr *RedisRegistrar) Register(channel string) (err error) {
	conn := redisPool.Get()
	defer conn.Close()

	_, err = conn.Do("SETEX", channel, redisChannelExpire, make([]byte, 0))
	if err != nil {
		util.CountWithData("RedisRegistrar.Register.error", 1, "error=%s", err)
		return
	}
	return
}

func (rr *RedisRegistrar) IsRegistered(channel string) (registered bool) {
	conn := redisPool.Get()
	defer conn.Close()

	exists, err := redis.Bool(conn.Do("EXISTS", channel))
	if err != nil {
		util.CountWithData("RedisRegistrar.IsRegistered.error", 1, "error=%s", err)
		return false
	}

	return exists
}

func Get(key string) ([]byte, error) {
	conn := redisPool.Get()
	defer conn.Close()

	channel := channel(key)
	return redis.Bytes(conn.Do("GET", channel.id()))
}
<|endoftext|>


<commit_before>// Copyright 2013 Prometheus Team
// 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 retrieval

import (
	"fmt"
	"github.com/prometheus/client_golang/metrics"
	"github.com/prometheus/prometheus/model"
	"github.com/prometheus/prometheus/retrieval/format"
	"net/http"
	"time"
)

const (
	instance = "instance"
)

// The state of the given Target.
type TargetState int

const (
	// The Target has not been seen; we know nothing about it, except that it is
	// on our docket for examination.
	UNKNOWN TargetState = iota
	// The Target has been found and successfully queried.
	ALIVE
	// The Target was either historically found or not found and then determined
	// to be unhealthy by either not responding or disappearing.
	UNREACHABLE
)

// A healthReporter is a type that can provide insight into its health state.
//
// It mainly exists for testability reasons to decouple the scheduler behaviors
// from fully-fledged Target and other types.
type healthReporter interface {
	// Report the last-known health state for this target.
	State() TargetState
}

// A Target represents an endpoint that should be interrogated for metrics.
//
// The protocol described by this type will likely change in future iterations,
// as it offers no good support for aggregated targets and fan out.  Thusly,
// it is likely that the current Target and target uses will be
// wrapped with some resolver type.
//
// For the future, the Target protocol will abstract away the exact means that
// metrics are retrieved and deserialized from the given instance to which it
// refers.
type Target interface {
	// Retrieve values from this target.
	//
	// earliest refers to the soonest available opportunity to reschedule the
	// target for a future retrieval.  It is up to the underlying scheduler type,
	// alluded to in the scheduledFor function, to use this as it wants to.  The
	// current use case is to create a common batching time for scraping multiple
	// Targets in the future through the TargetPool.
	Scrape(earliest time.Time, results chan format.Result) error
	// Fulfill the healthReporter interface.
	State() TargetState
	// Report the soonest time at which this Target may be scheduled for
	// retrieval.  This value needn't convey that the operation occurs at this
	// time, but it should occur no sooner than it.
	//
	// Right now, this is used as the sorting key in TargetPool.
	scheduledFor() time.Time
	// The address to which the Target corresponds.  Out of all of the available
	// points in this interface, this one is the best candidate to change given
	// the ways to express the endpoint.
	Address() string
	// Return the target's base labels.
	BaseLabels() model.LabelSet
	// Merge a new externally supplied target definition (e.g. with changed base
	// labels) into an old target definition for the same endpoint. Preserve
	// remaining information - like health state - from the old target.
	Merge(newTarget Target)
}

// target is a Target that refers to a singular HTTP or HTTPS endpoint.
type target struct {
	// scheduler provides the scheduling strategy that is used to formulate what
	// is returned in Target.scheduledFor.
	scheduler scheduler
	state     TargetState

	address string
	// What is the deadline for the HTTP or HTTPS against this endpoint.
	Deadline time.Duration
	// Any base labels that are added to this target and its metrics.
	baseLabels model.LabelSet
}

// Furnish a reasonably configured target for querying.
func NewTarget(address string, deadline time.Duration, baseLabels model.LabelSet) Target {
	target := &target{
		address:    address,
		Deadline:   deadline,
		baseLabels: baseLabels,
	}

	scheduler := &healthScheduler{
		target: target,
	}
	target.scheduler = scheduler

	return target
}

func (t *target) Scrape(earliest time.Time, results chan format.Result) (err error) {
	defer func() {
		futureState := t.state

		switch err {
		case nil:
			futureState = ALIVE
		default:
			futureState = UNREACHABLE
		}

		t.scheduler.Reschedule(earliest, futureState)
		t.state = futureState
	}()

	done := make(chan bool)

	request := func() {
		defer func() {
			done <- true
		}()

		var resp *http.Response // Don't shadow "err" from the enclosing function.
		resp, err = http.Get(t.Address())
		if err != nil {
			return
		}

		defer resp.Body.Close()

		processor, err := format.DefaultRegistry.ProcessorForRequestHeader(resp.Header)
		if err != nil {
			return
		}

		// XXX: This is a wart; we need to handle this more gracefully down the
		//      road, especially once we have service discovery support.
		baseLabels := model.LabelSet{instance: model.LabelValue(t.Address())}
		for baseLabel, baseValue := range t.baseLabels {
			baseLabels[baseLabel] = baseValue
		}

		err = processor.Process(resp.Body, baseLabels, results)
		if err != nil {
			return
		}
	}

	accumulator := func(d time.Duration) {
		ms := float64(d) / float64(time.Millisecond)
		labels := map[string]string{address: t.Address(), outcome: success}
		if err != nil {
			labels[outcome] = failure
		}

		targetOperationLatencies.Add(labels, ms)
		targetOperations.Increment(labels)
	}

	go metrics.InstrumentCall(request, accumulator)

	select {
	case <-done:
		break
	case <-time.After(t.Deadline):
		err = fmt.Errorf("Target %s exceeded %s deadline.", t, t.Deadline)
	}

	return
}

func (t target) State() TargetState {
	return t.state
}

func (t target) scheduledFor() time.Time {
	return t.scheduler.ScheduledFor()
}

func (t target) Address() string {
	return t.address
}

func (t target) BaseLabels() model.LabelSet {
	return t.baseLabels
}

// Merge a new externally supplied target definition (e.g. with changed base
// labels) into an old target definition for the same endpoint. Preserve
// remaining information - like health state - from the old target.
func (t *target) Merge(newTarget Target) {
	if t.Address() != newTarget.Address() {
		panic("targets don't refer to the same endpoint")
	}
	t.baseLabels = newTarget.BaseLabels()
}
<commit_msg>Include humanized target state strings.<commit_after>// Copyright 2013 Prometheus Team
// 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 retrieval

import (
	"fmt"
	"github.com/prometheus/client_golang/metrics"
	"github.com/prometheus/prometheus/model"
	"github.com/prometheus/prometheus/retrieval/format"
	"net/http"
	"time"
)

const (
	instance = "instance"
)

// The state of the given Target.
type TargetState int

func (t TargetState) String() string {
	switch t {
	case UNKNOWN:
		return "UNKNOWN"
	case ALIVE:
		return "ALIVE"
	case UNREACHABLE:
		return "UNREACHABLE"
	}

	panic("unknown state")
}

const (
	// The Target has not been seen; we know nothing about it, except that it is
	// on our docket for examination.
	UNKNOWN TargetState = iota
	// The Target has been found and successfully queried.
	ALIVE
	// The Target was either historically found or not found and then determined
	// to be unhealthy by either not responding or disappearing.
	UNREACHABLE
)

// A healthReporter is a type that can provide insight into its health state.
//
// It mainly exists for testability reasons to decouple the scheduler behaviors
// from fully-fledged Target and other types.
type healthReporter interface {
	// Report the last-known health state for this target.
	State() TargetState
}

// A Target represents an endpoint that should be interrogated for metrics.
//
// The protocol described by this type will likely change in future iterations,
// as it offers no good support for aggregated targets and fan out.  Thusly,
// it is likely that the current Target and target uses will be
// wrapped with some resolver type.
//
// For the future, the Target protocol will abstract away the exact means that
// metrics are retrieved and deserialized from the given instance to which it
// refers.
type Target interface {
	// Retrieve values from this target.
	//
	// earliest refers to the soonest available opportunity to reschedule the
	// target for a future retrieval.  It is up to the underlying scheduler type,
	// alluded to in the scheduledFor function, to use this as it wants to.  The
	// current use case is to create a common batching time for scraping multiple
	// Targets in the future through the TargetPool.
	Scrape(earliest time.Time, results chan format.Result) error
	// Fulfill the healthReporter interface.
	State() TargetState
	// Report the soonest time at which this Target may be scheduled for
	// retrieval.  This value needn't convey that the operation occurs at this
	// time, but it should occur no sooner than it.
	//
	// Right now, this is used as the sorting key in TargetPool.
	scheduledFor() time.Time
	// The address to which the Target corresponds.  Out of all of the available
	// points in this interface, this one is the best candidate to change given
	// the ways to express the endpoint.
	Address() string
	// Return the target's base labels.
	BaseLabels() model.LabelSet
	// Merge a new externally supplied target definition (e.g. with changed base
	// labels) into an old target definition for the same endpoint. Preserve
	// remaining information - like health state - from the old target.
	Merge(newTarget Target)
}

// target is a Target that refers to a singular HTTP or HTTPS endpoint.
type target struct {
	// scheduler provides the scheduling strategy that is used to formulate what
	// is returned in Target.scheduledFor.
	scheduler scheduler
	state     TargetState

	address string
	// What is the deadline for the HTTP or HTTPS against this endpoint.
	Deadline time.Duration
	// Any base labels that are added to this target and its metrics.
	baseLabels model.LabelSet
}

// Furnish a reasonably configured target for querying.
func NewTarget(address string, deadline time.Duration, baseLabels model.LabelSet) Target {
	target := &target{
		address:    address,
		Deadline:   deadline,
		baseLabels: baseLabels,
	}

	scheduler := &healthScheduler{
		target: target,
	}
	target.scheduler = scheduler

	return target
}

func (t *target) Scrape(earliest time.Time, results chan format.Result) (err error) {
	defer func() {
		futureState := t.state

		switch err {
		case nil:
			futureState = ALIVE
		default:
			futureState = UNREACHABLE
		}

		t.scheduler.Reschedule(earliest, futureState)
		t.state = futureState
	}()

	done := make(chan bool)

	request := func() {
		defer func() {
			done <- true
		}()

		var resp *http.Response // Don't shadow "err" from the enclosing function.
		resp, err = http.Get(t.Address())
		if err != nil {
			return
		}

		defer resp.Body.Close()

		processor, err := format.DefaultRegistry.ProcessorForRequestHeader(resp.Header)
		if err != nil {
			return
		}

		// XXX: This is a wart; we need to handle this more gracefully down the
		//      road, especially once we have service discovery support.
		baseLabels := model.LabelSet{instance: model.LabelValue(t.Address())}
		for baseLabel, baseValue := range t.baseLabels {
			baseLabels[baseLabel] = baseValue
		}

		err = processor.Process(resp.Body, baseLabels, results)
		if err != nil {
			return
		}
	}

	accumulator := func(d time.Duration) {
		ms := float64(d) / float64(time.Millisecond)
		labels := map[string]string{address: t.Address(), outcome: success}
		if err != nil {
			labels[outcome] = failure
		}

		targetOperationLatencies.Add(labels, ms)
		targetOperations.Increment(labels)
	}

	go metrics.InstrumentCall(request, accumulator)

	select {
	case <-done:
		break
	case <-time.After(t.Deadline):
		err = fmt.Errorf("Target %s exceeded %s deadline.", t, t.Deadline)
	}

	return
}

func (t target) State() TargetState {
	return t.state
}

func (t target) scheduledFor() time.Time {
	return t.scheduler.ScheduledFor()
}

func (t target) Address() string {
	return t.address
}

func (t target) BaseLabels() model.LabelSet {
	return t.baseLabels
}

// Merge a new externally supplied target definition (e.g. with changed base
// labels) into an old target definition for the same endpoint. Preserve
// remaining information - like health state - from the old target.
func (t *target) Merge(newTarget Target) {
	if t.Address() != newTarget.Address() {
		panic("targets don't refer to the same endpoint")
	}
	t.baseLabels = newTarget.BaseLabels()
}
<|endoftext|>


<commit_before>package ciolite

// Api functions that support: https://context.io/docs/lite/users/email_accounts/folders/messages/headers

import (
	"fmt"

	"github.com/contextio/contextio-go/cioutil"
)

// GetUserEmailAccountsFolderMessageHeadersParams query values data struct.
// Optional: Delimiter, Raw.
// 	https://context.io/docs/lite/users/email_accounts/folders/messages/headers#get
type GetUserEmailAccountsFolderMessageHeadersParams struct {
	// Optional:
	Delimiter string `json:"delimiter,omitempty"`
	Raw       bool   `json:"raw,omitempty"`
}

// GetUserEmailAccountsFolderMessageHeadersResponse data struct
// 	https://context.io/docs/lite/users/email_accounts/folders/messages/headers#get
type GetUserEmailAccountsFolderMessageHeadersResponse struct {
	ResourceURL int `json:"resource_url,omitempty"`

	Headers map[string]interface{} `json:"headers,omitempty"`
}

// GetUserEmailAccountsFolderMessageHeaders gets the complete headers of a given email message.
// queryValues may optionally contain Delimiter, Raw
// 	https://context.io/docs/lite/users/email_accounts/folders/messages/headers#get
func (cioLite CioLite) GetUserEmailAccountsFolderMessageHeaders(userID string, label string, folder string, messageID string, queryValues GetUserEmailAccountsFolderMessageHeadersParams) (GetUserEmailAccountsFolderMessageHeadersResponse, error) {

	// Make request
	request := cioutil.ClientRequest{
		Method:      "GET",
		Path:        fmt.Sprintf("/users/%s/email_accounts/%s/folders/%s/messages/%s/headers", userID, label, folder, messageID),
		QueryValues: queryValues,
	}

	// Make response
	var response GetUserEmailAccountsFolderMessageHeadersResponse

	// Request
	err := cioLite.DoFormRequest(request, &response)

	return response, err
}
<commit_msg>headers returns map of string -> []string<commit_after>package ciolite

// Api functions that support: https://context.io/docs/lite/users/email_accounts/folders/messages/headers

import (
	"fmt"

	"github.com/contextio/contextio-go/cioutil"
)

// GetUserEmailAccountsFolderMessageHeadersParams query values data struct.
// Optional: Delimiter, Raw.
// 	https://context.io/docs/lite/users/email_accounts/folders/messages/headers#get
type GetUserEmailAccountsFolderMessageHeadersParams struct {
	// Optional:
	Delimiter string `json:"delimiter,omitempty"`
	Raw       bool   `json:"raw,omitempty"`
}

// GetUserEmailAccountsFolderMessageHeadersResponse data struct
// 	https://context.io/docs/lite/users/email_accounts/folders/messages/headers#get
type GetUserEmailAccountsFolderMessageHeadersResponse struct {
	ResourceURL int `json:"resource_url,omitempty"`

	Headers map[string][]string `json:"headers,omitempty"`
}

// GetUserEmailAccountsFolderMessageHeaders gets the complete headers of a given email message.
// queryValues may optionally contain Delimiter, Raw
// 	https://context.io/docs/lite/users/email_accounts/folders/messages/headers#get
func (cioLite CioLite) GetUserEmailAccountsFolderMessageHeaders(userID string, label string, folder string, messageID string, queryValues GetUserEmailAccountsFolderMessageHeadersParams) (GetUserEmailAccountsFolderMessageHeadersResponse, error) {

	// Make request
	request := cioutil.ClientRequest{
		Method:      "GET",
		Path:        fmt.Sprintf("/users/%s/email_accounts/%s/folders/%s/messages/%s/headers", userID, label, folder, messageID),
		QueryValues: queryValues,
	}

	// Make response
	var response GetUserEmailAccountsFolderMessageHeadersResponse

	// Request
	err := cioLite.DoFormRequest(request, &response)

	return response, err
}
<|endoftext|>


<commit_before>package termcolours

import (
	"fmt"
	"image/color"
)

func Foreground24(c color.Color, s string) string {
	r, g, b, _ := c.RGBA()
	r = (r + 0x80) >> 8
	g = (g + 0x80) >> 8
	b = (b + 0x80) >> 8
	return fmt.Sprintf("%c[38;2;%d;%d;%dm%s%c[0m", ESC, r, g, b, s, ESC)
}

func Background24(c color.Color, s string) string {
	r, g, b, _ := c.RGBA()
	r = (r + 0x80) >> 8
	g = (g + 0x80) >> 8
	b = (b + 0x80) >> 8
	return fmt.Sprintf("%c[48;2;%d;%d;%dm%s%c[0m", ESC, r, g, b, s, ESC)
}
<commit_msg>Fix rounding error<commit_after>package termcolours

import (
	"fmt"
	"image/color"
)

func Foreground24(c color.Color, s string) string {
	r, g, b, _ := c.RGBA()
	r = r >> 8
	g = g >> 8
	b = b >> 8
	return fmt.Sprintf("%c[38;2;%d;%d;%dm%s%c[0m", ESC, r, g, b, s, ESC)
}

func Background24(c color.Color, s string) string {
	r, g, b, _ := c.RGBA()
	r = r >> 8
	g = g >> 8
	b = b >> 8
	return fmt.Sprintf("%c[48;2;%d;%d;%dm%s%c[0m", ESC, r, g, b, s, ESC)
}
<|endoftext|>


<commit_before>package leanpocker

type Card struct {
	// Rank of the card. Possible values are numbers 2-10 and J,Q,K,A
	Rank string `json:"rank"`

	// Suit of the card. Possible values are: clubs,spades,hearts,diamonds
	Suit string `json:"suit"`
}
<commit_msg>Fix package name<commit_after>package leanpoker

type Card struct {
	// Rank of the card. Possible values are numbers 2-10 and J,Q,K,A
	Rank string `json:"rank"`

	// Suit of the card. Possible values are: clubs,spades,hearts,diamonds
	Suit string `json:"suit"`
}
<|endoftext|>


<commit_before>package parser

import (
	"fmt"
	"sort"
	"strings"
)

type MetaObject struct {
	//! package name
	Package   string
	GoPackage string
	//! model name
	Name string
	Tag  string
	//! dbs
	Db      string
	Dbs     []string
	comment string
	//! database
	DbName  string
	DbTable string
	DbView  string
	//! fields
	fields       []*Field
	fieldNameMap map[string]*Field
	//! primary
	primary *PrimaryKey
	//! indexes
	uniques []*Index
	indexes []*Index
	ranges  []*Index
	//! relation
	Relation *Relation
	//! importSQL
	ImportSQL string
	//! elastic
	ElasticIndexAll bool
}

func NewMetaObject(packageName string) *MetaObject {
	return &MetaObject{
		Package:      packageName,
		GoPackage:    packageName,
		fieldNameMap: make(map[string]*Field),
		uniques:      []*Index{},
		indexes:      []*Index{},
		ranges:       []*Index{},
	}
}

func (o *MetaObject) FieldByName(name string) *Field {
	if f, ok := o.fieldNameMap[name]; ok {
		return f
	}
	return nil
}

func (o *MetaObject) PrimaryField() *Field {
	for _, f := range o.Fields() {
		if f.IsPrimary() {
			return f
		}
	}
	return nil
}

func (o *MetaObject) PrimaryKey() *PrimaryKey {
	return o.primary
}

func (o *MetaObject) DbContains(db string) bool {
	for _, v := range o.Dbs {
		if strings.ToLower(v) == strings.ToLower(db) {
			return true
		}
	}
	return false
}

func (o *MetaObject) DbSource() string {
	if o.DbTable != "" {
		return o.DbTable
	}
	if o.DbView != "" {
		return o.DbView
	}
	return ""
}

func (o *MetaObject) FromDB() string {
	switch o.Db {
	case "mssql":
		return fmt.Sprintf("[dbo].[%s]", o.DbSource())
	}
	return fmt.Sprintf("%s", o.DbSource())
}

func (o *MetaObject) Fields() []*Field {
	if o.Relation != nil {
		return o.Relation.Fields()
	}
	return o.fields
}

func (o *MetaObject) NoneIncrementFields() []*Field {
	if o.Relation != nil {
		return o.Relation.NoneIncrementFields()
	}
	fields := make([]*Field, 0, len(o.fields))
	for _, f := range o.fields {
		if f.IsAutoIncrement() == false {
			fields = append(fields, f)
		}
	}
	return fields
}

func (o *MetaObject) Uniques() []*Index {
	sort.Sort(IndexArray(o.uniques))
	return o.uniques
}

func (o *MetaObject) Indexes() []*Index {
	sort.Sort(IndexArray(o.indexes))
	return o.indexes
}

func (o *MetaObject) Ranges() []*Index {
	sort.Sort(IndexArray(o.ranges))
	return o.ranges
}
func (o *MetaObject) LastField() *Field {
	return o.fields[len(o.fields)-1]
}

func (o *MetaObject) Read(name string, data map[string]interface{}) error {
	o.Name = name
	hasType := false
	for key, val := range data {
		switch key {
		case "db":
			o.Db = val.(string)
			dbs := []string{}
			dbs = append(dbs, o.Db)
			dbs = append(dbs, o.Dbs...)
			o.Dbs = dbs
			hasType = true
		case "dbs":
			o.Dbs = toStringSlice(val.([]interface{}))
			if len(o.Dbs) != 0 {
				o.Db = o.Dbs[0]
			}
			hasType = true
		}
	}
	if hasType {
		delete(data, "db")
		delete(data, "dbs")
	}

	for key, val := range data {
		switch key {
		case "tag":
			tag := val.(int)
			o.Tag = fmt.Sprint(tag)
		case "dbname":
			o.DbName = val.(string)
		case "dbtable":
			o.DbTable = val.(string)
		case "dbview":
			o.DbView = val.(string)
		case "comment":
			o.comment = val.(string)

		case "importSQL":
			o.ImportSQL = val.(string)
		case "fields":
			fieldData := val.([]interface{})
			o.fields = make([]*Field, len(fieldData))
			for i, field := range fieldData {
				f := NewField()
				f.Obj = o
				err := f.Read(field.(map[interface{}]interface{}))
				if err != nil {
					return fmt.Errorf("object (%s) %s", o.Name, err.Error())
				}
				o.fields[i] = f
				o.fieldNameMap[f.Name] = f
			}
		case "primary":
			o.primary = NewPrimaryKey(o)
			o.primary.FieldNames = toStringSlice(val.([]interface{}))
		case "uniques":
			for _, i := range val.([]interface{}) {
				if len(i.([]interface{})) == 0 {
					continue
				}
				index := NewIndex(o)
				index.FieldNames = toStringSlice(i.([]interface{}))
				o.uniques = append(o.uniques, index)
			}
		case "indexes":
			for _, i := range val.([]interface{}) {
				if len(i.([]interface{})) == 0 {
					continue
				}
				index := NewIndex(o)
				index.FieldNames = toStringSlice(i.([]interface{}))
				o.indexes = append(o.indexes, index)
			}
		case "ranges":
			for _, i := range val.([]interface{}) {
				if len(i.([]interface{})) == 0 {
					continue
				}
				index := NewIndex(o)
				index.FieldNames = toStringSlice(i.([]interface{}))
				o.ranges = append(o.ranges, index)
			}
		case "relation":
			relation := NewRelation(o)
			err := relation.Read(val.(map[interface{}]interface{}))
			if err != nil {
				return fmt.Errorf("object (%s) %s", o.Name, err.Error())
			}
			o.Relation = relation

		case "es_index_all":
			o.ElasticIndexAll = val.(bool)
		}
	}

	for _, field := range o.fields {
		if field.IsPrimary() {
			if o.primary == nil {
				o.primary = NewPrimaryKey(o)
				o.primary.FieldNames = []string{}
			}
			o.primary.FieldNames = append(o.primary.FieldNames, field.Name)
		}
		if field.HasIndex() && field.IsNullable() {
			return fmt.Errorf("object (%s) field (%s) should not be nullable for indexing", o.Name, field.Name)
		}
	}

	if o.Relation == nil {
		if o.primary == nil {
			if o.DbContains("mysql") || o.DbContains("mssql") {
				return fmt.Errorf("object (%s) needs a primary key declare.", o.Name)
			}
		} else {
			if err := o.primary.build(); err != nil {
				return fmt.Errorf("object (%s) %s", o.Name, err.Error())
			}

			if o.primary.IsRange() {
				index := NewIndex(o)
				index.FieldNames = o.primary.FieldNames
				o.ranges = append(o.ranges, index)
			}
		}
	}

	for _, unique := range o.uniques {
		if err := unique.buildUnique(); err != nil {
			return fmt.Errorf("object (%s) %s", o.Name, err.Error())
		}
	}
	for _, index := range o.indexes {
		if err := index.buildIndex(); err != nil {
			return fmt.Errorf("object (%s) %s", o.Name, err.Error())
		}
	}
	for _, rg := range o.ranges {
		if err := rg.buildRange(); err != nil {
			return fmt.Errorf("object (%s) %s", o.Name, err.Error())
		}
	}
	return nil
}

func (m *MetaObject) ElasticIndexTypeName() string {
	if m.DbTable != "" {
		return m.DbTable
	}

	return Camel2Name(m.Name)
}

func (m *MetaObject) Comment() string {
	if m.comment != "" {
		return m.comment
	}

	return m.DbTable
}

func (o *MetaObject) CanSync() bool {
	if len(o.Dbs) > 1 && o.DbContains("redis") {
		return o.DbSource != "" || o.ImportSQL != ""
	}
	return false
}
<commit_msg>func missing<commit_after>package parser

import (
	"fmt"
	"sort"
	"strings"
)

type MetaObject struct {
	//! package name
	Package   string
	GoPackage string
	//! model name
	Name string
	Tag  string
	//! dbs
	Db      string
	Dbs     []string
	comment string
	//! database
	DbName  string
	DbTable string
	DbView  string
	//! fields
	fields       []*Field
	fieldNameMap map[string]*Field
	//! primary
	primary *PrimaryKey
	//! indexes
	uniques []*Index
	indexes []*Index
	ranges  []*Index
	//! relation
	Relation *Relation
	//! importSQL
	ImportSQL string
	//! elastic
	ElasticIndexAll bool
}

func NewMetaObject(packageName string) *MetaObject {
	return &MetaObject{
		Package:      packageName,
		GoPackage:    packageName,
		fieldNameMap: make(map[string]*Field),
		uniques:      []*Index{},
		indexes:      []*Index{},
		ranges:       []*Index{},
	}
}

func (o *MetaObject) FieldByName(name string) *Field {
	if f, ok := o.fieldNameMap[name]; ok {
		return f
	}
	return nil
}

func (o *MetaObject) PrimaryField() *Field {
	for _, f := range o.Fields() {
		if f.IsPrimary() {
			return f
		}
	}
	return nil
}

func (o *MetaObject) PrimaryKey() *PrimaryKey {
	return o.primary
}

func (o *MetaObject) DbContains(db string) bool {
	for _, v := range o.Dbs {
		if strings.ToLower(v) == strings.ToLower(db) {
			return true
		}
	}
	return false
}

func (o *MetaObject) DbSource() string {
	if o.DbTable != "" {
		return o.DbTable
	}
	if o.DbView != "" {
		return o.DbView
	}
	return ""
}

func (o *MetaObject) FromDB() string {
	switch o.Db {
	case "mssql":
		return fmt.Sprintf("[dbo].[%s]", o.DbSource())
	}
	return fmt.Sprintf("%s", o.DbSource())
}

func (o *MetaObject) Fields() []*Field {
	if o.Relation != nil {
		return o.Relation.Fields()
	}
	return o.fields
}

func (o *MetaObject) NoneIncrementFields() []*Field {
	if o.Relation != nil {
		return o.Relation.NoneIncrementFields()
	}
	fields := make([]*Field, 0, len(o.fields))
	for _, f := range o.fields {
		if f.IsAutoIncrement() == false {
			fields = append(fields, f)
		}
	}
	return fields
}

func (o *MetaObject) Uniques() []*Index {
	sort.Sort(IndexArray(o.uniques))
	return o.uniques
}

func (o *MetaObject) Indexes() []*Index {
	sort.Sort(IndexArray(o.indexes))
	return o.indexes
}

func (o *MetaObject) Ranges() []*Index {
	sort.Sort(IndexArray(o.ranges))
	return o.ranges
}
func (o *MetaObject) LastField() *Field {
	return o.fields[len(o.fields)-1]
}

func (o *MetaObject) Read(name string, data map[string]interface{}) error {
	o.Name = name
	hasType := false
	for key, val := range data {
		switch key {
		case "db":
			o.Db = val.(string)
			dbs := []string{}
			dbs = append(dbs, o.Db)
			dbs = append(dbs, o.Dbs...)
			o.Dbs = dbs
			hasType = true
		case "dbs":
			o.Dbs = toStringSlice(val.([]interface{}))
			if len(o.Dbs) != 0 {
				o.Db = o.Dbs[0]
			}
			hasType = true
		}
	}
	if hasType {
		delete(data, "db")
		delete(data, "dbs")
	}

	for key, val := range data {
		switch key {
		case "tag":
			tag := val.(int)
			o.Tag = fmt.Sprint(tag)
		case "dbname":
			o.DbName = val.(string)
		case "dbtable":
			o.DbTable = val.(string)
		case "dbview":
			o.DbView = val.(string)
		case "comment":
			o.comment = val.(string)

		case "importSQL":
			o.ImportSQL = val.(string)
		case "fields":
			fieldData := val.([]interface{})
			o.fields = make([]*Field, len(fieldData))
			for i, field := range fieldData {
				f := NewField()
				f.Obj = o
				err := f.Read(field.(map[interface{}]interface{}))
				if err != nil {
					return fmt.Errorf("object (%s) %s", o.Name, err.Error())
				}
				o.fields[i] = f
				o.fieldNameMap[f.Name] = f
			}
		case "primary":
			o.primary = NewPrimaryKey(o)
			o.primary.FieldNames = toStringSlice(val.([]interface{}))
		case "uniques":
			for _, i := range val.([]interface{}) {
				if len(i.([]interface{})) == 0 {
					continue
				}
				index := NewIndex(o)
				index.FieldNames = toStringSlice(i.([]interface{}))
				o.uniques = append(o.uniques, index)
			}
		case "indexes":
			for _, i := range val.([]interface{}) {
				if len(i.([]interface{})) == 0 {
					continue
				}
				index := NewIndex(o)
				index.FieldNames = toStringSlice(i.([]interface{}))
				o.indexes = append(o.indexes, index)
			}
		case "ranges":
			for _, i := range val.([]interface{}) {
				if len(i.([]interface{})) == 0 {
					continue
				}
				index := NewIndex(o)
				index.FieldNames = toStringSlice(i.([]interface{}))
				o.ranges = append(o.ranges, index)
			}
		case "relation":
			relation := NewRelation(o)
			err := relation.Read(val.(map[interface{}]interface{}))
			if err != nil {
				return fmt.Errorf("object (%s) %s", o.Name, err.Error())
			}
			o.Relation = relation

		case "es_index_all":
			o.ElasticIndexAll = val.(bool)
		}
	}

	for _, field := range o.fields {
		if field.IsPrimary() {
			if o.primary == nil {
				o.primary = NewPrimaryKey(o)
				o.primary.FieldNames = []string{}
			}
			o.primary.FieldNames = append(o.primary.FieldNames, field.Name)
		}
		if field.HasIndex() && field.IsNullable() {
			return fmt.Errorf("object (%s) field (%s) should not be nullable for indexing", o.Name, field.Name)
		}
	}

	if o.Relation == nil {
		if o.primary == nil {
			if o.DbContains("mysql") || o.DbContains("mssql") {
				return fmt.Errorf("object (%s) needs a primary key declare.", o.Name)
			}
		} else {
			if err := o.primary.build(); err != nil {
				return fmt.Errorf("object (%s) %s", o.Name, err.Error())
			}

			if o.primary.IsRange() {
				index := NewIndex(o)
				index.FieldNames = o.primary.FieldNames
				o.ranges = append(o.ranges, index)
			}
		}
	}

	for _, unique := range o.uniques {
		if err := unique.buildUnique(); err != nil {
			return fmt.Errorf("object (%s) %s", o.Name, err.Error())
		}
	}
	for _, index := range o.indexes {
		if err := index.buildIndex(); err != nil {
			return fmt.Errorf("object (%s) %s", o.Name, err.Error())
		}
	}
	for _, rg := range o.ranges {
		if err := rg.buildRange(); err != nil {
			return fmt.Errorf("object (%s) %s", o.Name, err.Error())
		}
	}
	return nil
}

func (m *MetaObject) ElasticIndexTypeName() string {
	if m.DbTable != "" {
		return m.DbTable
	}

	return Camel2Name(m.Name)
}

func (m *MetaObject) Comment() string {
	if m.comment != "" {
		return m.comment
	}

	return m.DbTable
}

func (o *MetaObject) CanSync() bool {
	if len(o.Dbs) > 1 && o.DbContains("redis") {
		return o.DbSource() != "" || o.ImportSQL != ""
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2015, Klaus Post, see LICENSE for details.

package password

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/klauspost/password/drivers/testdb"
	"github.com/klauspost/password/testdata"
	"github.com/klauspost/password/tokenizer"
)

// inDB will return information if a password is in the database
func inDB(password string, db DB, san Sanitizer) (bool, error) {
	if san == nil {
		san = DefaultSanitizer
	}
	p, err := san.Sanitize(password)
	if err != nil {
		return false, nil
	}
	p = strings.ToLower(p)
	return db.Has(p)
}

func TestImport(t *testing.T) {
	buf, err := testdata.Asset("testdata.txt.gz")
	if err != nil {
		t.Fatal(err)
	}
	mem := testdb.NewMemDB()
	in, err := tokenizer.NewGzLine(bytes.NewBuffer(buf))
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestImportBig(t *testing.T) {
	r, err := os.Open("crackstation-human-only.txt.gz")
	if err != nil {
		t.Skip("Skipping big file test. 'crackstation-human-only.txt.gz' must be in current dir")
	}
	mem := testdb.NewMemDBBulk()
	in, err := tokenizer.NewGzLine(r)
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestImportBz2(t *testing.T) {
	r, err := os.Open("rockyou.txt.bz2")
	if err != nil {
		t.Skip("Skipping bz2 file test. 'rockyou.txt.bz2' must be in current dir")
	}
	mem := testdb.NewMemDBBulk()
	in := tokenizer.NewBz2Line(r)
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestImportBulk(t *testing.T) {
	buf, err := testdata.Asset("testdata.txt.gz")
	if err != nil {
		t.Fatal(err)
	}
	mem := testdb.NewMemDBBulk()
	in, err := tokenizer.NewGzLine(bytes.NewBuffer(buf))
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
	// Test everything is kept open.
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestInDB(t *testing.T) {
	buf, err := testdata.Asset("testdata.txt.gz")
	if err != nil {
		t.Fatal(err)
	}
	mem := testdb.NewMemDB()
	in, err := tokenizer.NewGzLine(bytes.NewBuffer(buf))
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	for p := range testdata.TestSet {
		if SanitizeOK(p, nil) != nil {
			continue
		}
		has, err := inDB(p, mem, nil)
		if err != nil {
			t.Fatal(err)
		}
		if !has {
			t.Fatalf("db should have: %s", p)
		}
		err = Check(p, mem, nil)
		if err != ErrPasswordInDB {
			t.Fatal("check failed on:", p, err)
		}
	}
	for p := range testdata.NotInSet {
		if SanitizeOK(p, nil) != nil {
			continue
		}
		has, err := inDB(p, mem, nil)
		if err != nil {
			t.Fatal(err)
		}
		if has {
			t.Fatalf("db should not have: %s", p)
		}
		err = Check(p, mem, nil)
		if err != nil {
			t.Fatal("check failed on:", p, err)
		}
	}
}

func TestInDBBulk(t *testing.T) {
	buf, err := testdata.Asset("testdata.txt.gz")
	if err != nil {
		t.Fatal(err)
	}
	mem := testdb.NewMemDBBulk()
	in, err := tokenizer.NewGzLine(bytes.NewBuffer(buf))
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	for p := range testdata.TestSet {
		if SanitizeOK(p, nil) != nil {
			continue
		}
		has, err := inDB(p, mem, nil)
		if err != nil {
			t.Fatal(err)
		}
		if !has {
			t.Fatalf("db should have: %s", p)
		}
		err = Check(p, mem, nil)
		if err != ErrPasswordInDB {
			t.Fatal("check failed on:", p, err)
		}
	}
	for p := range testdata.NotInSet {
		if SanitizeOK(p, nil) != nil {
			continue
		}
		has, err := inDB(p, mem, nil)
		if err != nil {
			t.Fatal(err)
		}
		if has {
			t.Fatalf("db should not have: %s", p)
		}
		err = Check(p, mem, nil)
		if err != nil {
			t.Fatal("check failed on:", p, err)
		}
	}
}

func TestDefaultSanitizer(t *testing.T) {
	san := DefaultSanitizer
	all := map[string]testdata.PassErr{}
	for p := range testdata.TestSet {
		s, err := san.Sanitize(p)
		if true {
			pw := testdata.PassErr{S: s}
			if err != nil {
				pw.E = err.Error()
			}
			all[p] = pw
			continue
		}
		expect, ok := testdata.SanitizeExpect[p]
		if !ok {
			t.Fatalf("Sanitized version of `%s` not defined.", p)
		}
		if s != expect.S {
			t.Fatalf("Sanitized difference. Expected `%s`, got `%s`", expect.S, s)
		}
		e := ""
		if err != nil {
			e = err.Error()
		}
		if e != expect.E {
			t.Fatalf("Sanitized error difference. Expected `%s`, got `%s`", expect.E, e)
		}
	}
	//t.Logf("var SanitizeExpect = %#v", all)
}

type CustomSanitizer struct {
	email    string
	username string
}

func (c CustomSanitizer) Sanitize(s string) (string, error) {
	s, err := DefaultSanitizer.Sanitize(s)
	if err != nil {
		return "", err
	}
	if strings.EqualFold(s, c.email) {
		return "", errors.New("password cannot be the same as email")
	}
	if strings.EqualFold(s, c.username) {
		return "", errors.New("password cannot be the same as user name")
	}
	return s, nil
}

// This example shows how to create a custom sanitizer that checks if
// the password matches the username or email.
//
// CustomSanitizer is defined as:
//  type CustomSanitizer struct {
//      email string
//      username string
//  }
//
//  func (c CustomSanitizer) Sanitize(s string) (string, error) {
//      s, err := DefaultSanitizer.Sanitize(s)
//      if err != nil {
//          return "", err
//      }
//      if strings.EqualFold(s, c.email) {
//          return "", errors.New("password cannot be the same as email")
//      }
//      if strings.EqualFold(s, c.username) {
//          return "", errors.New("password cannot be the same as user name")
//      }
//      return s, nil
//  }
func ExampleSanitizer() {
	// Create a custom sanitizer.
	san := CustomSanitizer{email: "john@doe.com", username: "johndoe73"}

	// Check some passwords
	err := SanitizeOK("john@doe.com", san)
	fmt.Println(err)

	err = SanitizeOK("JohnDoe73", san)
	fmt.Println(err)

	err = SanitizeOK("MyP/|$$W0rd", san)
	fmt.Println(err)
	// Output: password cannot be the same as email
	// password cannot be the same as user name
	// <nil>
}

func ExampleImport() {
	r, err := os.Open("./testdata/testdata.txt.gz")
	if err != nil {
		panic("cannot open file")
	}
	// Create a database to write to
	mem := testdb.NewMemDBBulk()

	// The input is gzipped text file with
	// one input per line, so we choose a tokenizer
	// that matches.
	in, err := tokenizer.NewGzLine(r)
	if err != nil {
		panic(err)
	}
	// Import using the default sanitizer
	err = Import(in, mem, nil)
	if err != nil {
		panic(err)
	}
	// Data is now imported, let's do a check
	// Check a password that is in the sample data
	err = Check("tl1992rell", mem, nil)
	fmt.Println(err)
	// Output:password found in database
}
<commit_msg>Add xz import example.<commit_after>// Copyright 2015, Klaus Post, see LICENSE for details.

package password

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/klauspost/password/drivers/testdb"
	"github.com/klauspost/password/testdata"
	"github.com/klauspost/password/tokenizer"
	"xi2.org/x/xz"
)

// inDB will return information if a password is in the database
func inDB(password string, db DB, san Sanitizer) (bool, error) {
	if san == nil {
		san = DefaultSanitizer
	}
	p, err := san.Sanitize(password)
	if err != nil {
		return false, nil
	}
	p = strings.ToLower(p)
	return db.Has(p)
}

func TestImport(t *testing.T) {
	buf, err := testdata.Asset("testdata.txt.gz")
	if err != nil {
		t.Fatal(err)
	}
	mem := testdb.NewMemDB()
	in, err := tokenizer.NewGzLine(bytes.NewBuffer(buf))
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
}

// Open a xz compressed archive and import it.
// Uses the "xi2.org/x/xz" package to read xz files.
func ExampleImport_xz() {
	r, err := os.Open("rockyou.txt.xz")
	if err != nil {
		// Fake it
		fmt.Println("Imported", 9341543, "items")
		return
	}
	xzr, err := xz.NewReader(r, 0)
	if err != nil {
		panic(err)
	}
	mem := testdb.NewMemDBBulk()
	in := tokenizer.NewLine(xzr)
	err = Import(in, mem, nil)
	if err != nil {
		panic(err)
	}
	fmt.Println("Imported", len(*mem), "items")
	// Output: Imported 9341543 items
}

func TestImportBig(t *testing.T) {
	r, err := os.Open("crackstation-human-only.txt.gz")
	if err != nil {
		t.Skip("Skipping big file test. 'crackstation-human-only.txt.gz' must be in current dir")
	}
	mem := testdb.NewMemDBBulk()
	in, err := tokenizer.NewGzLine(r)
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestImportBz2(t *testing.T) {
	r, err := os.Open("rockyou.txt.bz2")
	if err != nil {
		t.Skip("Skipping bz2 file test. 'rockyou.txt.bz2' must be in current dir")
	}
	mem := testdb.NewMemDBBulk()
	in := tokenizer.NewBz2Line(r)
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestImportBulk(t *testing.T) {
	buf, err := testdata.Asset("testdata.txt.gz")
	if err != nil {
		t.Fatal(err)
	}
	mem := testdb.NewMemDBBulk()
	in, err := tokenizer.NewGzLine(bytes.NewBuffer(buf))
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
	// Test everything is kept open.
	err = Import(in, mem, nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestInDB(t *testing.T) {
	buf, err := testdata.Asset("testdata.txt.gz")
	if err != nil {
		t.Fatal(err)
	}
	mem := testdb.NewMemDB()
	in, err := tokenizer.NewGzLine(bytes.NewBuffer(buf))
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	for p := range testdata.TestSet {
		if SanitizeOK(p, nil) != nil {
			continue
		}
		has, err := inDB(p, mem, nil)
		if err != nil {
			t.Fatal(err)
		}
		if !has {
			t.Fatalf("db should have: %s", p)
		}
		err = Check(p, mem, nil)
		if err != ErrPasswordInDB {
			t.Fatal("check failed on:", p, err)
		}
	}
	for p := range testdata.NotInSet {
		if SanitizeOK(p, nil) != nil {
			continue
		}
		has, err := inDB(p, mem, nil)
		if err != nil {
			t.Fatal(err)
		}
		if has {
			t.Fatalf("db should not have: %s", p)
		}
		err = Check(p, mem, nil)
		if err != nil {
			t.Fatal("check failed on:", p, err)
		}
	}
}

func TestInDBBulk(t *testing.T) {
	buf, err := testdata.Asset("testdata.txt.gz")
	if err != nil {
		t.Fatal(err)
	}
	mem := testdb.NewMemDBBulk()
	in, err := tokenizer.NewGzLine(bytes.NewBuffer(buf))
	if err != nil {
		t.Fatal(err)
	}
	err = Import(in, mem, nil)
	for p := range testdata.TestSet {
		if SanitizeOK(p, nil) != nil {
			continue
		}
		has, err := inDB(p, mem, nil)
		if err != nil {
			t.Fatal(err)
		}
		if !has {
			t.Fatalf("db should have: %s", p)
		}
		err = Check(p, mem, nil)
		if err != ErrPasswordInDB {
			t.Fatal("check failed on:", p, err)
		}
	}
	for p := range testdata.NotInSet {
		if SanitizeOK(p, nil) != nil {
			continue
		}
		has, err := inDB(p, mem, nil)
		if err != nil {
			t.Fatal(err)
		}
		if has {
			t.Fatalf("db should not have: %s", p)
		}
		err = Check(p, mem, nil)
		if err != nil {
			t.Fatal("check failed on:", p, err)
		}
	}
}

func TestDefaultSanitizer(t *testing.T) {
	san := DefaultSanitizer
	all := map[string]testdata.PassErr{}
	for p := range testdata.TestSet {
		s, err := san.Sanitize(p)
		if true {
			pw := testdata.PassErr{S: s}
			if err != nil {
				pw.E = err.Error()
			}
			all[p] = pw
			continue
		}
		expect, ok := testdata.SanitizeExpect[p]
		if !ok {
			t.Fatalf("Sanitized version of `%s` not defined.", p)
		}
		if s != expect.S {
			t.Fatalf("Sanitized difference. Expected `%s`, got `%s`", expect.S, s)
		}
		e := ""
		if err != nil {
			e = err.Error()
		}
		if e != expect.E {
			t.Fatalf("Sanitized error difference. Expected `%s`, got `%s`", expect.E, e)
		}
	}
	//t.Logf("var SanitizeExpect = %#v", all)
}

type CustomSanitizer struct {
	email    string
	username string
}

func (c CustomSanitizer) Sanitize(s string) (string, error) {
	s, err := DefaultSanitizer.Sanitize(s)
	if err != nil {
		return "", err
	}
	if strings.EqualFold(s, c.email) {
		return "", errors.New("password cannot be the same as email")
	}
	if strings.EqualFold(s, c.username) {
		return "", errors.New("password cannot be the same as user name")
	}
	return s, nil
}

// This example shows how to create a custom sanitizer that checks if
// the password matches the username or email.
//
// CustomSanitizer is defined as:
//  type CustomSanitizer struct {
//      email string
//      username string
//  }
//
//  func (c CustomSanitizer) Sanitize(s string) (string, error) {
//      s, err := DefaultSanitizer.Sanitize(s)
//      if err != nil {
//          return "", err
//      }
//      if strings.EqualFold(s, c.email) {
//          return "", errors.New("password cannot be the same as email")
//      }
//      if strings.EqualFold(s, c.username) {
//          return "", errors.New("password cannot be the same as user name")
//      }
//      return s, nil
//  }
func ExampleSanitizer() {
	// Create a custom sanitizer.
	san := CustomSanitizer{email: "john@doe.com", username: "johndoe73"}

	// Check some passwords
	err := SanitizeOK("john@doe.com", san)
	fmt.Println(err)

	err = SanitizeOK("JohnDoe73", san)
	fmt.Println(err)

	err = SanitizeOK("MyP/|$$W0rd", san)
	fmt.Println(err)
	// Output: password cannot be the same as email
	// password cannot be the same as user name
	// <nil>
}

func ExampleImport() {
	r, err := os.Open("./testdata/testdata.txt.gz")
	if err != nil {
		panic("cannot open file")
	}
	// Create a database to write to
	mem := testdb.NewMemDBBulk()

	// The input is gzipped text file with
	// one input per line, so we choose a tokenizer
	// that matches.
	in, err := tokenizer.NewGzLine(r)
	if err != nil {
		panic(err)
	}
	// Import using the default sanitizer
	err = Import(in, mem, nil)
	if err != nil {
		panic(err)
	}
	// Data is now imported, let's do a check
	// Check a password that is in the sample data
	err = Check("tl1992rell", mem, nil)
	fmt.Println(err)
	// Output:password found in database
}
<|endoftext|>


<commit_before>package tracking

import (
	"encoding/json"
	"fmt"
	"gopkg.in/cas.v1"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"
	"gopkg.in/mgo.v2"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"gopkg.in/mgo.v2/bson"
)

//  represents a single position observed for a Vehicle from the data feed.
type VehicleUpdate struct {
	VehicleID string    `json:"vehicleID"   bson:"vehicleID,omitempty"`
	Lat       string    `json:"lat"         bson:"lat"`
	Lng       string    `json:"lng"         bson:"lng"`
	Heading   string    `json:"heading"     bson:"heading"`
	Speed     string    `json:"speed"       bson:"speed"`
	Lock      string    `json:"lock"        bson:"lock"`
	Time      string    `json:"time"        bson:"time"`
	Date      string    `json:"date"        bson:"date"`
	Status    string    `json:"status"      bson:"status"`
	Created   time.Time `json:"created"     bson:"created"`
	Segment   string    `json:"segment" 		bson:"segment"` // the segment that a vehicle resides on
}

// Vehicle represents an object being tracked.
type Vehicle struct {
	VehicleID   string    `json:"vehicleID"   bson:"vehicleID,omitempty"`
	VehicleName string    `json:"vehicleName" bson:"vehicleName"`
	Created     time.Time `bson:"created"`
	Updated     time.Time `bson:"updated"`
	ActiveStatus			int				`bson:"activeCount"`
	Active bool `json:"active"`
}

// Status contains a detailed message on the tracked object's status
type Status struct {
	Public  bool      `bson:"public"`
	Message string    `json:"message" bson:"message"`
	Created time.Time `bson:"created"`
	Updated time.Time `bson:"updated"`
}

var (
	// Match each API field with any number (+)
	//   of the previous expressions (\d digit, \. escaped period, - negative number)
	//   Specify named capturing groups to store each field from data feed
	dataRe    = regexp.MustCompile(`(?P<id>Vehicle ID:([\d\.]+)) (?P<lat>lat:([\d\.-]+)) (?P<lng>lon:([\d\.-]+)) (?P<heading>dir:([\d\.-]+)) (?P<speed>spd:([\d\.-]+)) (?P<lock>lck:([\d\.-]+)) (?P<time>time:([\d]+)) (?P<date>date:([\d]+)) (?P<status>trig:([\d]+))`)
	dataNames = dataRe.SubexpNames()
)
var lastUpdate time.Time

// UpdateShuttles send a request to iTrak API, gets updated shuttle info, and
// finally store updated records in db.
func (App *App) UpdateShuttles(dataFeed string, updateInterval int) {
	var st time.Duration
	for {

		// Sleep for n seconds before updating again
		log.Debugf("sleeping for %v", st)
		time.Sleep(st)
		if st == 0 {
			// Initialize the sleep timer after the first sleep.  This lets us sleep during errors
			// when we 'continue' back to the top of the loop without waiting to sleep for the first
			// update run.
			st = time.Duration(updateInterval) * time.Second
		}

		// Make request to our tracking data feed
		resp, err := http.Get(dataFeed)
		if err != nil {
			log.Errorf("error getting data feed: %v", err)
			continue
		}

		// Read response body content
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Errorf("error reading data feed: %v", err)
			continue
		}

		// this cannot be deferred because that will never get garbage collected
		resp.Body.Close()

		delim := "eof"
		// split the body of response by delimiter
		vehiclesData := strings.Split(string(body), delim)
		// BUG: if the request fails, it will give undefined result

		// TODO: Figure out if this handles == 1 vehicle correctly or always assumes > 1.
		if len(vehiclesData) <= 1 {
			log.Warnf("found no vehicles delineated by '%s'", delim)
		}

		updated := 0
		// for parsed data, update each vehicle
		for i := 0; i < len(vehiclesData)-1; i++ {
			match := dataRe.FindAllStringSubmatch(vehiclesData[i], -1)[0]
			// Store named capturing group and matching expression as a key value pair
			result := map[string]string{}
			for i, item := range match {
				result[dataNames[i]] = item
			}

			// Create new vehicle update & insert update into database
			// add computation of segment that the shuttle resides on and the arrival time to next N stops [here]

			// convert KPH to MPH
			speedKMH, err := strconv.ParseFloat(strings.Replace(result["speed"], "spd:", "", -1), 64)
			if err != nil {
				log.Error(err)
				continue
			}
			speedMPH := KPHtoMPH(speedKMH)
			speedMPHString := strconv.FormatFloat(speedMPH, 'f', 5, 64)

			update := VehicleUpdate{
				VehicleID: strings.Replace(result["id"], "Vehicle ID:", "", -1),
				Lat:       strings.Replace(result["lat"], "lat:", "", -1),
				Lng:       strings.Replace(result["lng"], "lon:", "", -1),
				Heading:   strings.Replace(result["heading"], "dir:", "", -1),
				Speed:     speedMPHString,
				Lock:      strings.Replace(result["lock"], "lck:", "", -1),
				Time:      strings.Replace(result["time"], "time:", "", -1),
				Date:      strings.Replace(result["date"], "date:", "", -1),
				Status:    strings.Replace(result["status"], "trig:", "", -1),
				Created:   time.Now()}

			// convert updated time to local time
			loc, err := time.LoadLocation("America/New_York")
			if err != nil {
				log.Error(err.Error())
				continue
			}
			var currentVehicle Vehicle;
			findErr := App.Vehicles.Find(bson.M{"vehicleID":update.VehicleID}).One(&currentVehicle);
			_ = findErr //Error Handling!

			lastUpdate = time.Now().In(loc)

			//if a shuttle hasnt gone over 3 miles per hour in 5 minutes, it is probably inactive, and we shouldn't show it.
			spd, err := strconv.ParseFloat(update.Speed, 64)
			if err != nil {
				log.Errorf("error finding speed")
			}
			if spd < 3 {
				currentVehicle.ActiveStatus += 1

			} else {
			 	currentVehicle.ActiveStatus = 0
				currentVehicle.Active = true
			}
			c := mgo.Change{
				ve,
				true,
				false,
				true,
			}
			if = currentVehicle.ActiveStatus > 20 {
				currentVehicle.Active = false;
			}
			changeInfo,findErr := App.Vehicles.Find(bson.M{"vehicleID":update.VehicleID}).Apply(c,&currentVehicle)
			_ = changeInfo

			if err := App.Updates.Insert(&update); err != nil {
				log.Errorf("error inserting vehicle update(%v): %v", update, err)
			} else {
				updated++
			}

			// here if parsing error, updated will be incremented, wait, the whole thing will crash, isn't it?
		}
		log.Infof("sucessfully updated %d/%d vehicles", updated, len(vehiclesData)-1)
	}
}

// VehiclesHandler finds all the vehicles in the database.
func (App *App) VehiclesHandler(w http.ResponseWriter, r *http.Request) {

	// Find all vehicles in database
	var vehicles []Vehicle
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle query errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Send each vehicle to client as JSON
	WriteJSON(w, vehicles)
}

// VehiclesCreateHandler adds a new vehicle to the database.
func (App *App) VehiclesCreateHandler(w http.ResponseWriter, r *http.Request) {
	if App.Config.Authenticate && !cas.IsAuthenticated(r) {
		return
	}

	// Create new vehicle object using request fields
	vehicle := Vehicle{}
	vehicle.Created = time.Now()
	vehicle.Updated = time.Now()
	vehicleData := json.NewDecoder(r.Body)
	err := vehicleData.Decode(&vehicle)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Store new vehicle under vehicles collection
	err = App.Vehicles.Insert(&vehicle)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (App *App) VehiclesEditHandler(w http.ResponseWriter, r *http.Request) {

}

func (App *App) VehiclesDeleteHandler(w http.ResponseWriter, r *http.Request) {
	if App.Config.Authenticate && !cas.IsAuthenticated(r) {
		return
	}

	// Delete vehicle from Vehicles collection
	vars := mux.Vars(r)
	log.Debugf("deleting", vars["id"])
	err := App.Vehicles.Remove(bson.M{"vehicleID": vars["id"]})
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// Here's my view, keep every name the same meaning, otherwise, choose another.
// UpdatesHandler get the most recent update for each vehicle in the vehicles collection.
func (App *App) UpdatesHandler(w http.ResponseWriter, r *http.Request) {
	// Store updates for each vehicle
	var vehicles []Vehicle
	var updates []VehicleUpdate
	var update VehicleUpdate
	// Query all Vehicles
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Find recent updates for each vehicle
	for _, vehicle := range vehicles {
		// here, huge waste of computational power, you record every shit inside the Updates table and using sort, I don't know what the hell is going on
		err := App.Updates.Find(bson.M{"vehicleID": vehicle.VehicleID}).Sort("-created").Limit(1).One(&update)

		if err == nil && vehicle.Active{
			updates = append(updates, update)
		}
	}
	// Convert updates to JSON
	WriteJSON(w, updates) // it's good to take some REST in our server :)
}

// UpdateMessageHandler generates a message about an update for a vehicle
func (App *App) UpdateMessageHandler(w http.ResponseWriter, r *http.Request) {
	// For each vehicle/update, store message as a string
	var messages []string
	var message string
	var vehicles []Vehicle
	var update VehicleUpdate

	// Query all Vehicles
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Find recent updates and generate message
	for _, vehicle := range vehicles {
		// find 10 most recent records
		err := App.Updates.Find(bson.M{"vehicleID": vehicle.VehicleID}).Sort("-created").Limit(1).One(&update)
		if err == nil {
			// Use first 4 char substring of update.Speed
			speed := update.Speed
			if len(speed) > 4 {
				speed = speed[0:4]
			}
			//nextArrival := GetArrivalTime(&update, App.Routes, App.Stops)
			message = fmt.Sprintf("%s
Traveling %s at
 %s mph as of %s", vehicle.VehicleName, CardinalDirection(&update.Heading), speed, lastUpdate.Format("3:04:05pm") /*, nextArrival*/)
			messages = append(messages, message)
		}
	}
	// Convert to JSON
	WriteJSON(w, messages)
}

// CardinalDirection figures out the cardinal direction of a vehicle's heading
func CardinalDirection(h *string) string {
	heading, err := strconv.ParseFloat(*h, 64)
	if err != nil {
		fmt.Println("ERROR", err.Error())
		return "North"
	}
	switch {
	case (heading >= 22.5 && heading < 67.5):
		return "North-East"
	case (heading >= 67.5 && heading < 112.5):
		return "East"
	case (heading >= 112.5 && heading < 157.5):
		return "South-East"
	case (heading >= 157.5 && heading < 202.5):
		return "South"
	case (heading >= 202.5 && heading < 247.5):
		return "South-West"
	case (heading >= 247.5 && heading < 292.5):
		return "West"
	case (heading >= 292.5 && heading < 337.5):
		return "North-West"
	default:
		return "North"
	}
}

// convert kmh to mph
func KPHtoMPH(kmh float64) (mph float64) {
	mph = kmh * 0.621371192
	return
}
<commit_msg>Fixed a build breaking bug<commit_after>package tracking

import (
	"encoding/json"
	"fmt"
	"gopkg.in/cas.v1"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"
	"gopkg.in/mgo.v2"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"
	"gopkg.in/mgo.v2/bson"
)

//  represents a single position observed for a Vehicle from the data feed.
type VehicleUpdate struct {
	VehicleID string    `json:"vehicleID"   bson:"vehicleID,omitempty"`
	Lat       string    `json:"lat"         bson:"lat"`
	Lng       string    `json:"lng"         bson:"lng"`
	Heading   string    `json:"heading"     bson:"heading"`
	Speed     string    `json:"speed"       bson:"speed"`
	Lock      string    `json:"lock"        bson:"lock"`
	Time      string    `json:"time"        bson:"time"`
	Date      string    `json:"date"        bson:"date"`
	Status    string    `json:"status"      bson:"status"`
	Created   time.Time `json:"created"     bson:"created"`
	Segment   string    `json:"segment" 		bson:"segment"` // the segment that a vehicle resides on
}

// Vehicle represents an object being tracked.
type Vehicle struct {
	VehicleID   string    `json:"vehicleID"   bson:"vehicleID,omitempty"`
	VehicleName string    `json:"vehicleName" bson:"vehicleName"`
	Created     time.Time `bson:"created"`
	Updated     time.Time `bson:"updated"`
	ActiveStatus			int				`bson:"activeCount"`
	Active bool `json:"active"`
}

// Status contains a detailed message on the tracked object's status
type Status struct {
	Public  bool      `bson:"public"`
	Message string    `json:"message" bson:"message"`
	Created time.Time `bson:"created"`
	Updated time.Time `bson:"updated"`
}

var (
	// Match each API field with any number (+)
	//   of the previous expressions (\d digit, \. escaped period, - negative number)
	//   Specify named capturing groups to store each field from data feed
	dataRe    = regexp.MustCompile(`(?P<id>Vehicle ID:([\d\.]+)) (?P<lat>lat:([\d\.-]+)) (?P<lng>lon:([\d\.-]+)) (?P<heading>dir:([\d\.-]+)) (?P<speed>spd:([\d\.-]+)) (?P<lock>lck:([\d\.-]+)) (?P<time>time:([\d]+)) (?P<date>date:([\d]+)) (?P<status>trig:([\d]+))`)
	dataNames = dataRe.SubexpNames()
)
var lastUpdate time.Time

// UpdateShuttles send a request to iTrak API, gets updated shuttle info, and
// finally store updated records in db.
func (App *App) UpdateShuttles(dataFeed string, updateInterval int) {
	var st time.Duration
	for {

		// Sleep for n seconds before updating again
		log.Debugf("sleeping for %v", st)
		time.Sleep(st)
		if st == 0 {
			// Initialize the sleep timer after the first sleep.  This lets us sleep during errors
			// when we 'continue' back to the top of the loop without waiting to sleep for the first
			// update run.
			st = time.Duration(updateInterval) * time.Second
		}

		// Make request to our tracking data feed
		resp, err := http.Get(dataFeed)
		if err != nil {
			log.Errorf("error getting data feed: %v", err)
			continue
		}

		// Read response body content
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Errorf("error reading data feed: %v", err)
			continue
		}

		// this cannot be deferred because that will never get garbage collected
		resp.Body.Close()

		delim := "eof"
		// split the body of response by delimiter
		vehiclesData := strings.Split(string(body), delim)
		// BUG: if the request fails, it will give undefined result

		// TODO: Figure out if this handles == 1 vehicle correctly or always assumes > 1.
		if len(vehiclesData) <= 1 {
			log.Warnf("found no vehicles delineated by '%s'", delim)
		}

		updated := 0
		// for parsed data, update each vehicle
		for i := 0; i < len(vehiclesData)-1; i++ {
			match := dataRe.FindAllStringSubmatch(vehiclesData[i], -1)[0]
			// Store named capturing group and matching expression as a key value pair
			result := map[string]string{}
			for i, item := range match {
				result[dataNames[i]] = item
			}

			// Create new vehicle update & insert update into database
			// add computation of segment that the shuttle resides on and the arrival time to next N stops [here]

			// convert KPH to MPH
			speedKMH, err := strconv.ParseFloat(strings.Replace(result["speed"], "spd:", "", -1), 64)
			if err != nil {
				log.Error(err)
				continue
			}
			speedMPH := KPHtoMPH(speedKMH)
			speedMPHString := strconv.FormatFloat(speedMPH, 'f', 5, 64)

			update := VehicleUpdate{
				VehicleID: strings.Replace(result["id"], "Vehicle ID:", "", -1),
				Lat:       strings.Replace(result["lat"], "lat:", "", -1),
				Lng:       strings.Replace(result["lng"], "lon:", "", -1),
				Heading:   strings.Replace(result["heading"], "dir:", "", -1),
				Speed:     speedMPHString,
				Lock:      strings.Replace(result["lock"], "lck:", "", -1),
				Time:      strings.Replace(result["time"], "time:", "", -1),
				Date:      strings.Replace(result["date"], "date:", "", -1),
				Status:    strings.Replace(result["status"], "trig:", "", -1),
				Created:   time.Now()}

			// convert updated time to local time
			loc, err := time.LoadLocation("America/New_York")
			if err != nil {
				log.Error(err.Error())
				continue
			}
			var currentVehicle Vehicle;
			findErr := App.Vehicles.Find(bson.M{"vehicleID":update.VehicleID}).One(&currentVehicle);
			_ = findErr //Error Handling!

			lastUpdate = time.Now().In(loc)

			//if a shuttle hasnt gone over 3 miles per hour in 5 minutes, it is probably inactive, and we shouldn't show it.
			spd, err := strconv.ParseFloat(update.Speed, 64)
			if err != nil {
				log.Errorf("error finding speed")
			}
			if spd < 3 {
				currentVehicle.ActiveStatus += 1

			} else {
			 	currentVehicle.ActiveStatus = 0
				currentVehicle.Active = true
			}
			c := mgo.Change{
				currentVehicle,
				true,
				false,
				true,
			}
			if currentVehicle.ActiveStatus > 20 {
				currentVehicle.Active = false;
			}
			changeInfo,findErr := App.Vehicles.Find(bson.M{"vehicleID":update.VehicleID}).Apply(c,&currentVehicle)
			_ = changeInfo

			if err := App.Updates.Insert(&update); err != nil {
				log.Errorf("error inserting vehicle update(%v): %v", update, err)
			} else {
				updated++
			}

			// here if parsing error, updated will be incremented, wait, the whole thing will crash, isn't it?
		}
		log.Infof("sucessfully updated %d/%d vehicles", updated, len(vehiclesData)-1)
	}
}

// VehiclesHandler finds all the vehicles in the database.
func (App *App) VehiclesHandler(w http.ResponseWriter, r *http.Request) {

	// Find all vehicles in database
	var vehicles []Vehicle
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle query errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Send each vehicle to client as JSON
	WriteJSON(w, vehicles)
}

// VehiclesCreateHandler adds a new vehicle to the database.
func (App *App) VehiclesCreateHandler(w http.ResponseWriter, r *http.Request) {
	if App.Config.Authenticate && !cas.IsAuthenticated(r) {
		return
	}

	// Create new vehicle object using request fields
	vehicle := Vehicle{}
	vehicle.Created = time.Now()
	vehicle.Updated = time.Now()
	vehicleData := json.NewDecoder(r.Body)
	err := vehicleData.Decode(&vehicle)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Store new vehicle under vehicles collection
	err = App.Vehicles.Insert(&vehicle)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (App *App) VehiclesEditHandler(w http.ResponseWriter, r *http.Request) {

}

func (App *App) VehiclesDeleteHandler(w http.ResponseWriter, r *http.Request) {
	if App.Config.Authenticate && !cas.IsAuthenticated(r) {
		return
	}

	// Delete vehicle from Vehicles collection
	vars := mux.Vars(r)
	log.Debugf("deleting", vars["id"])
	err := App.Vehicles.Remove(bson.M{"vehicleID": vars["id"]})
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// Here's my view, keep every name the same meaning, otherwise, choose another.
// UpdatesHandler get the most recent update for each vehicle in the vehicles collection.
func (App *App) UpdatesHandler(w http.ResponseWriter, r *http.Request) {
	// Store updates for each vehicle
	var vehicles []Vehicle
	var updates []VehicleUpdate
	var update VehicleUpdate
	// Query all Vehicles
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Find recent updates for each vehicle
	for _, vehicle := range vehicles {
		// here, huge waste of computational power, you record every shit inside the Updates table and using sort, I don't know what the hell is going on
		err := App.Updates.Find(bson.M{"vehicleID": vehicle.VehicleID}).Sort("-created").Limit(1).One(&update)

		if err == nil && vehicle.Active{
			updates = append(updates, update)
		}
	}
	// Convert updates to JSON
	WriteJSON(w, updates) // it's good to take some REST in our server :)
}

// UpdateMessageHandler generates a message about an update for a vehicle
func (App *App) UpdateMessageHandler(w http.ResponseWriter, r *http.Request) {
	// For each vehicle/update, store message as a string
	var messages []string
	var message string
	var vehicles []Vehicle
	var update VehicleUpdate

	// Query all Vehicles
	err := App.Vehicles.Find(bson.M{}).All(&vehicles)
	// Handle errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Find recent updates and generate message
	for _, vehicle := range vehicles {
		// find 10 most recent records
		err := App.Updates.Find(bson.M{"vehicleID": vehicle.VehicleID}).Sort("-created").Limit(1).One(&update)
		if err == nil {
			// Use first 4 char substring of update.Speed
			speed := update.Speed
			if len(speed) > 4 {
				speed = speed[0:4]
			}
			//nextArrival := GetArrivalTime(&update, App.Routes, App.Stops)
			message = fmt.Sprintf("%s
Traveling %s at
 %s mph as of %s", vehicle.VehicleName, CardinalDirection(&update.Heading), speed, lastUpdate.Format("3:04:05pm") /*, nextArrival*/)
			messages = append(messages, message)
		}
	}
	// Convert to JSON
	WriteJSON(w, messages)
}

// CardinalDirection figures out the cardinal direction of a vehicle's heading
func CardinalDirection(h *string) string {
	heading, err := strconv.ParseFloat(*h, 64)
	if err != nil {
		fmt.Println("ERROR", err.Error())
		return "North"
	}
	switch {
	case (heading >= 22.5 && heading < 67.5):
		return "North-East"
	case (heading >= 67.5 && heading < 112.5):
		return "East"
	case (heading >= 112.5 && heading < 157.5):
		return "South-East"
	case (heading >= 157.5 && heading < 202.5):
		return "South"
	case (heading >= 202.5 && heading < 247.5):
		return "South-West"
	case (heading >= 247.5 && heading < 292.5):
		return "West"
	case (heading >= 292.5 && heading < 337.5):
		return "North-West"
	default:
		return "North"
	}
}

// convert kmh to mph
func KPHtoMPH(kmh float64) (mph float64) {
	mph = kmh * 0.621371192
	return
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/byte_reader.go                                      *
 *                                                        *
 * byte reader for Go.                                    *
 *                                                        *
 * LastModified: Sep 1, 2016                              *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package io

import "io"

// ByteReader implements the io.Reader and io.ByteReader interfaces by reading
// from a byte slice
type ByteReader struct {
	buf []byte
	off int
}

// NewBytesReader is a constructor for ByteReader
func NewBytesReader(buf []byte) (reader *ByteReader) {
	reader = new(ByteReader)
	reader.buf = buf
	return
}

// ReadByte reads and returns a single byte. If no byte is available,
// it returns error io.EOF.
func (r *ByteReader) ReadByte() (byte, error) {
	if r.off >= len(r.buf) {
		return 0, io.EOF
	}
	return r.readByte(), nil
}

func (r *ByteReader) readByte() (b byte) {
	b = r.buf[r.off]
	r.off++
	return
}

// Read reads the next len(b) bytes from the buffer or until the buffer is
// drained. The return value n is the number of bytes read. If the buffer has
// no data, err is io.EOF (unless len(b) is zero); otherwise it is nil.
func (r *ByteReader) Read(b []byte) (n int, err error) {
	if len(b) == 0 {
		return 0, nil
	}
	if r.off >= len(r.buf) {
		return 0, io.EOF
	}
	n = copy(b, r.buf[r.off:])
	r.off += n
	return
}

// Next returns a slice containing the next n bytes from the buffer,
// advancing the buffer as if the bytes had been returned by Read.
// If there are fewer than n bytes, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
func (r *ByteReader) Next(n int) (data []byte) {
	p := r.off + n
	if p > len(r.buf) {
		p = len(r.buf)
	}
	data = r.buf[r.off:p]
	r.off = p
	return
}
<commit_msg>Added UnreadByte & Unread method<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/byte_reader.go                                      *
 *                                                        *
 * byte reader for Go.                                    *
 *                                                        *
 * LastModified: Sep 2, 2016                              *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package io

import "io"

// ByteReader implements the io.Reader and io.ByteReader interfaces by reading
// from a byte slice
type ByteReader struct {
	buf []byte
	off int
}

// NewBytesReader is a constructor for ByteReader
func NewBytesReader(buf []byte) (reader *ByteReader) {
	reader = new(ByteReader)
	reader.buf = buf
	return
}

// ReadByte reads and returns a single byte. If no byte is available,
// it returns error io.EOF.
func (r *ByteReader) ReadByte() (byte, error) {
	if r.off >= len(r.buf) {
		return 0, io.EOF
	}
	return r.readByte(), nil
}

func (r *ByteReader) readByte() (b byte) {
	b = r.buf[r.off]
	r.off++
	return
}

// UnreadByte unreads 1 byte from the current position.
func (r *ByteReader) UnreadByte() error {
	if r.off > 0 {
		r.off--
	}
	return nil
}

func (r *ByteReader) unreadByte() {
	if r.off > 0 {
		r.off--
	}
}

// Unread n bytes from the current position.
func (r *ByteReader) Unread(n int) {
	if r.off >= n {
		r.off -= n
	} else {
		r.off = 0
	}
}

// Read reads the next len(b) bytes from the buffer or until the buffer is
// drained. The return value n is the number of bytes read. If the buffer has
// no data, err is io.EOF (unless len(b) is zero); otherwise it is nil.
func (r *ByteReader) Read(b []byte) (n int, err error) {
	if len(b) == 0 {
		return 0, nil
	}
	if r.off >= len(r.buf) {
		return 0, io.EOF
	}
	n = copy(b, r.buf[r.off:])
	r.off += n
	return
}

// Next returns a slice containing the next n bytes from the buffer,
// advancing the buffer as if the bytes had been returned by Read.
// If there are fewer than n bytes, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
func (r *ByteReader) Next(n int) (data []byte) {
	p := r.off + n
	if p > len(r.buf) {
		p = len(r.buf)
	}
	data = r.buf[r.off:p]
	r.off = p
	return
}
<|endoftext|>