<commit_before>package pipoint

import (
	common "gobot.io/x/gobot/platforms/mavlink/common"
)

// Geographic coordinates.
type Position struct {
	Time    float64
	Lat     float64
	Lon     float64
	Alt     float64
	Heading float64
}

// Orientation of a body.
type Attitude struct {
	Roll  float64
	Pitch float64
	Yaw   float64
}

type State interface {
	Update(param *Param)
}

// An automatic, GPS based system that points a camera at the rover.
type PiPoint struct {
	Params *Params

	state *Param

	tick       *Param
	heartbeats *Param
	heartbeat  *Param
	attitude   *Param
	gps        *Param
	pred       *Param
	rover      *Param
	base       *Param
	sysStatus  *Param

	sp     *Param
	offset *Param

	pan  *Servo
	tilt *Servo

	cycle  float64
	states []State
}

// Create a new camera pointer.
func NewPiPoint() *PiPoint {
	p := &PiPoint{
		Params: NewParams("pipoint"),
	}

	p.states = []State{
		&LocateState{pi: p},
		&RunState{pi: p},
		&CycleState{pi: p},
	}

	p.tick = p.Params.New("tick")

	p.state = p.Params.NewWith("state", 0)
	p.heartbeat = p.Params.NewWith("heartbeat", &common.Heartbeat{})
	p.heartbeats = p.Params.New("heartbeat")

	p.gps = p.Params.New("gps.position")
	p.pred = p.Params.New("pred.position")

	p.attitude = p.Params.New("rover.attitude")
	p.rover = p.Params.New("rover.position")
	p.base = p.Params.New("base.position")

	p.sysStatus = p.Params.New("rover.status")

	p.sp = p.Params.NewWith("pantilt.sp", &Attitude{})
	p.offset = p.Params.NewWith("pantilt.offset", &Attitude{})

	p.pan = NewServo("pantilt.pan", p.Params)
	p.tilt = NewServo("pantilt.tilt", p.Params)

	p.Params.Listen(p.update)
	p.Params.Load()
	return p
}

func (p *PiPoint) Tick() {
	p.tick.SetFloat64(Now())
	p.pan.Tick()
	p.tilt.Tick()
}

func (p *PiPoint) check(code int, cond bool) bool {
	return !cond
}

func (p *PiPoint) update(param *Param) {
	state := p.state.GetInt()

	if state >= 0 && state < len(p.states) {
		p.states[state].Update(param)
	}
}

// Dispatch a MAVLink message.
func (p *PiPoint) Message(msg interface{}) {
	switch msg.(type) {
	case *common.Heartbeat:
		p.heartbeats.Inc()
		p.heartbeat.Set(msg.(*common.Heartbeat))
	case *common.SysStatus:
		p.sysStatus.Set(msg.(*common.SysStatus))
	case *common.GlobalPositionInt:
		gps := msg.(*common.GlobalPositionInt)
		p.gps.Set(&Position{
			Time:    float64(gps.TIME_BOOT_MS) * 1e-3,
			Lat:     float64(gps.LAT) * 1e-7,
			Lon:     float64(gps.LON) * 1e-7,
			Alt:     float64(gps.ALT) * 1e-3,
			Heading: float64(gps.HDG) * 1e-2,
		})
	case *common.Attitude:
		att := msg.(*common.Attitude)
		p.attitude.Set(&Attitude{
			float64(att.ROLL),
			float64(att.PITCH),
			float64(att.YAW),
		})
	default:
	}
}
<commit_msg>pipoint: add GPS prediction.  Add logging of all param changes.<commit_after>package pipoint

import (
	"log"

	common "gobot.io/x/gobot/platforms/mavlink/common"
)

// Geographic coordinates.
type Position struct {
	Time    float64
	Lat     float64
	Lon     float64
	Alt     float64
	Heading float64
}

// Orientation of a body.
type Attitude struct {
	Roll  float64
	Pitch float64
	Yaw   float64
}

type State interface {
	Update(param *Param)
}

// An automatic, GPS based system that points a camera at the rover.
type PiPoint struct {
	Params *Params

	state *Param

	tick       *Param
	heartbeats *Param
	heartbeat  *Param
	attitude   *Param
	gps        *Param
	pred       *Param
	rover      *Param
	base       *Param
	sysStatus  *Param

	sp     *Param
	offset *Param

	pan  *Servo
	tilt *Servo

	latPred *LinPred
	lonPred *LinPred
	altPred *LinPred

	cycle  float64
	states []State

	elog *EventLogger
	log *log.Logger
}

// Create a new camera pointer.
func NewPiPoint() *PiPoint {
	p := &PiPoint{
		Params: NewParams("pipoint"),
		latPred: &LinPred{},
		lonPred: &LinPred{},
		altPred: &LinPred{},
		elog: NewEventLogger("pipoint"),
	}

	p.log = p.elog.logger

	p.states = []State{
		&LocateState{pi: p},
		&RunState{pi: p},
		&CycleState{pi: p},
	}

	p.tick = p.Params.New("tick")

	p.state = p.Params.NewWith("state", 0)
	p.heartbeat = p.Params.NewWith("heartbeat", &common.Heartbeat{})
	p.heartbeats = p.Params.New("heartbeat")

	p.gps = p.Params.New("gps.position")
	p.pred = p.Params.New("pred.position")

	p.attitude = p.Params.New("rover.attitude")
	p.rover = p.Params.New("rover.position")
	p.base = p.Params.New("base.position")

	p.sysStatus = p.Params.New("rover.status")

	p.sp = p.Params.NewWith("pantilt.sp", &Attitude{})
	p.offset = p.Params.NewWith("pantilt.offset", &Attitude{})

	p.pan = NewServo("pantilt.pan", p.Params)
	p.tilt = NewServo("pantilt.tilt", p.Params)

	p.Params.Listen(p.update)
	p.Params.Load()
	return p
}

func (pi *PiPoint) Tick() {
	now := Now()
	pi.tick.SetFloat64(now)

	pred := &Position{
		Time: now,
		Lat: pi.latPred.GetEx(now),
		Lon: pi.lonPred.GetEx(now),
		Alt: pi.altPred.GetEx(now),
	}

	pi.pred.Set(pred)

	pi.pan.Tick()
	pi.tilt.Tick()
}

func (p *PiPoint) check(code int, cond bool) bool {
	return !cond
}

func (pi *PiPoint) predict(gps *Position) {
	now := Now()

	pi.latPred.SetEx(gps.Lat, now)
	pi.lonPred.SetEx(gps.Lon, now)
	pi.altPred.SetEx(gps.Alt, now)
}

func (p *PiPoint) update(param *Param) {
	switch param {
	case p.gps:
		if param.Ok() {
			p.predict(param.Get().(*Position))
		}
	}

	state := p.state.GetInt()

	if state >= 0 && state < len(p.states) {
		p.states[state].Update(param)
	}

	p.log.Printf("%s %T %#v\n", param.name, param.Get(), param.Get())
}

// Dispatch a MAVLink message.
func (p *PiPoint) Message(msg interface{}) {
	switch msg.(type) {
	case *common.Heartbeat:
		p.heartbeats.Inc()
		p.heartbeat.Set(msg.(*common.Heartbeat))
	case *common.SysStatus:
		p.sysStatus.Set(msg.(*common.SysStatus))
	case *common.GlobalPositionInt:
		gps := msg.(*common.GlobalPositionInt)
		p.gps.Set(&Position{
			Time:    float64(gps.TIME_BOOT_MS) * 1e-3,
			Lat:     float64(gps.LAT) * 1e-7,
			Lon:     float64(gps.LON) * 1e-7,
			Alt:     float64(gps.ALT) * 1e-3,
			Heading: float64(gps.HDG) * 1e-2,
		})
	case *common.Attitude:
		att := msg.(*common.Attitude)
		p.attitude.Set(&Attitude{
			float64(att.ROLL),
			float64(att.PITCH),
			float64(att.YAW),
		})
	default:
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016 Joseph Wright <rjosephwright@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package lib

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/kms"
	"github.com/aws/aws-sdk-go/service/s3"
)

const CiphertextLength = 204

type BossVaultClient struct {
	kms *kmsClient
	s3  *s3Client
}

func NewBossVaultClient() *BossVaultClient {
	s := session.New()
	return &BossVaultClient{
		kms: &kmsClient{kms.New(s)},
		s3:  &s3Client{s3.New(s)},
	}
}

func (c *BossVaultClient) EncryptAndStore(bucket, artifact, content string) error {
	namespace, err := nsFrom(artifact)
	if err != nil {
		return err
	}

	plaintext, err := contentBytes(content)
	if err != nil {
		return err
	}

	keyId, err := c.kms.keyIdForAlias(namespace)
	if err != nil {
		return err
	}

	dk, err := c.kms.dataKey(keyId)
	if err != nil {
		return err
	}

	encrypted, err := encrypt(plaintext, dk.Plaintext)
	if err != nil {
		return err
	}

	return c.s3.store(artifact, bucket, encrypted, dk.CiphertextBlob)
}

func (c *BossVaultClient) RetrieveAndDecrypt(bucket, artifact string) ([]byte, error) {
	obj, err := c.s3.GetObject(
		&s3.GetObjectInput{
			Bucket: &bucket,
			Key:    &artifact,
		},
	)
	if err != nil {
		return nil, err
	}

	content, err := ioutil.ReadAll(obj.Body)
	if err != nil {
		return nil, err
	}

	encryptedKey := content[:CiphertextLength]
	payload := content[CiphertextLength:]

	dk, err := c.kms.Decrypt(
		&kms.DecryptInput{
			CiphertextBlob: encryptedKey,
		},
	)
	if err != nil {
		return nil, err
	}

	decrypted, err := decrypt(payload, dk.Plaintext)
	if err != nil {
		return nil, err
	}

	return decrypted, nil
}

type kmsClient struct {
	*kms.KMS
}

type s3Client struct {
	*s3.S3
}

func (kc *kmsClient) dataKey(keyId string) (out *kms.GenerateDataKeyOutput, err error) {
	keySpec := "AES_256"
	out, err = kc.GenerateDataKey(&kms.GenerateDataKeyInput{
		KeyId:   &keyId,
		KeySpec: &keySpec,
	})
	if err != nil {
		return
	}
	return
}

func (kc *kmsClient) keyIdForAlias(alias string) (string, error) {
	var keyId string
	var err error

	aliases := []*kms.AliasListEntry{}
	err = kc.ListAliasesPages(
		&kms.ListAliasesInput{},
		func(out *kms.ListAliasesOutput, lastPage bool) bool {
			aliases = append(aliases, out.Aliases...)
			return lastPage
		},
	)
	if err != nil {
		return keyId, err
	}

	fullAlias := fmt.Sprintf("alias/%s", alias)
	for _, a := range aliases {
		if *a.AliasName == fullAlias {
			keyId = *a.TargetKeyId
			break
		}
	}
	if keyId == "" {
		err = fmt.Errorf("No master key found with alias %s", alias)
	}

	return keyId, err
}

func (sc *s3Client) store(artifact, bucket string, encrypted, encryptedKey []byte) error {
	sse := "aws:kms"
	key := fmt.Sprintf("%s.enc", artifact)
	payload := append(encryptedKey, encrypted...)
	body := bytes.NewReader(payload)
	_, err := sc.PutObject(
		&s3.PutObjectInput{
			Bucket:               &bucket,
			Key:                  &key,
			Body:                 body,
			ServerSideEncryption: &sse,
		},
	)
	return err
}

func randomBytes(n int) ([]byte, error) {
	buf := make([]byte, n)
	if _, err := io.ReadFull(rand.Reader, buf); err != nil {
		return nil, err
	}
	return buf, nil
}

func contentBytes(content string) ([]byte, error) {
	var buf []byte
	var err error
	parts := strings.Split(content, "@")
	if len(parts) > 1 && parts[0] == "" && len(parts[1]) > 0 {
		path := parts[1]
		if file, err := os.Open(path); err != nil {
			return nil, err
		} else {
			defer file.Close()
			if buf, err = ioutil.ReadAll(file); err != nil {
				return nil, err
			}
		}
	} else {
		buf = []byte(content)
	}
	return buf, err
}

func nsFrom(artifact string) (ns string, err error) {
	parts := strings.Split(artifact, "/")
	if len(parts) == 1 {
		err = fmt.Errorf("Invalid artifact name")
	} else {
		ns = parts[0]
	}
	return ns, err
}

func encrypt(plaintext, key []byte) ([]byte, error) {
	var block cipher.Block
	var err error
	var iv []byte

	if block, err = aes.NewCipher(key); err != nil {
		return nil, err
	}

	if iv, err = randomBytes(aes.BlockSize); err != nil {
		return nil, err
	}

	ciphertext := make([]byte, len(plaintext))
	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(ciphertext, plaintext)

	return append(iv, ciphertext...), nil
}

func decrypt(ciphertext, key []byte) ([]byte, error) {
	iv := ciphertext[:aes.BlockSize]
	payload := ciphertext[aes.BlockSize:]
	decrypted := make([]byte, len(payload))

	if block, err := aes.NewCipher(key); err != nil {
		return nil, err
	} else {
		cfb := cipher.NewCFBDecrypter(block, iv)
		cfb.XORKeyStream(decrypted, payload)
	}

	return decrypted, nil
}
<commit_msg>Remove suffix from stored artifacts<commit_after>// Copyright © 2016 Joseph Wright <rjosephwright@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package lib

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/kms"
	"github.com/aws/aws-sdk-go/service/s3"
)

const CiphertextLength = 204

type BossVaultClient struct {
	kms *kmsClient
	s3  *s3Client
}

func NewBossVaultClient() *BossVaultClient {
	s := session.New()
	return &BossVaultClient{
		kms: &kmsClient{kms.New(s)},
		s3:  &s3Client{s3.New(s)},
	}
}

func (c *BossVaultClient) EncryptAndStore(bucket, artifact, content string) error {
	namespace, err := nsFrom(artifact)
	if err != nil {
		return err
	}

	plaintext, err := contentBytes(content)
	if err != nil {
		return err
	}

	keyId, err := c.kms.keyIdForAlias(namespace)
	if err != nil {
		return err
	}

	dk, err := c.kms.dataKey(keyId)
	if err != nil {
		return err
	}

	encrypted, err := encrypt(plaintext, dk.Plaintext)
	if err != nil {
		return err
	}

	return c.s3.store(artifact, bucket, encrypted, dk.CiphertextBlob)
}

func (c *BossVaultClient) RetrieveAndDecrypt(bucket, artifact string) ([]byte, error) {
	obj, err := c.s3.GetObject(
		&s3.GetObjectInput{
			Bucket: &bucket,
			Key:    &artifact,
		},
	)
	if err != nil {
		return nil, err
	}

	content, err := ioutil.ReadAll(obj.Body)
	if err != nil {
		return nil, err
	}

	encryptedKey := content[:CiphertextLength]
	payload := content[CiphertextLength:]

	dk, err := c.kms.Decrypt(
		&kms.DecryptInput{
			CiphertextBlob: encryptedKey,
		},
	)
	if err != nil {
		return nil, err
	}

	decrypted, err := decrypt(payload, dk.Plaintext)
	if err != nil {
		return nil, err
	}

	return decrypted, nil
}

type kmsClient struct {
	*kms.KMS
}

type s3Client struct {
	*s3.S3
}

func (kc *kmsClient) dataKey(keyId string) (out *kms.GenerateDataKeyOutput, err error) {
	keySpec := "AES_256"
	out, err = kc.GenerateDataKey(&kms.GenerateDataKeyInput{
		KeyId:   &keyId,
		KeySpec: &keySpec,
	})
	if err != nil {
		return
	}
	return
}

func (kc *kmsClient) keyIdForAlias(alias string) (string, error) {
	var keyId string
	var err error

	aliases := []*kms.AliasListEntry{}
	err = kc.ListAliasesPages(
		&kms.ListAliasesInput{},
		func(out *kms.ListAliasesOutput, lastPage bool) bool {
			aliases = append(aliases, out.Aliases...)
			return lastPage
		},
	)
	if err != nil {
		return keyId, err
	}

	fullAlias := fmt.Sprintf("alias/%s", alias)
	for _, a := range aliases {
		if *a.AliasName == fullAlias {
			keyId = *a.TargetKeyId
			break
		}
	}
	if keyId == "" {
		err = fmt.Errorf("No master key found with alias %s", alias)
	}

	return keyId, err
}

func (sc *s3Client) store(artifact, bucket string, encrypted, encryptedKey []byte) error {
	sse := "aws:kms"
	payload := append(encryptedKey, encrypted...)
	body := bytes.NewReader(payload)
	_, err := sc.PutObject(
		&s3.PutObjectInput{
			Bucket:               &bucket,
			Key:                  &artifact,
			Body:                 body,
			ServerSideEncryption: &sse,
		},
	)
	return err
}

func randomBytes(n int) ([]byte, error) {
	buf := make([]byte, n)
	if _, err := io.ReadFull(rand.Reader, buf); err != nil {
		return nil, err
	}
	return buf, nil
}

func contentBytes(content string) ([]byte, error) {
	var buf []byte
	var err error
	parts := strings.Split(content, "@")
	if len(parts) > 1 && parts[0] == "" && len(parts[1]) > 0 {
		path := parts[1]
		if file, err := os.Open(path); err != nil {
			return nil, err
		} else {
			defer file.Close()
			if buf, err = ioutil.ReadAll(file); err != nil {
				return nil, err
			}
		}
	} else {
		buf = []byte(content)
	}
	return buf, err
}

func nsFrom(artifact string) (ns string, err error) {
	parts := strings.Split(artifact, "/")
	if len(parts) == 1 {
		err = fmt.Errorf("Invalid artifact name")
	} else {
		ns = parts[0]
	}
	return ns, err
}

func encrypt(plaintext, key []byte) ([]byte, error) {
	var block cipher.Block
	var err error
	var iv []byte

	if block, err = aes.NewCipher(key); err != nil {
		return nil, err
	}

	if iv, err = randomBytes(aes.BlockSize); err != nil {
		return nil, err
	}

	ciphertext := make([]byte, len(plaintext))
	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(ciphertext, plaintext)

	return append(iv, ciphertext...), nil
}

func decrypt(ciphertext, key []byte) ([]byte, error) {
	iv := ciphertext[:aes.BlockSize]
	payload := ciphertext[aes.BlockSize:]
	decrypted := make([]byte, len(payload))

	if block, err := aes.NewCipher(key); err != nil {
		return nil, err
	} else {
		cfb := cipher.NewCFBDecrypter(block, iv)
		cfb.XORKeyStream(decrypted, payload)
	}

	return decrypted, nil
}
<|endoftext|>


<commit_before>package types

import (
    "testing"
)

func TestLookDegrees_ToLookBytes(t *testing.T) {
    type Test struct {
        input    LookDegrees
        expected LookBytes
    }

    var tests = []Test{
        {LookDegrees{0, 0}, LookBytes{0, 0}},
        {LookDegrees{0, 90}, LookBytes{0, 64}},
        {LookDegrees{0, 180}, LookBytes{0, 128}},
        {LookDegrees{0, -90}, LookBytes{0, 192}},
        {LookDegrees{0, 270}, LookBytes{0, 192}},
        {LookDegrees{90, 0}, LookBytes{64, 0}},
        {LookDegrees{180, 0}, LookBytes{128, 0}},
        {LookDegrees{-90, 0}, LookBytes{192, 0}},
        {LookDegrees{270, 0}, LookBytes{192, 0}},
    }

    for _, r := range tests {
        result := r.input.ToLookBytes()
        if r.expected.Yaw != result.Yaw || r.expected.Pitch != result.Pitch {
            t.Errorf("LookDegrees%v expected LookBytes%v got LookBytes%v",
                r.input, r.expected, result)
        }
    }
}

func TestAbsXYZ_ToBlockXYZ(t *testing.T) {
    type Test struct {
        pos AbsXYZ
        exp BlockXYZ
    }

    var tests = []Test{
        // Simple positive tests
        {AbsXYZ{0.0, 0.0, 0.0}, BlockXYZ{0, 0, 0}},
        {AbsXYZ{0.1, 0.2, 0.3}, BlockXYZ{0, 0, 0}},
        {AbsXYZ{1.0, 2.0, 3.0}, BlockXYZ{1, 2, 3}},

        // Negative tests
        {AbsXYZ{-0.1, -0.2, -0.3}, BlockXYZ{-1, -1, -1}},
        {AbsXYZ{-1.0, -2.0, -3.0}, BlockXYZ{-1, -2, -3}},
        {AbsXYZ{-1.5, -2.5, -3.5}, BlockXYZ{-2, -3, -4}},
    }

    for _, r := range tests {
        result := r.pos.ToBlockXYZ()
        if r.exp.X != result.X || r.exp.Y != result.Y || r.exp.Z != result.Z {
            t.Errorf("AbsXYZ%v.ToBlockXYZ() expected BlockXYZ%v got BlockXYZ%v",
                r.pos, r.exp, result)
        }
    }
}

func TestAbsIntXYZ_ToChunkXZ(t *testing.T) {
    type Test struct {
        input    AbsIntXYZ
        expected ChunkXZ
    }

    var tests = []Test{
        {AbsIntXYZ{0, 0, 0}, ChunkXZ{0, 0}},
        {AbsIntXYZ{8 * 32, 0, 8 * 32}, ChunkXZ{0, 0}},
        {AbsIntXYZ{15 * 32, 0, 15 * 32}, ChunkXZ{0, 0}},
        {AbsIntXYZ{16 * 32, 0, 16 * 32}, ChunkXZ{1, 1}},
        {AbsIntXYZ{31*32 + 31, 0, 31*32 + 31}, ChunkXZ{1, 1}},
        {AbsIntXYZ{32 * 32, 0, 32 * 32}, ChunkXZ{2, 2}},
        {AbsIntXYZ{0, 0, 32 * 32}, ChunkXZ{0, 2}},
        {AbsIntXYZ{0, 0, -16 * 32}, ChunkXZ{0, -1}},
        {AbsIntXYZ{0, 0, -1 * 32}, ChunkXZ{0, -1}},
        {AbsIntXYZ{0, 0, -1}, ChunkXZ{0, -1}},
    }

    for _, r := range tests {
        result := r.input.ToChunkXZ()
        if r.expected.X != result.X || r.expected.Z != result.Z {
            t.Errorf("AbsIntXYZ%v expected ChunkXZ%v got ChunkXZ%v",
                r.input, r.expected, result)
        }
    }
}

func TestCoordDivMod(t *testing.T) {
    type CoordDivModTest struct {
        expected_div, expected_mod int32
        num, denom                 int32
    }

    var CoordDivModTests = []CoordDivModTest{
        // Simple +ve numerator cases
        CoordDivModTest{0, 0, 0, 16},
        CoordDivModTest{0, 1, 1, 16},
        CoordDivModTest{0, 15, 15, 16},
        CoordDivModTest{1, 0, 16, 16},
        CoordDivModTest{1, 15, 31, 16},

        // -ve numerator cases
        CoordDivModTest{-1, 15, -1, 16},
        CoordDivModTest{-1, 0, -16, 16},
        CoordDivModTest{-2, 15, -17, 16},
        CoordDivModTest{-2, 0, -32, 16},
    }

    for _, r := range CoordDivModTests {
        div, mod := coordDivMod(r.num, r.denom)
        if r.expected_div != div || r.expected_mod != mod {
            t.Errorf("coordDivMod(%d, %d) expected (%d, %d) got (%d, %d)",
                r.num, r.denom, r.expected_div, r.expected_mod, div, mod)
        }
    }
}

func TestChunkXZ_GetChunkCornerBlockXY(t *testing.T) {
    type Test struct {
        input    ChunkXZ
        expected BlockXYZ
    }

    var tests = []Test{
        {ChunkXZ{0, 0}, BlockXYZ{0, 0, 0}},
        {ChunkXZ{0, 1}, BlockXYZ{0, 0, 16}},
        {ChunkXZ{1, 0}, BlockXYZ{16, 0, 0}},
        {ChunkXZ{0, -1}, BlockXYZ{0, 0, -16}},
        {ChunkXZ{-1, 0}, BlockXYZ{-16, 0, 0}},
    }

    for _, r := range tests {
        result := r.input.GetChunkCornerBlockXY()
        if r.expected.X != result.X || r.expected.Y != result.Y || r.expected.Z != result.Z {
            t.Errorf("ChunkXZ%v expected BlockXYZ%v got BlockXYZ%v",
                r.input, r.expected, result)
        }
    }
}

func TestBlockXYZ_ToAbsIntXYZ(t *testing.T) {
    type Test struct {
        input    BlockXYZ
        expected AbsIntXYZ
    }

    var tests = []Test{
        {BlockXYZ{0, 0, 0}, AbsIntXYZ{0, 0, 0}},
        {BlockXYZ{0, 0, 1}, AbsIntXYZ{0, 0, 32}},
        {BlockXYZ{0, 0, -1}, AbsIntXYZ{0, 0, -32}},
        {BlockXYZ{1, 0, 0}, AbsIntXYZ{32, 0, 0}},
        {BlockXYZ{-1, 0, 0}, AbsIntXYZ{-32, 0, 0}},
        {BlockXYZ{0, 1, 0}, AbsIntXYZ{0, 32, 0}},
        {BlockXYZ{0, 10, 0}, AbsIntXYZ{0, 320, 0}},
        {BlockXYZ{0, 63, 0}, AbsIntXYZ{0, 2016, 0}},
        {BlockXYZ{0, 64, 0}, AbsIntXYZ{0, 2048, 0}},
    }

    for _, r := range tests {
        result := r.input.ToAbsIntXYZ()
        if r.expected.X != result.X || r.expected.Y != result.Y || r.expected.Z != result.Z {
            t.Errorf("BlockXYZ%v expected AbsIntXYZ%v got AbsIntXYZ%v",
                r.input, r.expected, result)
        }
    }
}
<commit_msg>Added test for ChunkXZ.ChunkKey().<commit_after>package types

import (
    "testing"
)

func TestLookDegrees_ToLookBytes(t *testing.T) {
    type Test struct {
        input    LookDegrees
        expected LookBytes
    }

    var tests = []Test{
        {LookDegrees{0, 0}, LookBytes{0, 0}},
        {LookDegrees{0, 90}, LookBytes{0, 64}},
        {LookDegrees{0, 180}, LookBytes{0, 128}},
        {LookDegrees{0, -90}, LookBytes{0, 192}},
        {LookDegrees{0, 270}, LookBytes{0, 192}},
        {LookDegrees{90, 0}, LookBytes{64, 0}},
        {LookDegrees{180, 0}, LookBytes{128, 0}},
        {LookDegrees{-90, 0}, LookBytes{192, 0}},
        {LookDegrees{270, 0}, LookBytes{192, 0}},
    }

    for _, r := range tests {
        result := r.input.ToLookBytes()
        if r.expected.Yaw != result.Yaw || r.expected.Pitch != result.Pitch {
            t.Errorf("LookDegrees%v expected LookBytes%v got LookBytes%v",
                r.input, r.expected, result)
        }
    }
}

func TestAbsXYZ_UpdateChunkXZ(t *testing.T) {
    type Test struct {
        input    AbsXYZ
        expected ChunkXZ
    }
    var tests = []Test{
        {AbsXYZ{0, 0, 0}, ChunkXZ{0, 0}},
        {AbsXYZ{0, 0, 16}, ChunkXZ{0, 1}},
        {AbsXYZ{16, 0, 0}, ChunkXZ{1, 0}},
        {AbsXYZ{0, 0, -16}, ChunkXZ{0, -1}},
        {AbsXYZ{-16, 0, 0}, ChunkXZ{-1, 0}},
        {AbsXYZ{-1, 0, -1}, ChunkXZ{-1, -1}},
    }

    for _, test := range tests {
        input, expected := test.input, test.expected
        var result ChunkXZ
        input.UpdateChunkXZ(&result)
        if expected.X != result.X || expected.Z != result.Z {
            t.Errorf("AbsXYZ%+v.UpdateChunkXZ() expected ChunkXZ%+v got ChunkXZ%+v",
                input, expected, result)
        }
    }
}

func TestAbsXYZ_ToBlockXYZ(t *testing.T) {
    type Test struct {
        pos AbsXYZ
        exp BlockXYZ
    }

    var tests = []Test{
        // Simple positive tests
        {AbsXYZ{0.0, 0.0, 0.0}, BlockXYZ{0, 0, 0}},
        {AbsXYZ{0.1, 0.2, 0.3}, BlockXYZ{0, 0, 0}},
        {AbsXYZ{1.0, 2.0, 3.0}, BlockXYZ{1, 2, 3}},

        // Negative tests
        {AbsXYZ{-0.1, -0.2, -0.3}, BlockXYZ{-1, -1, -1}},
        {AbsXYZ{-1.0, -2.0, -3.0}, BlockXYZ{-1, -2, -3}},
        {AbsXYZ{-1.5, -2.5, -3.5}, BlockXYZ{-2, -3, -4}},
    }

    for _, r := range tests {
        result := r.pos.ToBlockXYZ()
        if r.exp.X != result.X || r.exp.Y != result.Y || r.exp.Z != result.Z {
            t.Errorf("AbsXYZ%v.ToBlockXYZ() expected BlockXYZ%v got BlockXYZ%v",
                r.pos, r.exp, result)
        }
    }
}

func TestAbsIntXYZ_ToChunkXZ(t *testing.T) {
    type Test struct {
        input    AbsIntXYZ
        expected ChunkXZ
    }

    var tests = []Test{
        {AbsIntXYZ{0, 0, 0}, ChunkXZ{0, 0}},
        {AbsIntXYZ{8 * 32, 0, 8 * 32}, ChunkXZ{0, 0}},
        {AbsIntXYZ{15 * 32, 0, 15 * 32}, ChunkXZ{0, 0}},
        {AbsIntXYZ{16 * 32, 0, 16 * 32}, ChunkXZ{1, 1}},
        {AbsIntXYZ{31*32 + 31, 0, 31*32 + 31}, ChunkXZ{1, 1}},
        {AbsIntXYZ{32 * 32, 0, 32 * 32}, ChunkXZ{2, 2}},
        {AbsIntXYZ{0, 0, 32 * 32}, ChunkXZ{0, 2}},
        {AbsIntXYZ{0, 0, -16 * 32}, ChunkXZ{0, -1}},
        {AbsIntXYZ{0, 0, -1 * 32}, ChunkXZ{0, -1}},
        {AbsIntXYZ{0, 0, -1}, ChunkXZ{0, -1}},
    }

    for _, r := range tests {
        result := r.input.ToChunkXZ()
        if r.expected.X != result.X || r.expected.Z != result.Z {
            t.Errorf("AbsIntXYZ%v expected ChunkXZ%v got ChunkXZ%v",
                r.input, r.expected, result)
        }
    }
}

func TestCoordDivMod(t *testing.T) {
    type CoordDivModTest struct {
        expected_div, expected_mod int32
        num, denom                 int32
    }

    var CoordDivModTests = []CoordDivModTest{
        // Simple +ve numerator cases
        CoordDivModTest{0, 0, 0, 16},
        CoordDivModTest{0, 1, 1, 16},
        CoordDivModTest{0, 15, 15, 16},
        CoordDivModTest{1, 0, 16, 16},
        CoordDivModTest{1, 15, 31, 16},

        // -ve numerator cases
        CoordDivModTest{-1, 15, -1, 16},
        CoordDivModTest{-1, 0, -16, 16},
        CoordDivModTest{-2, 15, -17, 16},
        CoordDivModTest{-2, 0, -32, 16},
    }

    for _, r := range CoordDivModTests {
        div, mod := coordDivMod(r.num, r.denom)
        if r.expected_div != div || r.expected_mod != mod {
            t.Errorf("coordDivMod(%d, %d) expected (%d, %d) got (%d, %d)",
                r.num, r.denom, r.expected_div, r.expected_mod, div, mod)
        }
    }
}

func TestChunkXZ_GetChunkCornerBlockXY(t *testing.T) {
    type Test struct {
        input    ChunkXZ
        expected BlockXYZ
    }

    var tests = []Test{
        {ChunkXZ{0, 0}, BlockXYZ{0, 0, 0}},
        {ChunkXZ{0, 1}, BlockXYZ{0, 0, 16}},
        {ChunkXZ{1, 0}, BlockXYZ{16, 0, 0}},
        {ChunkXZ{0, -1}, BlockXYZ{0, 0, -16}},
        {ChunkXZ{-1, 0}, BlockXYZ{-16, 0, 0}},
    }

    for _, r := range tests {
        result := r.input.GetChunkCornerBlockXY()
        if r.expected.X != result.X || r.expected.Y != result.Y || r.expected.Z != result.Z {
            t.Errorf("ChunkXZ%v expected BlockXYZ%v got BlockXYZ%v",
                r.input, r.expected, result)
        }
    }
}

func TestChunkXZ_ChunkKey(t *testing.T) {
    type Test struct {
        input    ChunkXZ
        expected uint64
    }

    var tests = []Test{
        {ChunkXZ{0, 0}, 0},
        {ChunkXZ{0, 1}, 0x0000000000000001},
        {ChunkXZ{1, 0}, 0x0000000100000000},
        {ChunkXZ{0, -1}, 0x00000000ffffffff},
        {ChunkXZ{-1, 0}, 0xffffffff00000000},
        {ChunkXZ{0, 10}, 0x000000000000000a},
        {ChunkXZ{10, 0}, 0x0000000a00000000},
        {ChunkXZ{10, 11}, 0x0000000a0000000b},
    }

    for _, r := range tests {
        result := r.input.ChunkKey()
        if r.expected != result {
            t.Errorf("ChunkXZ%+v.ChunkKey() expected %d got %d",
                r.input, r.expected, result)
        }
    }
}

func TestBlockXYZ_ToAbsIntXYZ(t *testing.T) {
    type Test struct {
        input    BlockXYZ
        expected AbsIntXYZ
    }

    var tests = []Test{
        {BlockXYZ{0, 0, 0}, AbsIntXYZ{0, 0, 0}},
        {BlockXYZ{0, 0, 1}, AbsIntXYZ{0, 0, 32}},
        {BlockXYZ{0, 0, -1}, AbsIntXYZ{0, 0, -32}},
        {BlockXYZ{1, 0, 0}, AbsIntXYZ{32, 0, 0}},
        {BlockXYZ{-1, 0, 0}, AbsIntXYZ{-32, 0, 0}},
        {BlockXYZ{0, 1, 0}, AbsIntXYZ{0, 32, 0}},
        {BlockXYZ{0, 10, 0}, AbsIntXYZ{0, 320, 0}},
        {BlockXYZ{0, 63, 0}, AbsIntXYZ{0, 2016, 0}},
        {BlockXYZ{0, 64, 0}, AbsIntXYZ{0, 2048, 0}},
    }

    for _, r := range tests {
        result := r.input.ToAbsIntXYZ()
        if r.expected.X != result.X || r.expected.Y != result.Y || r.expected.Z != result.Z {
            t.Errorf("BlockXYZ%v expected AbsIntXYZ%v got AbsIntXYZ%v",
                r.input, r.expected, result)
        }
    }
}
<|endoftext|>


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

package bytes

// Simple byte buffer for marshaling data.

import (
	"errors"
	"io"
	"unicode/utf8"
)

// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
	buf       []byte            // contents are the bytes buf[off : len(buf)]
	off       int               // read at &buf[off], write at &buf[len(buf)]
	runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
	bootstrap [64]byte          // memory to hold first slice; helps small buffers (Printf) avoid allocation.
	lastRead  readOp            // last read operation, so that Unread* can work correctly.
}

// The readOp constants describe the last action performed on
// the buffer, so that UnreadRune and UnreadByte can
// check for invalid usage.
type readOp int

const (
	opInvalid  readOp = iota // Non-read operation.
	opReadRune               // Read rune.
	opRead                   // Any other read operation.
)

// ErrTooLarge is returned if there is too much data to fit in a buffer.
var ErrTooLarge = errors.New("bytes.Buffer: too large")

// Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len().  If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
// are no intervening method calls on the Buffer.
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }

// String returns the contents of the unread portion of the buffer
// as a string.  If the Buffer is a nil pointer, it returns "<nil>".
func (b *Buffer) String() string {
	if b == nil {
		// Special case, useful in debugging.
		return "<nil>"
	}
	return string(b.buf[b.off:])
}

// Len returns the number of bytes of the unread portion of the buffer;
// b.Len() == len(b.Bytes()).
func (b *Buffer) Len() int { return len(b.buf) - b.off }

// Truncate discards all but the first n unread bytes from the buffer.
// It is an error to call b.Truncate(n) with n > b.Len().
func (b *Buffer) Truncate(n int) {
	b.lastRead = opInvalid
	if n == 0 {
		// Reuse buffer space.
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+n]
}

// Reset resets the buffer so it has no content.
// b.Reset() is the same as b.Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }

// grow grows the buffer to guarantee space for n more bytes.
// It returns the index where bytes should be written.
// If the buffer can't grow, it returns -1, which will
// become ErrTooLarge in the caller.
func (b *Buffer) grow(n int) int {
	m := b.Len()
	// If buffer is empty, reset to recover space.
	if m == 0 && b.off != 0 {
		b.Truncate(0)
	}
	if len(b.buf)+n > cap(b.buf) {
		var buf []byte
		if b.buf == nil && n <= len(b.bootstrap) {
			buf = b.bootstrap[0:]
		} else {
			// not enough space anywhere
			buf = makeSlice(2*cap(b.buf) + n)
			if buf == nil {
				return -1
			}
			copy(buf, b.buf[b.off:])
		}
		b.buf = buf
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+m+n]
	return b.off + m
}

// Write appends the contents of p to the buffer.  The return
// value n is the length of p; err is always nil.
func (b *Buffer) Write(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	m := b.grow(len(p))
	if m < 0 {
		return 0, ErrTooLarge
	}
	return copy(b.buf[m:], p), nil
}

// WriteString appends the contents of s to the buffer.  The return
// value n is the length of s; err is always nil.
func (b *Buffer) WriteString(s string) (n int, err error) {
	b.lastRead = opInvalid
	m := b.grow(len(s))
	if m < 0 {
		return 0, ErrTooLarge
	}
	return copy(b.buf[m:], s), nil
}

// MinRead is the minimum slice size passed to a Read call by
// Buffer.ReadFrom.  As long as the Buffer has at least MinRead bytes beyond
// what is required to hold the contents of r, ReadFrom will not grow the
// underlying buffer.
const MinRead = 512

// ReadFrom reads data from r until EOF and appends it to the buffer.
// The return value n is the number of bytes read.
// Any error except io.EOF encountered during the read
// is also returned.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
	b.lastRead = opInvalid
	// If buffer is empty, reset to recover space.
	if b.off >= len(b.buf) {
		b.Truncate(0)
	}
	for {
		if cap(b.buf)-len(b.buf) < MinRead {
			var newBuf []byte
			// can we get space without allocation?
			if b.off+cap(b.buf)-len(b.buf) >= MinRead {
				// reuse beginning of buffer
				newBuf = b.buf[0 : len(b.buf)-b.off]
			} else {
				// not enough space at end; put space on end
				newBuf = makeSlice(2*(cap(b.buf)-b.off) + MinRead)[:len(b.buf)-b.off]
				if newBuf == nil {
					return n, ErrTooLarge
				}
			}
			copy(newBuf, b.buf[b.off:])
			b.buf = newBuf
			b.off = 0
		}
		m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
		b.buf = b.buf[0 : len(b.buf)+m]
		n += int64(m)
		if e == io.EOF {
			break
		}
		if e != nil {
			return n, e
		}
	}
	return n, nil // err is EOF, so return nil explicitly
}

// makeSlice allocates a slice of size n, returning nil if the slice cannot be allocated.
func makeSlice(n int) []byte {
	if n < 0 {
		return nil
	}
	// Catch out of memory panics.
	defer func() {
		recover()
	}()
	return make([]byte, n)
}

// WriteTo writes data to w until the buffer is drained or an error
// occurs. The return value n is the number of bytes written; it always
// fits into an int, but it is int64 to match the io.WriterTo interface.
// Any error encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
	b.lastRead = opInvalid
	if b.off < len(b.buf) {
		m, e := w.Write(b.buf[b.off:])
		b.off += m
		n = int64(m)
		if e != nil {
			return n, e
		}
		// otherwise all bytes were written, by definition of
		// Write method in io.Writer
	}
	// Buffer is now empty; reset.
	b.Truncate(0)
	return
}

// WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.
func (b *Buffer) WriteByte(c byte) error {
	b.lastRead = opInvalid
	m := b.grow(1)
	if m < 0 {
		return ErrTooLarge
	}
	b.buf[m] = c
	return nil
}

// WriteRune appends the UTF-8 encoding of Unicode
// code point r to the buffer, returning its length and
// an error, which is always nil but is included
// to match bufio.Writer's WriteRune.
func (b *Buffer) WriteRune(r rune) (n int, err error) {
	if r < utf8.RuneSelf {
		b.WriteByte(byte(r))
		return 1, nil
	}
	n = utf8.EncodeRune(b.runeBytes[0:], r)
	b.Write(b.runeBytes[0:n])
	return n, nil
}

// Read reads the next len(p) 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 to return, err is io.EOF (unless len(p) is zero);
// otherwise it is nil.
func (b *Buffer) Read(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		if len(p) == 0 {
			return
		}
		return 0, io.EOF
	}
	n = copy(p, b.buf[b.off:])
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	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 in the buffer, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
func (b *Buffer) Next(n int) []byte {
	b.lastRead = opInvalid
	m := b.Len()
	if n > m {
		n = m
	}
	data := b.buf[b.off : b.off+n]
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return data
}

// ReadByte reads and returns the next byte from the buffer.
// If no byte is available, it returns error io.EOF.
func (b *Buffer) ReadByte() (c byte, err error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, io.EOF
	}
	c = b.buf[b.off]
	b.off++
	b.lastRead = opRead
	return c, nil
}

// ReadRune reads and returns the next UTF-8-encoded
// Unicode code point from the buffer.
// If no bytes are available, the error returned is io.EOF.
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
func (b *Buffer) ReadRune() (r rune, size int, err error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, 0, io.EOF
	}
	b.lastRead = opReadRune
	c := b.buf[b.off]
	if c < utf8.RuneSelf {
		b.off++
		return rune(c), 1, nil
	}
	r, n := utf8.DecodeRune(b.buf[b.off:])
	b.off += n
	return r, n, nil
}

// UnreadRune unreads the last rune returned by ReadRune.
// If the most recent read or write operation on the buffer was
// not a ReadRune, UnreadRune returns an error.  (In this regard
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Buffer) UnreadRune() error {
	if b.lastRead != opReadRune {
		return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		_, n := utf8.DecodeLastRune(b.buf[0:b.off])
		b.off -= n
	}
	return nil
}

// UnreadByte unreads the last byte returned by the most recent
// read operation.  If write has happened since the last read, UnreadByte
// returns an error.
func (b *Buffer) UnreadByte() error {
	if b.lastRead != opReadRune && b.lastRead != opRead {
		return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		b.off--
	}
	return nil
}

// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
	i := IndexByte(b.buf[b.off:], delim)
	size := i + 1
	if i < 0 {
		size = len(b.buf) - b.off
		err = io.EOF
	}
	line = make([]byte, size)
	copy(line, b.buf[b.off:])
	b.off += size
	return
}

// ReadString reads until the first occurrence of delim in the input,
// returning a string containing the data up to and including the delimiter.
// If ReadString encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end
// in delim.
func (b *Buffer) ReadString(delim byte) (line string, err error) {
	bytes, err := b.ReadBytes(delim)
	return string(bytes), err
}

// NewBuffer creates and initializes a new Buffer using buf as its initial
// contents.  It is intended to prepare a Buffer to read existing data.  It
// can also be used to size the internal buffer for writing. To do that,
// buf should have the desired capacity but a length of zero.
//
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
// preferable to NewBuffer.  In particular, passing a non-empty buf to
// NewBuffer and then writing to the Buffer will overwrite buf, not append to
// it.
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }

// NewBufferString creates and initializes a new Buffer using string s as its
// initial contents.  It is intended to prepare a buffer to read an existing
// string.  See the warnings about NewBuffer; similar issues apply here.
func NewBufferString(s string) *Buffer {
	return &Buffer{buf: []byte(s)}
}
<commit_msg>bytes: simplified logic<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package bytes

// Simple byte buffer for marshaling data.

import (
	"errors"
	"io"
	"unicode/utf8"
)

// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
	buf       []byte            // contents are the bytes buf[off : len(buf)]
	off       int               // read at &buf[off], write at &buf[len(buf)]
	runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
	bootstrap [64]byte          // memory to hold first slice; helps small buffers (Printf) avoid allocation.
	lastRead  readOp            // last read operation, so that Unread* can work correctly.
}

// The readOp constants describe the last action performed on
// the buffer, so that UnreadRune and UnreadByte can
// check for invalid usage.
type readOp int

const (
	opInvalid  readOp = iota // Non-read operation.
	opReadRune               // Read rune.
	opRead                   // Any other read operation.
)

// ErrTooLarge is returned if there is too much data to fit in a buffer.
var ErrTooLarge = errors.New("bytes.Buffer: too large")

// Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len().  If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
// are no intervening method calls on the Buffer.
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }

// String returns the contents of the unread portion of the buffer
// as a string.  If the Buffer is a nil pointer, it returns "<nil>".
func (b *Buffer) String() string {
	if b == nil {
		// Special case, useful in debugging.
		return "<nil>"
	}
	return string(b.buf[b.off:])
}

// Len returns the number of bytes of the unread portion of the buffer;
// b.Len() == len(b.Bytes()).
func (b *Buffer) Len() int { return len(b.buf) - b.off }

// Truncate discards all but the first n unread bytes from the buffer.
// It is an error to call b.Truncate(n) with n > b.Len().
func (b *Buffer) Truncate(n int) {
	b.lastRead = opInvalid
	if n == 0 {
		// Reuse buffer space.
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+n]
}

// Reset resets the buffer so it has no content.
// b.Reset() is the same as b.Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }

// grow grows the buffer to guarantee space for n more bytes.
// It returns the index where bytes should be written.
// If the buffer can't grow, it returns -1, which will
// become ErrTooLarge in the caller.
func (b *Buffer) grow(n int) int {
	m := b.Len()
	// If buffer is empty, reset to recover space.
	if m == 0 && b.off != 0 {
		b.Truncate(0)
	}
	if len(b.buf)+n > cap(b.buf) {
		var buf []byte
		if b.buf == nil && n <= len(b.bootstrap) {
			buf = b.bootstrap[0:]
		} else {
			// not enough space anywhere
			buf = makeSlice(2*cap(b.buf) + n)
			if buf == nil {
				return -1
			}
			copy(buf, b.buf[b.off:])
		}
		b.buf = buf
		b.off = 0
	}
	b.buf = b.buf[0 : b.off+m+n]
	return b.off + m
}

// Write appends the contents of p to the buffer.  The return
// value n is the length of p; err is always nil.
func (b *Buffer) Write(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	m := b.grow(len(p))
	if m < 0 {
		return 0, ErrTooLarge
	}
	return copy(b.buf[m:], p), nil
}

// WriteString appends the contents of s to the buffer.  The return
// value n is the length of s; err is always nil.
func (b *Buffer) WriteString(s string) (n int, err error) {
	b.lastRead = opInvalid
	m := b.grow(len(s))
	if m < 0 {
		return 0, ErrTooLarge
	}
	return copy(b.buf[m:], s), nil
}

// MinRead is the minimum slice size passed to a Read call by
// Buffer.ReadFrom.  As long as the Buffer has at least MinRead bytes beyond
// what is required to hold the contents of r, ReadFrom will not grow the
// underlying buffer.
const MinRead = 512

// ReadFrom reads data from r until EOF and appends it to the buffer.
// The return value n is the number of bytes read.
// Any error except io.EOF encountered during the read
// is also returned.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
	b.lastRead = opInvalid
	// If buffer is empty, reset to recover space.
	if b.off >= len(b.buf) {
		b.Truncate(0)
	}
	for {
		if free := cap(b.buf) - len(b.buf); free < MinRead {
			// not enough space at end
			newBuf := b.buf
			if b.off+free < MinRead {
				// not enough space using beginning of buffer;
				// double buffer capacity
				newBuf = makeSlice(2*cap(b.buf) + MinRead)
				if newBuf == nil {
					return n, ErrTooLarge
				}
			}
			copy(newBuf, b.buf[b.off:])
			b.buf = newBuf[:len(b.buf)-b.off]
			b.off = 0
		}
		m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
		b.buf = b.buf[0 : len(b.buf)+m]
		n += int64(m)
		if e == io.EOF {
			break
		}
		if e != nil {
			return n, e
		}
	}
	return n, nil // err is EOF, so return nil explicitly
}

// makeSlice allocates a slice of size n, returning nil if the slice cannot be allocated.
func makeSlice(n int) []byte {
	if n < 0 {
		return nil
	}
	// Catch out of memory panics.
	defer func() {
		recover()
	}()
	return make([]byte, n)
}

// WriteTo writes data to w until the buffer is drained or an error
// occurs. The return value n is the number of bytes written; it always
// fits into an int, but it is int64 to match the io.WriterTo interface.
// Any error encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
	b.lastRead = opInvalid
	if b.off < len(b.buf) {
		m, e := w.Write(b.buf[b.off:])
		b.off += m
		n = int64(m)
		if e != nil {
			return n, e
		}
		// otherwise all bytes were written, by definition of
		// Write method in io.Writer
	}
	// Buffer is now empty; reset.
	b.Truncate(0)
	return
}

// WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.
func (b *Buffer) WriteByte(c byte) error {
	b.lastRead = opInvalid
	m := b.grow(1)
	if m < 0 {
		return ErrTooLarge
	}
	b.buf[m] = c
	return nil
}

// WriteRune appends the UTF-8 encoding of Unicode
// code point r to the buffer, returning its length and
// an error, which is always nil but is included
// to match bufio.Writer's WriteRune.
func (b *Buffer) WriteRune(r rune) (n int, err error) {
	if r < utf8.RuneSelf {
		b.WriteByte(byte(r))
		return 1, nil
	}
	n = utf8.EncodeRune(b.runeBytes[0:], r)
	b.Write(b.runeBytes[0:n])
	return n, nil
}

// Read reads the next len(p) 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 to return, err is io.EOF (unless len(p) is zero);
// otherwise it is nil.
func (b *Buffer) Read(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		if len(p) == 0 {
			return
		}
		return 0, io.EOF
	}
	n = copy(p, b.buf[b.off:])
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	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 in the buffer, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
func (b *Buffer) Next(n int) []byte {
	b.lastRead = opInvalid
	m := b.Len()
	if n > m {
		n = m
	}
	data := b.buf[b.off : b.off+n]
	b.off += n
	if n > 0 {
		b.lastRead = opRead
	}
	return data
}

// ReadByte reads and returns the next byte from the buffer.
// If no byte is available, it returns error io.EOF.
func (b *Buffer) ReadByte() (c byte, err error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, io.EOF
	}
	c = b.buf[b.off]
	b.off++
	b.lastRead = opRead
	return c, nil
}

// ReadRune reads and returns the next UTF-8-encoded
// Unicode code point from the buffer.
// If no bytes are available, the error returned is io.EOF.
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
func (b *Buffer) ReadRune() (r rune, size int, err error) {
	b.lastRead = opInvalid
	if b.off >= len(b.buf) {
		// Buffer is empty, reset to recover space.
		b.Truncate(0)
		return 0, 0, io.EOF
	}
	b.lastRead = opReadRune
	c := b.buf[b.off]
	if c < utf8.RuneSelf {
		b.off++
		return rune(c), 1, nil
	}
	r, n := utf8.DecodeRune(b.buf[b.off:])
	b.off += n
	return r, n, nil
}

// UnreadRune unreads the last rune returned by ReadRune.
// If the most recent read or write operation on the buffer was
// not a ReadRune, UnreadRune returns an error.  (In this regard
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Buffer) UnreadRune() error {
	if b.lastRead != opReadRune {
		return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		_, n := utf8.DecodeLastRune(b.buf[0:b.off])
		b.off -= n
	}
	return nil
}

// UnreadByte unreads the last byte returned by the most recent
// read operation.  If write has happened since the last read, UnreadByte
// returns an error.
func (b *Buffer) UnreadByte() error {
	if b.lastRead != opReadRune && b.lastRead != opRead {
		return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
	}
	b.lastRead = opInvalid
	if b.off > 0 {
		b.off--
	}
	return nil
}

// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
	i := IndexByte(b.buf[b.off:], delim)
	size := i + 1
	if i < 0 {
		size = len(b.buf) - b.off
		err = io.EOF
	}
	line = make([]byte, size)
	copy(line, b.buf[b.off:])
	b.off += size
	return
}

// ReadString reads until the first occurrence of delim in the input,
// returning a string containing the data up to and including the delimiter.
// If ReadString encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end
// in delim.
func (b *Buffer) ReadString(delim byte) (line string, err error) {
	bytes, err := b.ReadBytes(delim)
	return string(bytes), err
}

// NewBuffer creates and initializes a new Buffer using buf as its initial
// contents.  It is intended to prepare a Buffer to read existing data.  It
// can also be used to size the internal buffer for writing. To do that,
// buf should have the desired capacity but a length of zero.
//
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
// preferable to NewBuffer.  In particular, passing a non-empty buf to
// NewBuffer and then writing to the Buffer will overwrite buf, not append to
// it.
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }

// NewBufferString creates and initializes a new Buffer using string s as its
// initial contents.  It is intended to prepare a buffer to read an existing
// string.  See the warnings about NewBuffer; similar issues apply here.
func NewBufferString(s string) *Buffer {
	return &Buffer{buf: []byte(s)}
}
<|endoftext|>


<commit_before>// (c) 2012 Alexander Solovyov
// under terms of ISC license

package gostatic

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"sort"
	"strings"
	"time"
)

const (
	StateUnknown = iota
	StateChanged
	StateUnchanged
	StateIgnored
)

type Page struct {
	PageHeader

	Site    *Site `json:"-"`
	Rule    *Rule
	Pattern string
	Deps    PageSlice `json:"-"`

	Source  string
	Path    string
	ModTime time.Time

	processed bool
	state     int
	raw       string
	content   string
	wasread   bool // if content was read already
}

type PageSlice []*Page

func NewPages(site *Site, path string) PageSlice {
	stat, err := os.Stat(path)
	errhandle(err)

	relpath, err := filepath.Rel(site.Source, path)
	errhandle(err)

	// convert windows path separators to unix style
	relpath = strings.Replace(relpath, "\\", "/", -1)

	pattern, rules := site.Rules.MatchedRules(relpath)
	if rules == nil {
		rules = make([]*Rule, 1)
	}

	pages := make(PageSlice, 0)

	for _, rule := range rules {
		page := &Page{
			Site:    site,
			Rule:    rule,
			Pattern: pattern,
			Source:  relpath,
			Path:    relpath,
			ModTime: stat.ModTime(),
		}
		page.Peek()
		debug("Found page: %s; rule: %v\n",
			page.Source, page.Rule)
		pages = append(pages, page)
	}
	return pages
}

func (page *Page) Raw() string {
	if !page.wasread {
		data, err := ioutil.ReadFile(page.FullPath())
		errhandle(err)

		// remove BOM if present
		if bytes.HasPrefix(data, []byte{0xEF, 0xBB, 0xBF}) {
			data = data[3:]
		}

		page.raw = string(data)
		page.wasread = true
		debug("Page '%s' was read, is of length %d\n", page.FullPath(), len(page.raw))
	}
	return page.raw
}

func (page *Page) Content() string {
	if page.content == "" {
		return page.Raw()
	}
	return page.content
}

func (page *Page) SetContent(content string) {
	page.content = content
}

func (page *Page) SetState(state int) {
	page.state = state
}

func (page *Page) FullPath() string {
	return filepath.Join(page.Site.Source, page.Source)
}

func (page *Page) OutputPath() string {
	return filepath.Join(page.Site.Output, page.Path)
}

func (page *Page) Url() string {
	if page == nil {
		errexit(fmt.Errorf(".Url called on a Page which does not exist"))
	}
	url := strings.Replace(page.Path, string(filepath.Separator), "/", -1)
	if url == "index.html" {
		return ""
	}
	if strings.HasSuffix(url, "/index.html") {
		return strings.TrimSuffix(url, "/index.html") + "/"
	}
	return url
}

func (page *Page) Name() string {
	return filepath.Base(page.Url())
}

func (page *Page) UrlTo(other *Page) string {
	return page.Rel(other.Url())
}

func (page *Page) Rel(path string) string {
	root := strings.Repeat("../", strings.Count(page.Url(), "/"))
	if root == "" {
		root = "./"
	}
	if len(path) == 0 {
		return root
	}
	if path[0] == '/' {
		return root + path[1:]
	}
	return root + path
}

func (page *Page) Is(path string) bool {
	return page.Url() == path || page.Path == path
}

// Is used for dynamically created pages
func (page *Page) SetWasRead(wasread bool) {
	page.wasread = wasread
}

func (page *Page) WasRead() bool {
	return page.wasread
}

// Peek is used to run those processors which should be done before others can
// find out about us. Two actual examples include 'config' and 'rename'
// processors.
func (page *Page) Peek() error {
	if page.Rule == nil {
		return nil
	}

	for _, cmd := range page.Rule.Commands {
		err := page.Site.ProcessCommand(page, &cmd, true)
		if err != nil {
			return err
		}
	}

	// Raw is page content after preprocessors, but before preprocessors
	if page.content != "" {
		page.raw = page.content
	}
	return nil
}

func (page *Page) findDeps() {
	if page.Rule == nil {
		return
	}

	deps := make(PageSlice, 0)
	for _, other := range page.Site.Pages {
		if other != page && page.Rule.IsDep(other) {
			deps = append(deps, other)
		}
	}
	page.Deps = deps
}

func (page *Page) Changed() bool {
	if page.Site.ForceRefresh {
		return true
	}

	if page.state == StateUnknown {
		page.state = StateUnchanged
		dest, err := os.Stat(page.OutputPath())

		if err != nil ||
			dest.ModTime().Before(page.ModTime) ||
			dest.ModTime().Before(page.Site.ChangedAt) {
			page.state = StateChanged
		} else {
			for _, dep := range page.Deps {
				if dep.Changed() {
					page.state = StateChanged
				}
			}
		}
	}

	return page.state == StateChanged
}

func (page *Page) Process() (*Page, error) {
	if page.processed || page.Rule == nil {
		return page, nil
	}

	page.processed = true
	if page.Rule.Commands != nil {
		for _, cmd := range page.Rule.Commands {
			err := page.Site.ProcessCommand(page, &cmd, false)
			if err != nil {
				return nil, err
			}
		}
	}

	return page, nil
}

func (page *Page) WriteTo(writer io.Writer) (n int64, err error) {
	if page.Rule == nil {
		return 0, nil
	}

	if !page.processed {
		page.Process()
	}

	nint, err := writer.Write([]byte(page.Content()))
	return int64(nint), err
}

func (page *Page) Render() (n int64, err error) {
	if page.Rule == nil {
		return CopyFile(page.FullPath(), page.OutputPath())
	}

	file, err := os.Create(page.OutputPath())
	if err != nil {
		return 0, err
	}
	defer file.Close()

	return page.WriteTo(file)
}

func (page *Page) UrlMatches(regex string) bool {
	re, err := regexp.Compile(regex)
	if err != nil {
		errhandle(fmt.Errorf("Incorrect regex given to Page.UrlMatches: '%s' ", regex))
	}
	return re.Match([]byte(page.Url()))
}

func (page *Page) Has(field, value string) bool {
	switch field {
	case "Title": return page.Title == value
	case "Tag": return (page.Tags != nil &&
		SliceStringIndexOf(page.Tags, value) != -1)
	case "Url": return page.UrlMatches(value)
	case "Source": matched, _ := path.Match(value, page.Source)
		return matched
	case "Hide": return ((page.Hide == true && value == "true") ||
		(page.Hide == false && value == "false"))
	default: return page.Other[field] == value
	}
}

func (page *Page) Prev() *Page {
	return page.Site.Pages.Prev(page)
}

func (page *Page) Next() *Page {
	return page.Site.Pages.Next(page)
}

// PageSlice manipulation

func (pages PageSlice) Get(i int) *Page { return pages[i] }
func (pages PageSlice) First() *Page    { return pages.Get(0) }
func (pages PageSlice) Last() *Page     { return pages.Get(len(pages) - 1) }

func (pages PageSlice) Prev(cur *Page) *Page {
	for i, page := range pages {
		if page == cur {
			if i == pages.Len()-1 {
				return nil
			}
			return pages[i+1]
		}
	}
	return nil
}

func (pages PageSlice) Next(cur *Page) *Page {
	for i, page := range pages {
		if page == cur {
			if i == 0 {
				return nil
			}
			return pages[i-1]
		}
	}
	return nil
}

func (pages PageSlice) Slice(from int, to int) PageSlice {
	length := len(pages)

	if from > length {
		from = length
	}
	if to > length {
		to = length
	}

	return pages[from:to]
}

// Sorting interface
func (pages PageSlice) Len() int {
	return len(pages)
}

func (pages PageSlice) Less(i, j int) bool {
	left := pages.Get(i)
	right := pages.Get(j)
	if left.Date.Unix() == right.Date.Unix() {
		return left.Path > right.Path
	}
	return left.Date.Unix() > right.Date.Unix()
}

func (pages PageSlice) Swap(i, j int) {
	pages[i], pages[j] = pages[j], pages[i]
}

func (pages PageSlice) Sort() {
	sort.Sort(pages)
}

func (pages PageSlice) Reverse() *PageSlice {
	p1 := append(PageSlice(nil), pages...)
	sort.Sort(sort.Reverse(p1))
	return &p1
}

func (pages PageSlice) Children(root string) *PageSlice {
	children := make(PageSlice, 0)

	for _, page := range pages {
		if !page.Hide &&
			strings.HasPrefix(page.Source, root) &&
			page.Url() != root {
			children = append(children, page)
		}
	}

	return &children
}

func (pages PageSlice) WithTag(tag string) *PageSlice {
	tagged := make(PageSlice, 0)

	for _, page := range pages {
		if !page.Hide &&
			page.Tags != nil &&
			SliceStringIndexOf(page.Tags, tag) != -1 {
			tagged = append(tagged, page)
		}
	}

	return &tagged
}

func (pages PageSlice) HasPage(check func(page *Page) bool) bool {
	for _, page := range pages {
		if check(page) {
			return true
		}
	}
	return false
}

func (pages PageSlice) BySource(s string) *Page {
	for _, page := range pages {
		if page.Source == s {
			return page
		}
	}
	return nil
}

func (pages PageSlice) GlobSource(pattern string) *PageSlice {
	found := make(PageSlice, 0)

	for _, page := range pages {
		if matched, _ := path.Match(pattern, page.Source); matched {
			found = append(found, page)
		}
	}

	return &found
}

func (pages PageSlice) ByPath(s string) *Page {
	for _, page := range pages {
		if page.Path == s {
			return page
		}
	}
	return nil
}

func (pages PageSlice) Where(field, value string) *PageSlice {
	found := make(PageSlice, 0)
	for _, page := range pages {
		if page.Has(field, value) {
			found = append(found, page)
		}
	}
	return &found
}

func (pages PageSlice) WhereNot(field, value string) *PageSlice {
	found := make(PageSlice, 0)
	for _, page := range pages {
		if !page.Has(field, value) {
			found = append(found, page)
		}
	}
	return &found
}
<commit_msg>fix #96<commit_after>// (c) 2012 Alexander Solovyov
// under terms of ISC license

package gostatic

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"sort"
	"strings"
	"time"
)

const (
	StateUnknown = iota
	StateChanged
	StateUnchanged
	StateIgnored
)

type Page struct {
	PageHeader

	Site    *Site `json:"-"`
	Rule    *Rule
	Pattern string
	Deps    PageSlice `json:"-"`

	Source  string
	Path    string
	ModTime time.Time

	processed bool
	state     int
	raw       string
	content   string
	wasread   bool // if content was read already
}

type PageSlice []*Page

func NewPages(site *Site, path string) PageSlice {
	stat, err := os.Stat(path)
	errhandle(err)

	relpath, err := filepath.Rel(site.Source, path)
	errhandle(err)

	// convert windows path separators to unix style
	relpath = strings.Replace(relpath, "\\", "/", -1)

	pattern, rules := site.Rules.MatchedRules(relpath)
	if rules == nil {
		rules = make([]*Rule, 1)
	}

	pages := make(PageSlice, 0)

	for _, rule := range rules {
		page := &Page{
			Site:    site,
			Rule:    rule,
			Pattern: pattern,
			Source:  relpath,
			Path:    relpath,
			ModTime: stat.ModTime(),
		}
		page.Peek()
		debug("Found page: %s; rule: %v\n",
			page.Source, page.Rule)
		pages = append(pages, page)
	}
	return pages
}

func (page *Page) Raw() string {
	if !page.wasread {
		data, err := ioutil.ReadFile(page.FullPath())
		errhandle(err)

		// remove BOM if present
		if bytes.HasPrefix(data, []byte{0xEF, 0xBB, 0xBF}) {
			data = data[3:]
		}

		page.raw = string(data)
		page.wasread = true
		debug("Page '%s' was read, is of length %d\n", page.FullPath(), len(page.raw))
	}
	return page.raw
}

func (page *Page) Content() string {
	if page.content == "" {
		return page.Raw()
	}
	return page.content
}

func (page *Page) SetContent(content string) {
	page.content = content
}

func (page *Page) SetState(state int) {
	page.state = state
}

func (page *Page) FullPath() string {
	return filepath.Join(page.Site.Source, page.Source)
}

func (page *Page) OutputPath() string {
	return filepath.Join(page.Site.Output, page.Path)
}

func (page *Page) Url() string {
	if page == nil {
		errexit(fmt.Errorf(".Url called on a Page which does not exist"))
	}
	url := strings.Replace(page.Path, string(filepath.Separator), "/", -1)
	if url == "index.html" {
		return ""
	}
	if strings.HasSuffix(url, "/index.html") {
		return strings.TrimSuffix(url, "/index.html") + "/"
	}
	return url
}

func (page *Page) Name() string {
	return filepath.Base(page.Url())
}

func (page *Page) UrlTo(other *Page) string {
	return page.Rel(other.Url())
}

func (page *Page) Rel(path string) string {
	root := strings.Repeat("../", strings.Count(page.Url(), "/"))
	if root == "" {
		root = "./"
	}
	if len(path) == 0 {
		return root
	}
	if path[0] == '/' {
		return root + path[1:]
	}
	return root + path
}

func (page *Page) Is(path string) bool {
	return page.Url() == path || page.Path == path
}

// SetWasRead is used for dynamically created pages
func (page *Page) SetWasRead(wasread bool) {
	page.wasread = wasread
}

func (page *Page) WasRead() bool {
	return page.wasread
}

// Peek is used to run those processors which should be done before others can
// find out about us. Two actual examples include 'config' and 'rename'
// processors.
func (page *Page) Peek() error {
	if page.Rule == nil {
		return nil
	}

	for _, cmd := range page.Rule.Commands {
		err := page.Site.ProcessCommand(page, &cmd, true)
		if err != nil {
			return err
		}
	}

	// Raw is page content after preprocessors, but before preprocessors
	if page.content != "" {
		page.raw = page.content
	}
	return nil
}

func (page *Page) findDeps() {
	if page.Rule == nil {
		return
	}

	deps := make(PageSlice, 0)
	for _, other := range page.Site.Pages {
		if other != page && page.Rule.IsDep(other) {
			deps = append(deps, other)
		}
	}
	page.Deps = deps
}

func (page *Page) Changed() bool {
	if page.Site.ForceRefresh {
		return true
	}

	if page.state == StateUnknown {
		page.state = StateUnchanged
		dest, err := os.Stat(page.OutputPath())

		if err != nil ||
			dest.ModTime().Before(page.ModTime) ||
			dest.ModTime().Before(page.Site.ChangedAt) {
			page.state = StateChanged
		} else {
			for _, dep := range page.Deps {
				if dep.Changed() {
					page.state = StateChanged
				}
			}
		}
	}

	return page.state == StateChanged
}

func (page *Page) Process() (*Page, error) {
	if page.processed || page.Rule == nil {
		return page, nil
	}

	page.processed = true
	if page.Rule.Commands != nil {
		for _, cmd := range page.Rule.Commands {
			err := page.Site.ProcessCommand(page, &cmd, false)
			if err != nil {
				return nil, err
			}
		}
	}

	return page, nil
}

func (page *Page) WriteTo(writer io.Writer) (n int64, err error) {
	if page.Rule == nil {
		return 0, nil
	}

	if !page.processed {
		page.Process()
	}

	nint, err := writer.Write([]byte(page.Content()))
	return int64(nint), err
}

func (page *Page) Render() (n int64, err error) {
	if page.Rule == nil {
		return CopyFile(page.FullPath(), page.OutputPath())
	}

	file, err := os.Create(page.OutputPath())
	if err != nil {
		return 0, err
	}
	defer file.Close()

	return page.WriteTo(file)
}

func (page *Page) UrlMatches(regex string) bool {
	re, err := regexp.Compile(regex)
	if err != nil {
		errhandle(fmt.Errorf("Incorrect regex given to Page.UrlMatches: '%s' ", regex))
	}
	return re.Match([]byte(page.Url()))
}

func (page *Page) Has(field, value string) bool {
	switch field {
	case "Title": return page.Title == value
	case "Tag": return (page.Tags != nil &&
		SliceStringIndexOf(page.Tags, value) != -1)
	case "Url": return page.UrlMatches(value)
	case "Source": matched, _ := path.Match(value, page.Source)
		return matched
	case "Hide": return ((page.Hide == true && value == "true") ||
		(page.Hide == false && value == "false"))
	default: return page.Other[field] == value
	}
}

func (page *Page) Prev() *Page {
	return page.Site.Pages.Prev(page)
}

func (page *Page) Next() *Page {
	return page.Site.Pages.Next(page)
}

// PageSlice manipulation

func (pages PageSlice) Get(i int) *Page { return pages[i] }
func (pages PageSlice) First() *Page    { return pages.Get(0) }
func (pages PageSlice) Last() *Page     { return pages.Get(len(pages) - 1) }

func (pages PageSlice) Prev(cur *Page) *Page {
	for i, page := range pages {
		if page == cur {
			if i == pages.Len()-1 {
				return nil
			}
			return pages[i+1]
		}
	}
	return nil
}

func (pages PageSlice) Next(cur *Page) *Page {
	for i, page := range pages {
		if page == cur {
			if i == 0 {
				return nil
			}
			return pages[i-1]
		}
	}
	return nil
}

func (pages PageSlice) Slice(from int, to int) PageSlice {
	length := len(pages)

	if from > length {
		from = length
	}
	if to > length {
		to = length
	}

	return pages[from:to]
}

// Sorting interface
func (pages PageSlice) Len() int {
	return len(pages)
}

func (pages PageSlice) Less(i, j int) bool {
	left := pages.Get(i)
	right := pages.Get(j)
	if left.Date.Unix() == right.Date.Unix() {
		return left.Path > right.Path
	}
	return left.Date.Unix() > right.Date.Unix()
}

func (pages PageSlice) Swap(i, j int) {
	pages[i], pages[j] = pages[j], pages[i]
}

func (pages PageSlice) Sort() {
	sort.Sort(pages)
}

func (pages PageSlice) Reverse() *PageSlice {
	p1 := append(PageSlice(nil), pages...)
	sort.Sort(sort.Reverse(p1))
	return &p1
}

func (pages PageSlice) Children(root string) *PageSlice {
	children := make(PageSlice, 0)

	for _, page := range pages {
		if !page.Hide &&
			strings.HasPrefix(page.Source, root) &&
			page.Url() != root {
			children = append(children, page)
		}
	}

	return &children
}

func (pages PageSlice) WithTag(tag string) *PageSlice {
	tagged := make(PageSlice, 0)

	for _, page := range pages {
		if !page.Hide &&
			page.Tags != nil &&
			SliceStringIndexOf(page.Tags, tag) != -1 {
			tagged = append(tagged, page)
		}
	}

	return &tagged
}

func (pages PageSlice) HasPage(check func(page *Page) bool) bool {
	for _, page := range pages {
		if check(page) {
			return true
		}
	}
	return false
}

func (pages PageSlice) BySource(s string) *Page {
	for _, page := range pages {
		if page.Source == s {
			return page
		}
	}
	return nil
}

func (pages PageSlice) GlobSource(pattern string) *PageSlice {
	found := make(PageSlice, 0)

	for _, page := range pages {
		if matched, _ := path.Match(pattern, page.Source); matched {
			found = append(found, page)
		}
	}

	return &found
}

func (pages PageSlice) ByPath(s string) *Page {
	for _, page := range pages {
		if page.Path == s {
			return page
		}
	}
	return nil
}

func (pages PageSlice) Where(field, value string) *PageSlice {
	found := make(PageSlice, 0)
	for _, page := range pages {
		if page.Has(field, value) {
			found = append(found, page)
		}
	}
	return &found
}

func (pages PageSlice) WhereNot(field, value string) *PageSlice {
	found := make(PageSlice, 0)
	for _, page := range pages {
		if !page.Has(field, value) {
			found = append(found, page)
		}
	}
	return &found
}
<|endoftext|>


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

package json

import "bytes"

// Compact appends to dst the JSON-encoded src with
// insignificant space characters elided.
// Like Marshal, Compact applies HTMLEscape to any
// string literals so that the JSON will be safe to embed
// inside HTML <script> tags.
func Compact(dst *bytes.Buffer, src []byte) error {
	return compact(dst, src, false)
}

func compact(dst *bytes.Buffer, src []byte, escape bool) error {
	origLen := dst.Len()
	var scan scanner
	scan.reset()
	start := 0
	for i, c := range src {
		if escape && (c == '<' || c == '>' || c == '&') {
			if start < i {
				dst.Write(src[start:i])
			}
			dst.WriteString(`\u00`)
			dst.WriteByte(hex[c>>4])
			dst.WriteByte(hex[c&0xF])
			start = i + 1
		}
		// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
		if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
			if start < i {
				dst.Write(src[start:i])
			}
			dst.WriteString(`\u202`)
			dst.WriteByte(hex[src[i+2]&0xF])
			start = i + 3
		}
		v := scan.step(&scan, c)
		if v >= scanSkipSpace {
			if v == scanError {
				break
			}
			if start < i {
				dst.Write(src[start:i])
			}
			start = i + 1
		}
	}
	if scan.eof() == scanError {
		dst.Truncate(origLen)
		return scan.err
	}
	if start < len(src) {
		dst.Write(src[start:])
	}
	return nil
}

func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
	dst.WriteByte('\n')
	dst.WriteString(prefix)
	for i := 0; i < depth; i++ {
		dst.WriteString(indent)
	}
}

// Indent appends to dst an indented form of the JSON-encoded src.
// Each element in a JSON object or array begins on a new,
// indented line beginning with prefix followed by one or more
// copies of indent according to the indentation nesting.
// The data appended to dst does not begin with the prefix nor
// any indentation, to make it easier to embed inside other formatted JSON data.
// Although leading space characters (space, tab, carriage return, newline)
// at the beginning of src are dropped, trailing space characters
// at the end of src are preserved and copied to dst.
// For example, if src has no trailing spaces, neither will dst;
// if src ends in a trailing newline, so will dst.
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
	origLen := dst.Len()
	var scan scanner
	scan.reset()
	needIndent := false
	depth := 0
	for _, c := range src {
		scan.bytes++
		v := scan.step(&scan, c)
		if v == scanSkipSpace {
			continue
		}
		if v == scanError {
			break
		}
		if needIndent && v != scanEndObject && v != scanEndArray {
			needIndent = false
			depth++
			newline(dst, prefix, indent, depth)
		}

		// Emit semantically uninteresting bytes
		// (in particular, punctuation in strings) unmodified.
		if v == scanContinue {
			dst.WriteByte(c)
			continue
		}

		// Add spacing around real punctuation.
		switch c {
		case '{', '[':
			// delay indent so that empty object and array are formatted as {} and [].
			needIndent = true
			dst.WriteByte(c)

		case ',':
			dst.WriteByte(c)
			newline(dst, prefix, indent, depth)

		case ':':
			dst.WriteByte(c)
			dst.WriteByte(' ')

		case '}', ']':
			if needIndent {
				// suppress indent in empty object/array
				needIndent = false
			} else {
				depth--
				newline(dst, prefix, indent, depth)
			}
			dst.WriteByte(c)

		default:
			dst.WriteByte(c)
		}
	}
	if scan.eof() == scanError {
		dst.Truncate(origLen)
		return scan.err
	}
	return nil
}
<commit_msg>encoding/json: revert Compact HTML escaping documentation<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package json

import "bytes"

// Compact appends to dst the JSON-encoded src with
// insignificant space characters elided.
func Compact(dst *bytes.Buffer, src []byte) error {
	return compact(dst, src, false)
}

func compact(dst *bytes.Buffer, src []byte, escape bool) error {
	origLen := dst.Len()
	var scan scanner
	scan.reset()
	start := 0
	for i, c := range src {
		if escape && (c == '<' || c == '>' || c == '&') {
			if start < i {
				dst.Write(src[start:i])
			}
			dst.WriteString(`\u00`)
			dst.WriteByte(hex[c>>4])
			dst.WriteByte(hex[c&0xF])
			start = i + 1
		}
		// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
		if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
			if start < i {
				dst.Write(src[start:i])
			}
			dst.WriteString(`\u202`)
			dst.WriteByte(hex[src[i+2]&0xF])
			start = i + 3
		}
		v := scan.step(&scan, c)
		if v >= scanSkipSpace {
			if v == scanError {
				break
			}
			if start < i {
				dst.Write(src[start:i])
			}
			start = i + 1
		}
	}
	if scan.eof() == scanError {
		dst.Truncate(origLen)
		return scan.err
	}
	if start < len(src) {
		dst.Write(src[start:])
	}
	return nil
}

func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
	dst.WriteByte('\n')
	dst.WriteString(prefix)
	for i := 0; i < depth; i++ {
		dst.WriteString(indent)
	}
}

// Indent appends to dst an indented form of the JSON-encoded src.
// Each element in a JSON object or array begins on a new,
// indented line beginning with prefix followed by one or more
// copies of indent according to the indentation nesting.
// The data appended to dst does not begin with the prefix nor
// any indentation, to make it easier to embed inside other formatted JSON data.
// Although leading space characters (space, tab, carriage return, newline)
// at the beginning of src are dropped, trailing space characters
// at the end of src are preserved and copied to dst.
// For example, if src has no trailing spaces, neither will dst;
// if src ends in a trailing newline, so will dst.
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
	origLen := dst.Len()
	var scan scanner
	scan.reset()
	needIndent := false
	depth := 0
	for _, c := range src {
		scan.bytes++
		v := scan.step(&scan, c)
		if v == scanSkipSpace {
			continue
		}
		if v == scanError {
			break
		}
		if needIndent && v != scanEndObject && v != scanEndArray {
			needIndent = false
			depth++
			newline(dst, prefix, indent, depth)
		}

		// Emit semantically uninteresting bytes
		// (in particular, punctuation in strings) unmodified.
		if v == scanContinue {
			dst.WriteByte(c)
			continue
		}

		// Add spacing around real punctuation.
		switch c {
		case '{', '[':
			// delay indent so that empty object and array are formatted as {} and [].
			needIndent = true
			dst.WriteByte(c)

		case ',':
			dst.WriteByte(c)
			newline(dst, prefix, indent, depth)

		case ':':
			dst.WriteByte(c)
			dst.WriteByte(' ')

		case '}', ']':
			if needIndent {
				// suppress indent in empty object/array
				needIndent = false
			} else {
				depth--
				newline(dst, prefix, indent, depth)
			}
			dst.WriteByte(c)

		default:
			dst.WriteByte(c)
		}
	}
	if scan.eof() == scanError {
		dst.Truncate(origLen)
		return scan.err
	}
	return nil
}
<|endoftext|>


<commit_before>package meter

import (
	"encoding/json"
	"sort"
	"time"

	"github.com/go-redis/redis"
)

type Record struct {
	Name   string
	Time   time.Time
	Key    string
	Field  string
	Labels []string
	Result *redis.StringCmd
}

func (r *Record) Value() int64 {
	if r.Result != nil {
		if n, err := r.Result.Int64(); err == nil {
			return n
		}
	}
	return 0
}

func (r *Record) MarshalJSON() ([]byte, error) {
	obj := make(map[string]interface{})
	for i := 0; i < len(r.Labels); i += 2 {
		obj[r.Labels[i]] = r.Labels[i+1]
	}
	obj["value"] = r.Value()
	obj["time"] = r.Time.String()
	obj["name"] = r.Name

	return json.Marshal(obj)
}

func ReadRecords(r redis.UniversalClient, records []*Record) error {
	pipeline := r.Pipeline()
	defer pipeline.Close()
	for _, r := range records {
		r.Result = pipeline.HGet(r.Key, r.Field)
	}
	_, err := pipeline.Exec()
	if err == redis.Nil {
		return nil
	}
	return err
}

type RecordSequence []*Record

func (s RecordSequence) Results() []*Result {
	grouped := make(map[string]*Result)
	for _, r := range s {
		key := r.Name + ":" + r.Field
		result, ok := grouped[key]
		if !ok {
			result = &Result{
				Event:  r.Name,
				Labels: Labels(r.Labels).Map(),
				Data:   make([]DataPoint, 0, len(s)),
			}
			grouped[key] = result
		}
		result.Data = append(result.Data, DataPoint{r.Time.Unix(), r.Value()})
	}
	results := make([]*Result, len(grouped))
	i := 0
	for _, r := range grouped {
		sort.Slice(r.Data, func(i, j int) bool {
			return r.Data[i].Value < r.Data[j].Value
		})
		results[i] = r
		i++
	}
	return results
}

func (s RecordSequence) Group() []*Result {
	grouped := make(map[string]*Result)
sloop:
	for _, r := range s {
		key := r.Name
		result, ok := grouped[key]
		if !ok {
			result = &Result{
				Event: r.Name,
				Data:  make([]DataPoint, 0, len(s)),
			}
			grouped[key] = result
		}
		t := r.Time.Unix()
		v := r.Value()
		for i, d := range result.Data {
			if d.Timestamp == t {
				result.Data[i].Value += v
				continue sloop
			}
		}
		result.Data = append(result.Data, DataPoint{t, v})
	}
	results := make([]*Result, len(grouped))
	i := 0
	for _, r := range grouped {
		sort.Slice(r.Data, func(i, j int) bool {
			return r.Data[i].Value < r.Data[j].Value
		})
		results[i] = r
		i++
	}
	return results

}
<commit_msg>Fix Record.MarshalJSON()<commit_after>package meter

import (
	"encoding/json"
	"sort"
	"time"

	"github.com/go-redis/redis"
)

type Record struct {
	Name   string
	Time   time.Time
	Key    string
	Field  string
	Labels []string
	Result *redis.StringCmd
}

func (r *Record) Value() int64 {
	if r.Result != nil {
		if n, err := r.Result.Int64(); err == nil {
			return n
		}
	}
	return 0
}

func (r *Record) MarshalJSON() ([]byte, error) {
	obj := make(map[string]interface{})
	for i := 0; i < len(r.Labels); i += 2 {
		if k, v := r.Labels[i], r.Labels[i+1]; v != "*" {
			obj[k] = v
		}
	}
	obj["value"] = r.Value()
	obj["time"] = r.Time.String()
	obj["name"] = r.Name

	return json.Marshal(obj)
}

func ReadRecords(r redis.UniversalClient, records []*Record) error {
	pipeline := r.Pipeline()
	defer pipeline.Close()
	for _, r := range records {
		r.Result = pipeline.HGet(r.Key, r.Field)
	}
	_, err := pipeline.Exec()
	if err == redis.Nil {
		return nil
	}
	return err
}

type RecordSequence []*Record

func (s RecordSequence) Results() []*Result {
	grouped := make(map[string]*Result)
	for _, r := range s {
		key := r.Name + ":" + r.Field
		result, ok := grouped[key]
		if !ok {
			result = &Result{
				Event:  r.Name,
				Labels: Labels(r.Labels).Map(),
				Data:   make([]DataPoint, 0, len(s)),
			}
			grouped[key] = result
		}
		result.Data = append(result.Data, DataPoint{r.Time.Unix(), r.Value()})
	}
	results := make([]*Result, len(grouped))
	i := 0
	for _, r := range grouped {
		sort.Slice(r.Data, func(i, j int) bool {
			return r.Data[i].Value < r.Data[j].Value
		})
		results[i] = r
		i++
	}
	return results
}

func (s RecordSequence) Group() []*Result {
	grouped := make(map[string]*Result)
sloop:
	for _, r := range s {
		key := r.Name
		result, ok := grouped[key]
		if !ok {
			result = &Result{
				Event: r.Name,
				Data:  make([]DataPoint, 0, len(s)),
			}
			grouped[key] = result
		}
		t := r.Time.Unix()
		v := r.Value()
		for i, d := range result.Data {
			if d.Timestamp == t {
				result.Data[i].Value += v
				continue sloop
			}
		}
		result.Data = append(result.Data, DataPoint{t, v})
	}
	results := make([]*Result, len(grouped))
	i := 0
	for _, r := range grouped {
		sort.Slice(r.Data, func(i, j int) bool {
			return r.Data[i].Value < r.Data[j].Value
		})
		results[i] = r
		i++
	}
	return results

}
<|endoftext|>