<commit_before>package roaring64

// to run just these tests: go test -run TestParAggregations

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"testing"
)

func testAggregations(t *testing.T,
	and func(bitmaps ...*Bitmap) *Bitmap,
	or func(bitmaps ...*Bitmap) *Bitmap,
	xor func(bitmaps ...*Bitmap) *Bitmap) {

	t.Run("simple case", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb1.Add(uint64(1))
		rb2.Add(uint64(2))

		assertAggregation(t, 0, and, rb1, rb2)
		assertAggregation(t, 2, or, rb1, rb2)
		assertAggregation(t, 2, xor, rb1, rb2)
	})

	t.Run("aggregate nothing", func(t *testing.T) {
		assertAggregation(t, 0, and)
		assertAggregation(t, 0, or)
		assertAggregation(t, 0, xor)
	})

	t.Run("single bitmap", func(t *testing.T) {
		rb := BitmapOf(1, 2, 3)

		assertAggregation(t, 3, and, rb)
		assertAggregation(t, 3, or, rb)
		assertAggregation(t, 3, xor, rb)
	})

	t.Run("empty and single elem bitmaps", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := BitmapOf(1)

		assertAggregation(t, 0, and, rb1, rb2)
		assertAggregation(t, 1, or, rb1, rb2)
		assertAggregation(t, 1, xor, rb1, rb2)
	})

	t.Run("two single elem disjoint sets", func(t *testing.T) {
		rb1 := BitmapOf(1)
		rb2 := BitmapOf(2)

		assertAggregation(t, 0, and, rb1, rb2)
		assertAggregation(t, 2, or, rb1, rb2)
	})

	t.Run("3 bitmaps with CoW set (not in order of definition)", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		rb1.SetCopyOnWrite(true)
		rb2.SetCopyOnWrite(true)
		rb3.SetCopyOnWrite(true)
		rb1.Add(uint64(1))
		rb1.Add(uint64(100000))
		rb2.Add(uint64(200000))
		rb3.Add(uint64(1))
		rb3.Add(uint64(300000))

		assertAggregation(t, 0, and, rb2, rb1, rb3)
		assertAggregation(t, 4, or, rb2, rb1, rb3)
		assertAggregation(t, 3, xor, rb2, rb1, rb3)
	})

	t.Run("3 bitmaps (not in order of definition)", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		rb1.Add(uint64(1))
		rb1.Add(uint64(100000))
		rb2.Add(uint64(200000))
		rb3.Add(uint64(1))
		rb3.Add(uint64(300000))

		assertAggregation(t, 0, and, rb2, rb1, rb3)
		assertAggregation(t, 4, or, rb2, rb1, rb3)
		assertAggregation(t, 3, xor, rb2, rb1, rb3)
	})

	t.Run("3 bitmaps", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		rb1.Add(uint64(1))
		rb1.Add(uint64(100000))
		rb2.Add(uint64(200000))
		rb3.Add(uint64(1))
		rb3.Add(uint64(300000))

		assertAggregation(t, 0, and, rb1, rb2, rb3)
		assertAggregation(t, 4, or, rb1, rb2, rb3)
		assertAggregation(t, 3, xor, rb1, rb2, rb3)
	})

	t.Run("3 bitmaps with CoW set", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		rb1.SetCopyOnWrite(true)
		rb2.SetCopyOnWrite(true)
		rb3.SetCopyOnWrite(true)
		rb1.Add(uint64(1))
		rb1.Add(uint64(100000))
		rb2.Add(uint64(200000))
		rb3.Add(uint64(1))
		rb3.Add(uint64(300000))

		assertAggregation(t, 0, and, rb1, rb2, rb3)
		assertAggregation(t, 4, or, rb1, rb2, rb3)
		assertAggregation(t, 3, xor, rb1, rb2, rb3)
	})

	t.Run("advanced case", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		for i := uint64(0); i < 1000000; i += 3 {
			rb1.Add(i)
		}
		for i := uint64(0); i < 1000000; i += 7 {
			rb2.Add(i)
		}
		for i := uint64(0); i < 1000000; i += 1001 {
			rb3.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 1001 {
			rb1.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 3 {
			rb2.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 7 {
			rb3.Add(i)
		}

		rb1.Or(rb2)
		rb1.Or(rb3)
		bigand := And(And(rb1, rb2), rb3)
		bigxor := Xor(Xor(rb1, rb2), rb3)

		if or != nil {
			assert.True(t, or(rb1, rb2, rb3).Equals(rb1))
		}

		if and != nil {
			assert.True(t, and(rb1, rb2, rb3).Equals(bigand))
		}

		if xor != nil {
			assert.True(t, xor(rb1, rb2, rb3).Equals(bigxor))
		}
	})

	t.Run("advanced case with runs", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		for i := uint64(500); i < 75000; i++ {
			rb1.Add(i)
		}
		for i := uint64(0); i < 1000000; i += 7 {
			rb2.Add(i)
		}
		for i := uint64(0); i < 1000000; i += 1001 {
			rb3.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 1001 {
			rb1.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 3 {
			rb2.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 7 {
			rb3.Add(i)
		}
		rb1.RunOptimize()

		rb1.Or(rb2)
		rb1.Or(rb3)
		bigand := And(And(rb1, rb2), rb3)
		bigxor := Xor(Xor(rb1, rb2), rb3)

		if or != nil {
			assert.True(t, or(rb1, rb2, rb3).Equals(rb1))
		}

		if and != nil {
			assert.True(t, and(rb1, rb2, rb3).Equals(bigand))
		}

		if xor != nil {
			assert.True(t, xor(rb1, rb2, rb3).Equals(bigxor))
		}
	})

	t.Run("issue 178", func(t *testing.T) {
		ba1 := []uint64{3585028, 65901253, 143441994, 211160474, 286511937, 356744840, 434332509, 502812785, 576097614, 646557334, 714794241, 775083485, 833704249, 889329147, 941367043}
		ba2 := []uint64{17883, 54494426, 113908938, 174519827, 235465665, 296685741, 357644666, 420192495, 476104304, 523046142, 577855081, 634889665, 692460635, 751350463, 809989192, 863494316, 919127240}

		r1 := BitmapOf(ba1...)
		r2 := BitmapOf(ba2...)

		assertAggregation(t, 32, or, r1, r2)
	})
}

func assertAggregation(t *testing.T, expected uint64, aggr func(bitmaps ...*Bitmap) *Bitmap, bitmaps ...*Bitmap) {
	if aggr != nil {
		assert.Equal(t, aggr(bitmaps...).GetCardinality(), expected)
	}
}

func TestParAggregations(t *testing.T) {
	for _, p := range [...]int{0, 1, 2, 4} {
		//andFunc := func(bitmaps ...*Bitmap) *Bitmap {
		//	return ParAnd(p, bitmaps...)
		//}
		orFunc := func(bitmaps ...*Bitmap) *Bitmap {
			return ParOr(p, bitmaps...)
		}

		t.Run(fmt.Sprintf("par%d", p), func(t *testing.T) {
			//testAggregations(t, andFunc, orFunc, nil)
			testAggregations(t, nil, orFunc, nil)
		})
	}
}

/*
func TestParHeapAggregations(t *testing.T) {
	orFunc := func(bitmaps ...*Bitmap) *Bitmap {
		return ParHeapOr(0, bitmaps...)
	}

	testAggregations(t, nil, orFunc, nil)
}
*/

func TestFastAggregations(t *testing.T) {
	testAggregations(t, nil, FastOr, nil)
}

//func TestHeapAggregations(t *testing.T) {
//	testAggregations(t, nil, HeapOr, HeapXor)
//}
<commit_msg>Try to improve coverage of ParOr.<commit_after>package roaring64

// to run just these tests: go test -run TestParAggregations

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"testing"
)

func testAggregations(t *testing.T,
	and func(bitmaps ...*Bitmap) *Bitmap,
	or func(bitmaps ...*Bitmap) *Bitmap,
	xor func(bitmaps ...*Bitmap) *Bitmap) {

	t.Run("simple case", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb1.Add(uint64(1))
		rb2.Add(uint64(2))

		assertAggregation(t, 0, and, rb1, rb2)
		assertAggregation(t, 2, or, rb1, rb2)
		assertAggregation(t, 2, xor, rb1, rb2)
	})

	t.Run("aggregate nothing", func(t *testing.T) {
		assertAggregation(t, 0, and)
		assertAggregation(t, 0, or)
		assertAggregation(t, 0, xor)
	})

	t.Run("single bitmap", func(t *testing.T) {
		rb := BitmapOf(1, 2, 3)

		assertAggregation(t, 3, and, rb)
		assertAggregation(t, 3, or, rb)
		assertAggregation(t, 3, xor, rb)
	})

	t.Run("empty and single elem bitmaps", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := BitmapOf(1)

		assertAggregation(t, 0, and, rb1, rb2)
		assertAggregation(t, 1, or, rb1, rb2)
		assertAggregation(t, 1, xor, rb1, rb2)
	})

	t.Run("two single elem disjoint sets", func(t *testing.T) {
		rb1 := BitmapOf(1)
		rb2 := BitmapOf(2)

		assertAggregation(t, 0, and, rb1, rb2)
		assertAggregation(t, 2, or, rb1, rb2)
	})

	t.Run("3 bitmaps with CoW set (not in order of definition)", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		rb1.SetCopyOnWrite(true)
		rb2.SetCopyOnWrite(true)
		rb3.SetCopyOnWrite(true)
		rb1.Add(uint64(1))
		rb1.Add(uint64(100000))
		rb2.Add(uint64(200000))
		rb3.Add(uint64(1))
		rb3.Add(uint64(300000))

		assertAggregation(t, 0, and, rb2, rb1, rb3)
		assertAggregation(t, 4, or, rb2, rb1, rb3)
		assertAggregation(t, 3, xor, rb2, rb1, rb3)
	})

	t.Run("3 bitmaps (not in order of definition)", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		rb1.Add(uint64(1))
		rb1.Add(uint64(100000))
		rb2.Add(uint64(200000))
		rb3.Add(uint64(1))
		rb3.Add(uint64(300000))

		assertAggregation(t, 0, and, rb2, rb1, rb3)
		assertAggregation(t, 4, or, rb2, rb1, rb3)
		assertAggregation(t, 3, xor, rb2, rb1, rb3)
	})

	t.Run("3 bitmaps", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		rb1.Add(uint64(1))
		rb1.Add(uint64(100000))
		rb2.Add(uint64(200000))
		rb3.Add(uint64(1))
		rb3.Add(uint64(300000))

		assertAggregation(t, 0, and, rb1, rb2, rb3)
		assertAggregation(t, 4, or, rb1, rb2, rb3)
		assertAggregation(t, 3, xor, rb1, rb2, rb3)
	})

	t.Run("3 bitmaps with CoW set", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		rb1.SetCopyOnWrite(true)
		rb2.SetCopyOnWrite(true)
		rb3.SetCopyOnWrite(true)
		rb1.Add(uint64(1))
		rb1.Add(uint64(100000))
		rb2.Add(uint64(200000))
		rb3.Add(uint64(1))
		rb3.Add(uint64(300000))

		assertAggregation(t, 0, and, rb1, rb2, rb3)
		assertAggregation(t, 4, or, rb1, rb2, rb3)
		assertAggregation(t, 3, xor, rb1, rb2, rb3)
	})

	t.Run("advanced case", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		for i := uint64(0); i < 1000000; i += 3 {
			rb1.Add(i)
		}
		for i := uint64(0); i < 1000000; i += 7 {
			rb2.Add(i)
		}
		for i := uint64(0); i < 1000000; i += 1001 {
			rb3.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 1001 {
			rb1.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 3 {
			rb2.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 7 {
			rb3.Add(i)
		}

		rb1.Or(rb2)
		rb1.Or(rb3)
		bigand := And(And(rb1, rb2), rb3)
		bigxor := Xor(Xor(rb1, rb2), rb3)

		if or != nil {
			assert.True(t, or(rb1, rb2, rb3).Equals(rb1))
		}

		if and != nil {
			assert.True(t, and(rb1, rb2, rb3).Equals(bigand))
		}

		if xor != nil {
			assert.True(t, xor(rb1, rb2, rb3).Equals(bigxor))
		}
	})

	t.Run("advanced case with runs", func(t *testing.T) {
		rb1 := NewBitmap()
		rb2 := NewBitmap()
		rb3 := NewBitmap()
		for i := uint64(500); i < 75000; i++ {
			rb1.Add(i)
		}
		for i := uint64(0); i < 1000000; i += 7 {
			rb2.Add(i)
		}
		for i := uint64(0); i < 1000000; i += 1001 {
			rb3.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 1001 {
			rb1.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 3 {
			rb2.Add(i)
		}
		for i := uint64(1000000); i < 2000000; i += 7 {
			rb3.Add(i)
		}
		rb1.RunOptimize()

		rb1.Or(rb2)
		rb1.Or(rb3)
		bigand := And(And(rb1, rb2), rb3)
		bigxor := Xor(Xor(rb1, rb2), rb3)

		if or != nil {
			assert.True(t, or(rb1, rb2, rb3).Equals(rb1))
		}

		if and != nil {
			assert.True(t, and(rb1, rb2, rb3).Equals(bigand))
		}

		if xor != nil {
			assert.True(t, xor(rb1, rb2, rb3).Equals(bigxor))
		}
	})

	t.Run("issue 178", func(t *testing.T) {
		ba1 := []uint64{3585028, 65901253, 143441994, 211160474, 286511937, 356744840, 434332509, 502812785, 576097614, 646557334, 714794241, 775083485, 833704249, 889329147, 941367043}
		ba2 := []uint64{17883, 54494426, 113908938, 174519827, 235465665, 296685741, 357644666, 420192495, 476104304, 523046142, 577855081, 634889665, 692460635, 751350463, 809989192, 863494316, 919127240}

		r1 := BitmapOf(ba1...)
		r2 := BitmapOf(ba2...)

		assertAggregation(t, 32, or, r1, r2)
	})
}

func assertAggregation(t *testing.T, expected uint64, aggr func(bitmaps ...*Bitmap) *Bitmap, bitmaps ...*Bitmap) {
	if aggr != nil {
		assert.Equal(t, aggr(bitmaps...).GetCardinality(), expected)
	}
}

func TestParAggregations(t *testing.T) {
	for _, p := range [...]int{0, 1, 2, 4} {
		//andFunc := func(bitmaps ...*Bitmap) *Bitmap {
		//	return ParAnd(p, bitmaps...)
		//}
		orFunc := func(bitmaps ...*Bitmap) *Bitmap {
			return ParOr(p, bitmaps...)
		}

		t.Run(fmt.Sprintf("par%d", p), func(t *testing.T) {
			//testAggregations(t, andFunc, orFunc, nil)
			testAggregations(t, nil, orFunc, nil)
		})
	}
}

func TestParAggregations2(t *testing.T) {
	orFunc := func(bitmaps ...*Bitmap) *Bitmap {
		return ParOr(0, bitmaps...)
	}
	t.Run(fmt.Sprintf("par0"), func(t *testing.T) {
		testAggregations(t, nil, orFunc, nil)
	})
}

/*
func TestParHeapAggregations(t *testing.T) {
	orFunc := func(bitmaps ...*Bitmap) *Bitmap {
		return ParHeapOr(0, bitmaps...)
	}

	testAggregations(t, nil, orFunc, nil)
}
*/

func TestFastAggregations(t *testing.T) {
	testAggregations(t, nil, FastOr, nil)
}

//func TestHeapAggregations(t *testing.T) {
//	testAggregations(t, nil, HeapOr, HeapXor)
//}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"fmt"
	"socialapi/config"
	"time"

	"github.com/koding/bongo"
)

type ChannelMessage struct {
	// unique identifier of the channel message
	Id int64 `json:"id"`

	// Body of the mesage
	Body string `json:"body"`

	// Generated Slug for body
	Slug string `json:"slug"                        sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// type of the message
	TypeConstant string `json:"typeConstant"        sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creator of the channel message
	AccountId int64 `json:"accountId"               sql:"NOT NULL"`

	// in which channel this message is created
	InitialChannelId int64 `json:"initialChannelId" sql:"NOT NULL"`

	// Creation date of the message
	CreatedAt time.Time `json:"createdAt"           sql:"DEFAULT:CURRENT_TIMESTAMP"`

	// Modification date of the message
	UpdatedAt time.Time `json:"updatedAt"           sql:"DEFAULT:CURRENT_TIMESTAMP"`
}

func (c *ChannelMessage) AfterCreate() {
	bongo.B.AfterCreate(c)
}

func (c *ChannelMessage) AfterUpdate() {
	bongo.B.AfterUpdate(c)
}

func (c *ChannelMessage) AfterDelete() {
	bongo.B.AfterDelete(c)
}

func (c *ChannelMessage) GetId() int64 {
	return c.Id
}

func (c ChannelMessage) TableName() string {
	return "api.channel_message"
}

const (
	ChannelMessage_TYPE_POST  = "post"
	ChannelMessage_TYPE_REPLY = "reply"
	ChannelMessage_TYPE_JOIN  = "join"
	ChannelMessage_TYPE_LEAVE = "leave"
	ChannelMessage_TYPE_CHAT  = "chat"
)

func NewChannelMessage() *ChannelMessage {
	return &ChannelMessage{}
}

func (c *ChannelMessage) Fetch() error {
	return bongo.B.Fetch(c)
}

func (c *ChannelMessage) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func bodyLenCheck(body string) error {
	if len(body) < config.Get().Limits.MessageBodyMinLen {
		return fmt.Errorf("Message Body Length should be greater than %d, yours is %d ", config.Get().Limits.MessageBodyMinLen, len(body))
	}
	return nil
}

func (c *ChannelMessage) Update() error {
	if err := bodyLenCheck(c.Body); err != nil {
		return err
	}
	// only update body
	err := bongo.B.UpdatePartial(c,
		map[string]interface{}{
			"body": c.Body,
		},
	)
	return err
}

func (c *ChannelMessage) Create() error {
	if err := bodyLenCheck(c.Body); err != nil {
		return err
	}

	var err error
	c, err = Slugify(c)
	if err != nil {
		return err
	}

	return bongo.B.Create(c)
}

func (c *ChannelMessage) Delete() error {
	return bongo.B.Delete(c)
}

func (c *ChannelMessage) FetchByIds(ids []int64) ([]ChannelMessage, error) {
	var messages []ChannelMessage

	if len(ids) == 0 {
		return messages, nil
	}

	if err := bongo.B.FetchByIds(c, &messages, ids); err != nil {
		return nil, err
	}
	return messages, nil
}

func (c *ChannelMessage) FetchRelatives(query *Query) (*ChannelMessageContainer, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel message id is not set")
	}
	container := NewChannelMessageContainer()
	container.Message = c

	i := NewInteraction()
	i.MessageId = c.Id

	oldId, err := FetchMongoIdByAccountId(c.AccountId)
	if err != nil {
		return nil, err
	}

	container.AccountOldId = oldId

	interactorIds, err := i.List("like")
	if err != nil {
		return nil, err
	}

	oldIds, err := FetchMongoIdsByAccountIds(interactorIds)
	if err != nil {
		return nil, err
	}

	interactionContainer := NewInteractionContainer()
	interactionContainer.Actors = oldIds

	isInteracted, err := i.IsInteracted(query.AccountId)
	if err != nil {
		return nil, err
	}

	interactionContainer.IsInteracted = isInteracted

	if container.Interactions == nil {
		container.Interactions = make(map[string]*InteractionContainer)
	}
	if _, ok := container.Interactions["like"]; !ok {
		container.Interactions["like"] = NewInteractionContainer()
	}
	container.Interactions["like"] = interactionContainer
	return container, nil
}

func (c *ChannelMessage) BuildMessage(query *Query) (*ChannelMessageContainer, error) {
	cmc, err := c.FetchRelatives(query)
	if err != nil {
		return nil, err
	}

	mr := NewMessageReply()
	mr.MessageId = c.Id
	replies, err := mr.List()
	if err != nil {
		return nil, err
	}

	populatedChannelMessagesReplies := make([]*ChannelMessageContainer, len(replies))
	for rl := 0; rl < len(replies); rl++ {
		cmrc, err := replies[rl].FetchRelatives(query)
		if err != nil {
			return nil, err
		}
		populatedChannelMessagesReplies[rl] = cmrc
	}

	cmc.Replies = populatedChannelMessagesReplies
	return cmc, nil
}
<commit_msg>Social: add some function for channelMessage<commit_after>package models

import (
	"errors"
	"fmt"
	"socialapi/config"
	"time"

	"github.com/koding/bongo"
)

type ChannelMessage struct {
	// unique identifier of the channel message
	Id int64 `json:"id"`

	// Body of the mesage
	Body string `json:"body"`

	// Generated Slug for body
	Slug string `json:"slug"                        sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// type of the message
	TypeConstant string `json:"typeConstant"        sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creator of the channel message
	AccountId int64 `json:"accountId"               sql:"NOT NULL"`

	// in which channel this message is created
	InitialChannelId int64 `json:"initialChannelId" sql:"NOT NULL"`

	// Creation date of the message
	CreatedAt time.Time `json:"createdAt"           sql:"DEFAULT:CURRENT_TIMESTAMP"`

	// Modification date of the message
	UpdatedAt time.Time `json:"updatedAt"           sql:"DEFAULT:CURRENT_TIMESTAMP"`
}

func (c *ChannelMessage) AfterCreate() {
	bongo.B.AfterCreate(c)
}

func (c *ChannelMessage) AfterUpdate() {
	bongo.B.AfterUpdate(c)
}

func (c *ChannelMessage) AfterDelete() {
	bongo.B.AfterDelete(c)
}

func (c *ChannelMessage) GetId() int64 {
	return c.Id
}

func (c ChannelMessage) TableName() string {
	return "api.channel_message"
}

const (
	ChannelMessage_TYPE_POST  = "post"
	ChannelMessage_TYPE_REPLY = "reply"
	ChannelMessage_TYPE_JOIN  = "join"
	ChannelMessage_TYPE_LEAVE = "leave"
	ChannelMessage_TYPE_CHAT  = "chat"
)

func NewChannelMessage() *ChannelMessage {
	return &ChannelMessage{}
}

func (c *ChannelMessage) Fetch() error {
	return bongo.B.Fetch(c)
}

func (c *ChannelMessage) One(q *bongo.Query) error {
	return bongo.B.One(c, c, q)
}

func (c *ChannelMessage) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(c, data, q)
}

func bodyLenCheck(body string) error {
	if len(body) < config.Get().Limits.MessageBodyMinLen {
		return fmt.Errorf("Message Body Length should be greater than %d, yours is %d ", config.Get().Limits.MessageBodyMinLen, len(body))
	}
	return nil
}

func (c *ChannelMessage) Update() error {
	if err := bodyLenCheck(c.Body); err != nil {
		return err
	}
	// only update body
	err := bongo.B.UpdatePartial(c,
		map[string]interface{}{
			"body": c.Body,
		},
	)
	return err
}

func (c *ChannelMessage) Create() error {
	if err := bodyLenCheck(c.Body); err != nil {
		return err
	}

	var err error
	c, err = Slugify(c)
	if err != nil {
		return err
	}

	return bongo.B.Create(c)
}

func (c *ChannelMessage) Delete() error {
	return bongo.B.Delete(c)
}

func (c *ChannelMessage) FetchByIds(ids []int64) ([]ChannelMessage, error) {
	var messages []ChannelMessage

	if len(ids) == 0 {
		return messages, nil
	}

	if err := bongo.B.FetchByIds(c, &messages, ids); err != nil {
		return nil, err
	}
	return messages, nil
}

func (c *ChannelMessage) FetchRelatives(query *Query) (*ChannelMessageContainer, error) {
	if c.Id == 0 {
		return nil, errors.New("Channel message id is not set")
	}
	container := NewChannelMessageContainer()
	container.Message = c

	i := NewInteraction()
	i.MessageId = c.Id

	oldId, err := FetchMongoIdByAccountId(c.AccountId)
	if err != nil {
		return nil, err
	}

	container.AccountOldId = oldId

	interactorIds, err := i.List("like")
	if err != nil {
		return nil, err
	}

	oldIds, err := FetchMongoIdsByAccountIds(interactorIds)
	if err != nil {
		return nil, err
	}

	interactionContainer := NewInteractionContainer()
	interactionContainer.Actors = oldIds

	isInteracted, err := i.IsInteracted(query.AccountId)
	if err != nil {
		return nil, err
	}

	interactionContainer.IsInteracted = isInteracted

	if container.Interactions == nil {
		container.Interactions = make(map[string]*InteractionContainer)
	}
	if _, ok := container.Interactions["like"]; !ok {
		container.Interactions["like"] = NewInteractionContainer()
	}
	container.Interactions["like"] = interactionContainer
	return container, nil
}

func (c *ChannelMessage) BuildMessage(query *Query) (*ChannelMessageContainer, error) {
	cmc, err := c.FetchRelatives(query)
	if err != nil {
		return nil, err
	}

	mr := NewMessageReply()
	mr.MessageId = c.Id
	replies, err := mr.List()
	if err != nil {
		return nil, err
	}

	populatedChannelMessagesReplies := make([]*ChannelMessageContainer, len(replies))
	for rl := 0; rl < len(replies); rl++ {
		cmrc, err := replies[rl].FetchRelatives(query)
		if err != nil {
			return nil, err
		}
		populatedChannelMessagesReplies[rl] = cmrc
	}

	cmc.Replies = populatedChannelMessagesReplies
	return cmc, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"koding/db/mongodb/modelhelper"
	"socialapi/workers/common/runner"
	"socialapi/workers/migrator/controller"
)

var (
	Name = "Migrator"
)

func main() {
	r := runner.New(Name)
	if err := r.Init(); err != nil {
		fmt.Println(err)
		return
	}
	defer r.Close()

	modelhelper.Initialize(r.Conf.Mongo)

	handler, err := controller.New(r.Log)
	if err != nil {
		panic(err)
	}

	if err := handler.Start(); err != nil {
		panic(err)
	}

}
<commit_msg>Migration: Add scheduler support to migrator by adding -s flag<commit_after>package main

import (
	"flag"
	"fmt"
	"koding/db/mongodb/modelhelper"
	"socialapi/workers/common/runner"
	"socialapi/workers/migrator/controller"
)

var (
	Name         = "Migrator"
	flagSchedule = flag.Bool("s", false, "Schedule worker")
)

func main() {
	r := runner.New(Name)
	if err := r.Init(); err != nil {
		fmt.Println(err)
		return
	}
	defer r.Close()

	modelhelper.Initialize(r.Conf.Mongo)

	handler, err := controller.New(r.Log)
	if err != nil {
		panic(err)
	}

	if *flagSchedule {
		r.ShutdownHandler = handler.Shutdown
		if err := handler.Schedule(); err != nil {
			panic(err)
		}
		r.Wait()

		return
	}

	handler.Start()
}
<|endoftext|>


<commit_before>package presence

import "time"

// Ping holds the ping data
type Ping struct {
	// GroupName holds group name
	GroupName string `json:"channelID"`

	// AccountID holds the host's id the only one that can send this request
	AccountID int64 `json:"accountID,string"`

	// CreatedAt holds the ping time
	CreatedAt time.Time `json:"createdAt"`
}

// NewPing creates an empty ping
func NewPing() *Ping {
	return &Ping{}
}

// GetId returns the id of the ping, it is here just to satisfy Bongo.Modellable
// interface
func (a Ping) GetId() int64 {
	return 0
}

// BongoName returns the unique name for the bongo operations
func (a Ping) BongoName() string {
	return "presence.ping"
}
<commit_msg>go/presence: fix json tag<commit_after>package presence

import "time"

// Ping holds the ping data
type Ping struct {
	// GroupName holds group name
	GroupName string `json:"groupName"`

	// AccountID holds the host's id the only one that can send this request
	AccountID int64 `json:"accountID,string"`

	// CreatedAt holds the ping time
	CreatedAt time.Time `json:"createdAt"`
}

// NewPing creates an empty ping
func NewPing() *Ping {
	return &Ping{}
}

// GetId returns the id of the ping, it is here just to satisfy Bongo.Modellable
// interface
func (a Ping) GetId() int64 {
	return 0
}

// BongoName returns the unique name for the bongo operations
func (a Ping) BongoName() string {
	return "presence.ping"
}
<|endoftext|>


<commit_before>package routers

import (
	"github.com/astaxie/beego"
	"github.com/dockercn/docker-bucket/controllers"
)

func init() {
	//Web Interface
	beego.Router("/", &controllers.MainController{})
	beego.Router("/auth", &controllers.AuthController{}, "get:Get")
	beego.Router("/setting", &controllers.DashboardController{}, "get:GetSetting")
	beego.Router("/dashboard", &controllers.DashboardController{}, "get:GetDashboard")
	beego.Router("/admin", &controllers.AdminController{}, "get:GetAdmin")
	beego.Router("/p/:article", &controllers.ArticleController{}, "get:GetArticle")

	//Static File
	beego.Router("/favicon.ico", &controllers.StaticController{}, "get:GetFavicon")
	//TODO sitemap/rss/robots.txt

	web := beego.NewNamespace("/w1",
		beego.NSRouter("/signin", &controllers.AuthWebController{}, "post:Signin"),
		beego.NSRouter("/reset", &controllers.AuthWebController{}, "post:ResetPasswd"),
		beego.NSRouter("/signup", &controllers.AuthWebController{}, "post:Signup"),
		beego.NSRouter("/gravatar", &controllers.UsersWebController{}, "post:PostGravatar"),
	)

	//CI Service API
	drone := beego.NewNamespace("/d1",
		beego.NSRouter("/yaml", &controllers.DroneAPIController{}, "post:PostYAML"),
	)

	//Docker Registry API V1 remain
	beego.Router("/_ping", &controllers.PingAPIController{}, "get:GetPing")
	beego.Router("/_status", &controllers.StatusAPIController{})

	//Docker Registry API V1
	api := beego.NewNamespace("/v1",
		beego.NSRouter("/_ping", &controllers.PingAPIController{}, "get:GetPing"),
		beego.NSRouter("/_status", &controllers.StatusAPIController{}),
		beego.NSRouter("/users", &controllers.UsersAPIController{}, "get:GetUsers"),
		beego.NSRouter("/users", &controllers.UsersAPIController{}, "post:PostUsers"),

		beego.NSNamespace("/repositories",
			beego.NSRouter("/:namespace/:repo_name/tags/:tag", &controllers.RepositoryAPIController{}, "put:PutTag"),
			beego.NSRouter("/:namespace/:repo_name/images", &controllers.RepositoryAPIController{}, "put:PutRepositoryImages"),
			beego.NSRouter("/:namespace/:repo_name/images", &controllers.RepositoryAPIController{}, "get:GetRepositoryImages"),
			beego.NSRouter("/:namespace/:repo_name/tags", &controllers.RepositoryAPIController{}, "get:GetRepositoryTags"),
			beego.NSRouter("/:namespace/:repo_name", &controllers.RepositoryAPIController{}, "put:PutRepository"),
		),

		beego.NSNamespace("/images",
			beego.NSRouter("/:image_id/ancestry", &controllers.ImageAPIController{}, "get:GetImageAncestry"),
			beego.NSRouter("/:image_id/json", &controllers.ImageAPIController{}, "get:GetImageJSON"),
			beego.NSRouter("/:image_id/layer", &controllers.ImageAPIController{}, "get:GetImageLayer"),
			beego.NSRouter("/:image_id/json", &controllers.ImageAPIController{}, "put:PutImageJSON"),
			beego.NSRouter("/:image_id/layer", &controllers.ImageAPIController{}, "put:PutImageLayer"),
			beego.NSRouter("/:image_id/checksum", &controllers.ImageAPIController{}, "put:PutChecksum"),
		),
	)

	beego.AddNamespace(web)
	beego.AddNamespace(drone)
	beego.AddNamespace(api)
}
<commit_msg>增加用户退出路由<commit_after>package routers

import (
	"github.com/astaxie/beego"
	"github.com/dockercn/docker-bucket/controllers"
)

func init() {
	//Web Interface
	beego.Router("/", &controllers.MainController{})
	beego.Router("/auth", &controllers.AuthController{}, "get:Get")
	beego.Router("/signout", &controllers.AuthWebController{}, "get:Signout")
	beego.Router("/setting", &controllers.DashboardController{}, "get:GetSetting")
	beego.Router("/dashboard", &controllers.DashboardController{}, "get:GetDashboard")
	beego.Router("/admin", &controllers.AdminController{}, "get:GetAdmin")
	beego.Router("/p/:article", &controllers.ArticleController{}, "get:GetArticle")

	//Static File
	beego.Router("/favicon.ico", &controllers.StaticController{}, "get:GetFavicon")
	//TODO sitemap/rss/robots.txt

	web := beego.NewNamespace("/w1",
		beego.NSRouter("/signin", &controllers.AuthWebController{}, "post:Signin"),
		beego.NSRouter("/reset", &controllers.AuthWebController{}, "post:ResetPasswd"),
		beego.NSRouter("/signup", &controllers.AuthWebController{}, "post:Signup"),
		beego.NSRouter("/gravatar", &controllers.UsersWebController{}, "post:PostGravatar"),
	)

	//CI Service API
	drone := beego.NewNamespace("/d1",
		beego.NSRouter("/yaml", &controllers.DroneAPIController{}, "post:PostYAML"),
	)

	//Docker Registry API V1 remain
	beego.Router("/_ping", &controllers.PingAPIController{}, "get:GetPing")
	beego.Router("/_status", &controllers.StatusAPIController{})

	//Docker Registry API V1
	api := beego.NewNamespace("/v1",
		beego.NSRouter("/_ping", &controllers.PingAPIController{}, "get:GetPing"),
		beego.NSRouter("/_status", &controllers.StatusAPIController{}),
		beego.NSRouter("/users", &controllers.UsersAPIController{}, "get:GetUsers"),
		beego.NSRouter("/users", &controllers.UsersAPIController{}, "post:PostUsers"),

		beego.NSNamespace("/repositories",
			beego.NSRouter("/:namespace/:repo_name/tags/:tag", &controllers.RepositoryAPIController{}, "put:PutTag"),
			beego.NSRouter("/:namespace/:repo_name/images", &controllers.RepositoryAPIController{}, "put:PutRepositoryImages"),
			beego.NSRouter("/:namespace/:repo_name/images", &controllers.RepositoryAPIController{}, "get:GetRepositoryImages"),
			beego.NSRouter("/:namespace/:repo_name/tags", &controllers.RepositoryAPIController{}, "get:GetRepositoryTags"),
			beego.NSRouter("/:namespace/:repo_name", &controllers.RepositoryAPIController{}, "put:PutRepository"),
		),

		beego.NSNamespace("/images",
			beego.NSRouter("/:image_id/ancestry", &controllers.ImageAPIController{}, "get:GetImageAncestry"),
			beego.NSRouter("/:image_id/json", &controllers.ImageAPIController{}, "get:GetImageJSON"),
			beego.NSRouter("/:image_id/layer", &controllers.ImageAPIController{}, "get:GetImageLayer"),
			beego.NSRouter("/:image_id/json", &controllers.ImageAPIController{}, "put:PutImageJSON"),
			beego.NSRouter("/:image_id/layer", &controllers.ImageAPIController{}, "put:PutImageLayer"),
			beego.NSRouter("/:image_id/checksum", &controllers.ImageAPIController{}, "put:PutChecksum"),
		),
	)

	beego.AddNamespace(web)
	beego.AddNamespace(drone)
	beego.AddNamespace(api)
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// 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 zanzibar

import (
	"encoding/json"
	"net/http"

	"time"

	"github.com/uber-go/zap"
)

// ServerHTTPResponse struct manages request
type ServerHTTPResponse struct {
	responseWriter http.ResponseWriter
	req            *ServerHTTPRequest
	gateway        *Gateway
	finishTime     time.Time
	finished       bool
	metrics        *EndpointMetrics

	StatusCode int
}

// NewServerHTTPResponse is helper function to alloc ServerHTTPResponse
func NewServerHTTPResponse(
	w http.ResponseWriter, req *ServerHTTPRequest,
) *ServerHTTPResponse {
	res := &ServerHTTPResponse{
		gateway:        req.gateway,
		req:            req,
		responseWriter: w,
		StatusCode:     200,
		metrics:        req.metrics,
	}

	return res
}

// finish will handle final logic, like metrics
func (res *ServerHTTPResponse) finish() {
	if !res.req.started {
		/* coverage ignore next line */
		res.req.Logger.Error(
			"Forgot to start incoming request",
			zap.String("path", res.req.URL.Path),
		)
		/* coverage ignore next line */
		return
	}
	if res.finished {
		/* coverage ignore next line */
		res.req.Logger.Error(
			"Finished an incoming request twice",
			zap.String("path", res.req.URL.Path),
		)
		/* coverage ignore next line */
		return
	}

	res.finished = true
	res.finishTime = time.Now()

	counter := res.metrics.statusCodes[res.StatusCode]
	if counter == nil {
		res.req.Logger.Error(
			"Could not emit statusCode metric",
			zap.Int("UnexpectedStatusCode", res.StatusCode),
		)
	} else {
		counter.Inc(1)
	}

	res.metrics.requestLatency.Record(
		res.finishTime.Sub(res.req.startTime),
	)
}

// SendError helper to send an error
func (res *ServerHTTPResponse) SendError(statusCode int, err error) {
	res.SendErrorString(statusCode, err.Error())
}

// SendErrorString helper to send an error string
func (res *ServerHTTPResponse) SendErrorString(
	statusCode int, err string,
) {
	res.req.Logger.Warn(
		"Sending error for endpoint request",
		zap.String("error", err),
		zap.String("path", res.req.URL.Path),
	)

	res.writeHeader(statusCode)
	res.writeString(err)

	res.finish()
}

// WriteJSONBytes writes a byte[] slice that is valid json to Response
func (res *ServerHTTPResponse) WriteJSONBytes(
	statusCode int, bytes []byte,
) {
	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	res.writeBytes(bytes)

	res.finish()
}

// WriteJSON writes a json serializable struct to Response
func (res *ServerHTTPResponse) WriteJSON(
	statusCode int, body json.Marshaler,
) {
	if body == nil {
		res.SendErrorString(500, "Could not serialize json response")
		res.req.Logger.Error("Could not serialize nil pointer body")
		return
	}

	bytes, err := body.MarshalJSON()
	if err != nil {
		res.SendErrorString(500, "Could not serialize json response")
		res.req.Logger.Error("Could not serialize json response",
			zap.String("error", err.Error()),
		)
		return
	}

	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	res.writeBytes(bytes)

	res.finish()
}

func (res *ServerHTTPResponse) writeHeader(statusCode int) {
	res.StatusCode = statusCode
	res.responseWriter.WriteHeader(statusCode)
}

// WriteBytes writes raw bytes to output
func (res *ServerHTTPResponse) writeBytes(bytes []byte) {
	_, err := res.responseWriter.Write(bytes)
	if err != nil {
		res.req.Logger.Error("Could not write string to resp body",
			zap.String("error", err.Error()),
		)
	}
}

// WriteHeader writes the header to http respnse.
func (res *ServerHTTPResponse) WriteHeader(statusCode int) {
	res.writeHeader(statusCode)
}

// WriteString helper just writes a string to the response
func (res *ServerHTTPResponse) writeString(text string) {
	res.writeBytes([]byte(text))
}

// IsOKResponse checks if the status code is OK.
func (res *ServerHTTPResponse) IsOKResponse(
	statusCode int, okResponses []int,
) bool {
	for _, r := range okResponses {
		if statusCode == r {
			return true
		}
	}
	return false
}
<commit_msg>runtime/ServerResponse: do not use WriteHeader<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// 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 zanzibar

import (
	"encoding/json"
	"net/http"

	"time"

	"github.com/uber-go/zap"
)

// ServerHTTPResponse struct manages request
type ServerHTTPResponse struct {
	responseWriter http.ResponseWriter
	req            *ServerHTTPRequest
	gateway        *Gateway
	finishTime     time.Time
	finished       bool
	metrics        *EndpointMetrics

	StatusCode int
}

// NewServerHTTPResponse is helper function to alloc ServerHTTPResponse
func NewServerHTTPResponse(
	w http.ResponseWriter, req *ServerHTTPRequest,
) *ServerHTTPResponse {
	res := &ServerHTTPResponse{
		gateway:        req.gateway,
		req:            req,
		responseWriter: w,
		StatusCode:     200,
		metrics:        req.metrics,
	}

	return res
}

// finish will handle final logic, like metrics
func (res *ServerHTTPResponse) finish() {
	if !res.req.started {
		/* coverage ignore next line */
		res.req.Logger.Error(
			"Forgot to start incoming request",
			zap.String("path", res.req.URL.Path),
		)
		/* coverage ignore next line */
		return
	}
	if res.finished {
		/* coverage ignore next line */
		res.req.Logger.Error(
			"Finished an incoming request twice",
			zap.String("path", res.req.URL.Path),
		)
		/* coverage ignore next line */
		return
	}

	res.finished = true
	res.finishTime = time.Now()

	counter := res.metrics.statusCodes[res.StatusCode]
	if counter == nil {
		res.req.Logger.Error(
			"Could not emit statusCode metric",
			zap.Int("UnexpectedStatusCode", res.StatusCode),
		)
	} else {
		counter.Inc(1)
	}

	res.metrics.requestLatency.Record(
		res.finishTime.Sub(res.req.startTime),
	)
}

// SendError helper to send an error
func (res *ServerHTTPResponse) SendError(statusCode int, err error) {
	res.SendErrorString(statusCode, err.Error())
}

// SendErrorString helper to send an error string
func (res *ServerHTTPResponse) SendErrorString(
	statusCode int, err string,
) {
	res.req.Logger.Warn(
		"Sending error for endpoint request",
		zap.String("error", err),
		zap.String("path", res.req.URL.Path),
	)

	res.writeHeader(statusCode)
	res.writeString(err)

	res.finish()
}

// WriteJSONBytes writes a byte[] slice that is valid json to Response
func (res *ServerHTTPResponse) WriteJSONBytes(
	statusCode int, bytes []byte,
) {
	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	res.writeBytes(bytes)

	res.finish()
}

// WriteJSON writes a json serializable struct to Response
func (res *ServerHTTPResponse) WriteJSON(
	statusCode int, body json.Marshaler,
) {
	if body == nil {
		res.SendErrorString(500, "Could not serialize json response")
		res.req.Logger.Error("Could not serialize nil pointer body")
		return
	}

	bytes, err := body.MarshalJSON()
	if err != nil {
		res.SendErrorString(500, "Could not serialize json response")
		res.req.Logger.Error("Could not serialize json response",
			zap.String("error", err.Error()),
		)
		return
	}

	res.responseWriter.Header().Set("content-type", "application/json")
	res.writeHeader(statusCode)
	res.writeBytes(bytes)

	res.finish()
}

func (res *ServerHTTPResponse) writeHeader(statusCode int) {
	res.StatusCode = statusCode
	res.responseWriter.WriteHeader(statusCode)
}

// WriteBytes writes raw bytes to output
func (res *ServerHTTPResponse) writeBytes(bytes []byte) {
	_, err := res.responseWriter.Write(bytes)
	if err != nil {
		res.req.Logger.Error("Could not write string to resp body",
			zap.String("error", err.Error()),
		)
	}
}

// WriteString helper just writes a string to the response
func (res *ServerHTTPResponse) writeString(text string) {
	res.writeBytes([]byte(text))
}

// IsOKResponse checks if the status code is OK.
func (res *ServerHTTPResponse) IsOKResponse(
	statusCode int, okResponses []int,
) bool {
	for _, r := range okResponses {
		if statusCode == r {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package codec

import (
	"encoding/json"
	"fmt"
	"net"
	"time"

	"github.com/ethereum/go-ethereum/rpc/shared"
)

const (
	MAX_REQUEST_SIZE  = 1024 * 1024
	MAX_RESPONSE_SIZE = 1024 * 1024
)

// Json serialization support
type JsonCodec struct {
	c             net.Conn
	buffer        []byte
	bytesInBuffer int
}

// Create new JSON coder instance
func NewJsonCoder(conn net.Conn) ApiCoder {
	return &JsonCodec{
		c:             conn,
		buffer:        make([]byte, MAX_REQUEST_SIZE),
		bytesInBuffer: 0,
	}
}

// Serialize obj to JSON and write it to conn
func (self *JsonCodec) ReadRequest() (requests []*shared.Request, isBatch bool, err error) {
	n, err := self.c.Read(self.buffer[self.bytesInBuffer:])
	if err != nil {
		self.bytesInBuffer = 0
		return nil, false, err
	}

	self.bytesInBuffer += n

	singleRequest := shared.Request{}
	err = json.Unmarshal(self.buffer[:self.bytesInBuffer], &singleRequest)
	if err == nil {
		self.bytesInBuffer = 0
		requests := make([]*shared.Request, 1)
		requests[0] = &singleRequest
		return requests, false, nil
	}

	requests = make([]*shared.Request, 0)
	err = json.Unmarshal(self.buffer[:self.bytesInBuffer], &requests)
	if err == nil {
		self.bytesInBuffer = 0
		return requests, true, nil
	}

	return nil, false, err
}

func (self *JsonCodec) ReadResponse() (interface{}, error) {
	bytesInBuffer := 0
	buf := make([]byte, MAX_RESPONSE_SIZE)

	deadline := time.Now().Add(15 * time.Second)
	self.c.SetDeadline(deadline)

	for {
		n, err := self.c.Read(buf[bytesInBuffer:])
		if err != nil {
			return nil, err
		}
		bytesInBuffer += n

		var success shared.SuccessResponse
		if err = json.Unmarshal(buf[:bytesInBuffer], &success); err == nil {
			return success, nil
		}

		var failure shared.ErrorResponse
		if err = json.Unmarshal(buf[:bytesInBuffer], &failure); err == nil && failure.Error != nil {
			return failure, nil
		}
	}

	self.c.Close()
	return nil, fmt.Errorf("Unable to read response")
}

// Decode data
func (self *JsonCodec) Decode(data []byte, msg interface{}) error {
	return json.Unmarshal(data, msg)
}

// Encode message
func (self *JsonCodec) Encode(msg interface{}) ([]byte, error) {
	return json.Marshal(msg)
}

// Parse JSON data from conn to obj
func (self *JsonCodec) WriteResponse(res interface{}) error {
	data, err := json.Marshal(res)
	if err != nil {
		self.c.Close()
		return err
	}

	bytesWritten := 0

	for bytesWritten < len(data) {
		n, err := self.c.Write(data[bytesWritten:])
		if err != nil {
			self.c.Close()
			return err
		}
		bytesWritten += n
	}

	return nil
}

// Close decoder and encoder
func (self *JsonCodec) Close() {
	self.c.Close()
}
<commit_msg>added IPC timeout support<commit_after>package codec

import (
	"encoding/json"
	"fmt"
	"net"
	"time"

	"github.com/ethereum/go-ethereum/rpc/shared"
)

const (
	READ_TIMEOUT      = 15 // read timeout in seconds
	MAX_REQUEST_SIZE  = 1024 * 1024
	MAX_RESPONSE_SIZE = 1024 * 1024
)

// Json serialization support
type JsonCodec struct {
	c net.Conn
}

// Create new JSON coder instance
func NewJsonCoder(conn net.Conn) ApiCoder {
	return &JsonCodec{
		c: conn,
	}
}

// Serialize obj to JSON and write it to conn
func (self *JsonCodec) ReadRequest() (requests []*shared.Request, isBatch bool, err error) {
	bytesInBuffer := 0
	buf := make([]byte, MAX_REQUEST_SIZE)

	deadline := time.Now().Add(READ_TIMEOUT * time.Second)
	if err := self.c.SetDeadline(deadline); err != nil {
		return nil, false, err
	}

	for {
		n, err := self.c.Read(buf[bytesInBuffer:])
		if err != nil {
			self.c.Close()
			return nil, false, err
		}

		bytesInBuffer += n

		singleRequest := shared.Request{}
		err = json.Unmarshal(buf[:bytesInBuffer], &singleRequest)
		if err == nil {
			requests := make([]*shared.Request, 1)
			requests[0] = &singleRequest
			return requests, false, nil
		}

		requests = make([]*shared.Request, 0)
		err = json.Unmarshal(buf[:bytesInBuffer], &requests)
		if err == nil {
			return requests, true, nil
		}
	}

	self.c.Close() // timeout
	return nil, false, fmt.Errorf("Unable to read response")
}

func (self *JsonCodec) ReadResponse() (interface{}, error) {
	bytesInBuffer := 0
	buf := make([]byte, MAX_RESPONSE_SIZE)

	deadline := time.Now().Add(READ_TIMEOUT * time.Second)
	if err := self.c.SetDeadline(deadline); err != nil {
		return nil, err
	}

	for {
		n, err := self.c.Read(buf[bytesInBuffer:])
		if err != nil {
			return nil, err
		}
		bytesInBuffer += n

		var success shared.SuccessResponse
		if err = json.Unmarshal(buf[:bytesInBuffer], &success); err == nil {
			return success, nil
		}

		var failure shared.ErrorResponse
		if err = json.Unmarshal(buf[:bytesInBuffer], &failure); err == nil && failure.Error != nil {
			return failure, nil
		}
	}

	self.c.Close()
	return nil, fmt.Errorf("Unable to read response")
}

// Decode data
func (self *JsonCodec) Decode(data []byte, msg interface{}) error {
	return json.Unmarshal(data, msg)
}

// Encode message
func (self *JsonCodec) Encode(msg interface{}) ([]byte, error) {
	return json.Marshal(msg)
}

// Parse JSON data from conn to obj
func (self *JsonCodec) WriteResponse(res interface{}) error {
	data, err := json.Marshal(res)
	if err != nil {
		self.c.Close()
		return err
	}

	bytesWritten := 0

	for bytesWritten < len(data) {
		n, err := self.c.Write(data[bytesWritten:])
		if err != nil {
			self.c.Close()
			return err
		}
		bytesWritten += n
	}

	return nil
}

// Close decoder and encoder
func (self *JsonCodec) Close() {
	self.c.Close()
}
<|endoftext|>


<commit_before>package docker

import (
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/fsouza/go-dockerclient"
	"github.com/remind101/empire/pkg/bytesize"
	"github.com/remind101/empire/scheduler"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

var ctx = context.Background()

func TestScheduler_InstancesFromAttachedRuns(t *testing.T) {
	d := new(mockDockerClient)
	s := Scheduler{
		docker: d,
	}

	d.On("ListContainers", docker.ListContainersOptions{
		Filters: map[string][]string{
			"label": []string{
				"attached-run=true",
				"empire.app.id=2cdc4941-e36d-4855-a0ec-51525db4a500",
			},
		},
	}).Return([]docker.APIContainers{
		{ID: "65311c2cc20d671d43118b7d42b3f02df6b48a6bb65b1c5939007214e7587b24"},
	}, nil)

	d.On("InspectContainer", "65311c2cc20d671d43118b7d42b3f02df6b48a6bb65b1c5939007214e7587b24").Return(&docker.Container{
		ID: "65311c2cc20d671d43118b7d42b3f02df6b48a6bb65b1c5939007214e7587b24",
		State: docker.State{
			Running:   true,
			StartedAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
		},
		Config: &docker.Config{
			Labels: map[string]string{
				"attached-run":       "true",
				"empire.app.id":      "2cdc4941-e36d-4855-a0ec-51525db4a500",
				"empire.app.process": "run",
			},
			Cmd: []string{"/bin/sh"},
			Env: []string{"FOO=bar"},
		},
		HostConfig: &docker.HostConfig{
			Memory:    int64(124 * bytesize.MB),
			CPUShares: 512,
		},
	}, nil)

	instances, err := s.InstancesFromAttachedRuns(ctx, "2cdc4941-e36d-4855-a0ec-51525db4a500")
	assert.NoError(t, err)
	assert.Equal(t, 1, len(instances))
	assert.Equal(t, &scheduler.Instance{
		Process: &scheduler.Process{
			Type:    "run",
			Command: []string{"/bin/sh"},
			Env: map[string]string{
				"FOO": "bar",
			},
			MemoryLimit: 124 * bytesize.MB,
			CPUShares:   512,
		},
		ID:        "65311c2cc20d",
		State:     "RUNNING",
		UpdatedAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
	}, instances[0])

	d.AssertExpectations(t)
}

func TestScheduler_Stop(t *testing.T) {
	d := new(mockDockerClient)
	s := Scheduler{
		docker: d,
	}

	d.On("StopContainer", "container_id", uint(30)).Return(nil)

	err := s.Stop(ctx, "container_id")
	assert.NoError(t, err)

	d.AssertExpectations(t)
}

func TestParseEnv(t *testing.T) {
	tests := []struct {
		in  []string
		out map[string]string
	}{
		{[]string{"FOO=bar"}, map[string]string{"FOO": "bar"}},
	}

	for _, tt := range tests {
		out := parseEnv(tt.in)
		assert.Equal(t, tt.out, out)
	}
}

type mockDockerClient struct {
	dockerClient
	mock.Mock
}

func (m *mockDockerClient) ListContainers(opts docker.ListContainersOptions) ([]docker.APIContainers, error) {
	args := m.Called(opts)
	return args.Get(0).([]docker.APIContainers), args.Error(1)
}

func (m *mockDockerClient) InspectContainer(id string) (*docker.Container, error) {
	args := m.Called(id)
	return args.Get(0).(*docker.Container), args.Error(1)
}

func (m *mockDockerClient) StopContainer(ctx context.Context, id string, timeout uint) error {
	args := m.Called(id, timeout)
	return args.Error(0)
}
<commit_msg>Adds test for attachedScheduler.Stop.<commit_after>package docker

import (
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/fsouza/go-dockerclient"
	"github.com/remind101/empire/pkg/bytesize"
	"github.com/remind101/empire/scheduler"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

var ctx = context.Background()

func TestScheduler_InstancesFromAttachedRuns(t *testing.T) {
	d := new(mockDockerClient)
	s := Scheduler{
		docker: d,
	}

	d.On("ListContainers", docker.ListContainersOptions{
		Filters: map[string][]string{
			"label": []string{
				"attached-run=true",
				"empire.app.id=2cdc4941-e36d-4855-a0ec-51525db4a500",
			},
		},
	}).Return([]docker.APIContainers{
		{ID: "65311c2cc20d671d43118b7d42b3f02df6b48a6bb65b1c5939007214e7587b24"},
	}, nil)

	d.On("InspectContainer", "65311c2cc20d671d43118b7d42b3f02df6b48a6bb65b1c5939007214e7587b24").Return(&docker.Container{
		ID: "65311c2cc20d671d43118b7d42b3f02df6b48a6bb65b1c5939007214e7587b24",
		State: docker.State{
			Running:   true,
			StartedAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
		},
		Config: &docker.Config{
			Labels: map[string]string{
				"attached-run":       "true",
				"empire.app.id":      "2cdc4941-e36d-4855-a0ec-51525db4a500",
				"empire.app.process": "run",
			},
			Cmd: []string{"/bin/sh"},
			Env: []string{"FOO=bar"},
		},
		HostConfig: &docker.HostConfig{
			Memory:    int64(124 * bytesize.MB),
			CPUShares: 512,
		},
	}, nil)

	instances, err := s.InstancesFromAttachedRuns(ctx, "2cdc4941-e36d-4855-a0ec-51525db4a500")
	assert.NoError(t, err)
	assert.Equal(t, 1, len(instances))
	assert.Equal(t, &scheduler.Instance{
		Process: &scheduler.Process{
			Type:    "run",
			Command: []string{"/bin/sh"},
			Env: map[string]string{
				"FOO": "bar",
			},
			MemoryLimit: 124 * bytesize.MB,
			CPUShares:   512,
		},
		ID:        "65311c2cc20d",
		State:     "RUNNING",
		UpdatedAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
	}, instances[0])

	d.AssertExpectations(t)
}

func TestScheduler_Stop(t *testing.T) {
	d := new(mockDockerClient)
	s := Scheduler{
		docker: d,
	}

	d.On("StopContainer", "container_id", uint(10)).Return(nil)

	err := s.Stop(ctx, "container_id")
	assert.NoError(t, err)

	d.AssertExpectations(t)
}

func TestAttachedScheduler_Stop_ContainerNotFound(t *testing.T) {
	w := new(mockScheduler)
	d := new(mockDockerClient)
	ds := &Scheduler{
		docker: d,
	}
	s := &attachedScheduler{
		Scheduler:       w,
		dockerScheduler: ds,
	}

	d.On("StopContainer", "d9ad8d2f-318d-4abd-9d58-ece9a5ca423c", uint(10)).Return(&docker.NoSuchContainer{
		ID: "d9ad8d2f-318d-4abd-9d58-ece9a5ca423c",
	})

	w.On("Stop", "d9ad8d2f-318d-4abd-9d58-ece9a5ca423c").Return(nil)

	err := s.Stop(ctx, "d9ad8d2f-318d-4abd-9d58-ece9a5ca423c")
	assert.NoError(t, err)

	d.AssertExpectations(t)
	w.AssertExpectations(t)
}

func TestParseEnv(t *testing.T) {
	tests := []struct {
		in  []string
		out map[string]string
	}{
		{[]string{"FOO=bar"}, map[string]string{"FOO": "bar"}},
	}

	for _, tt := range tests {
		out := parseEnv(tt.in)
		assert.Equal(t, tt.out, out)
	}
}

type mockDockerClient struct {
	dockerClient
	mock.Mock
}

func (m *mockDockerClient) ListContainers(opts docker.ListContainersOptions) ([]docker.APIContainers, error) {
	args := m.Called(opts)
	return args.Get(0).([]docker.APIContainers), args.Error(1)
}

func (m *mockDockerClient) InspectContainer(id string) (*docker.Container, error) {
	args := m.Called(id)
	return args.Get(0).(*docker.Container), args.Error(1)
}

func (m *mockDockerClient) StopContainer(ctx context.Context, id string, timeout uint) error {
	args := m.Called(id, timeout)
	return args.Error(0)
}

type mockScheduler struct {
	scheduler.Scheduler
	mock.Mock
}

func (m *mockScheduler) Stop(ctx context.Context, id string) error {
	args := m.Called(id)
	return args.Error(0)
}
<|endoftext|>


<commit_before>package asm

import (
	"bytes"
	"strings"
	"testing"
)

// test assembly code
var testAsm = `

// This is a comment.
@256

// This is also a comment.
D=M
@i
MD=0
@j
AD=D|M;JGE
@i
AMD=D+1;JLT
@j
M+1;JLT

(LOOP)
	@17 // indent spaces
	D=A // indent tab

	@LOOP
	D;JEQ

(END)
	@END
	0;JMP
`

// expected binary code converted from testAsm
var wantHack = `0000000100000000
1111110000010000
0000000000010000
1110101010011000
0000000000010001
1111010101110011
0000000000010000
1110011111111100
0000000000010001
1111110111000100
0000000000010001
1110110000010000
0000000000001010
1110001100000010
0000000000001111
1110101010000111
`

func TestDefineSymbols(t *testing.T) {
	symtbl := map[string]uintptr{
		"SP":     0x0,
		"LCL":    0x1,
		"ARG":    0x2,
		"THIS":   0x3,
		"THAT":   0x4,
		"R0":     0x0,
		"R4":     0x4,
		"R5":     0x5,
		"R15":    0xF,
		"SCREEN": 0x4000,
		"KBD":    0x6000,
	}

	asmblr, err := New(strings.NewReader(testAsm))
	if err != nil {
		t.Fatalf("New failed: %s", err.Error())
	}

	asmblr.DefineSymbols(symtbl)

	for symb, addr := range symtbl {
		got := asmblr.st.GetAddress(symb)
		if got != addr {
			t.Errorf("got = 0x%X; want = 0x%X", got, addr)
		}
	}
}

func TestRun(t *testing.T) {
	runTests := []struct {
		src  string
		want string
	}{
		{"@1", "0000000000000001\n"},
		{"@256", "0000000100000000\n"},
		{"(LOOP)", ""},
		{"(END)", ""},
		{"A=!A", "1110110001100000\n"},
		{"M=M-D", "1111000111001000\n"},
		{"1;JMP", "1110111111000111\n"},
		{"A-1;JNE", "1110110010000101\n"},
		{"AM=D&A;JLE", "1110000000101110\n"},
		{"@i\n@j", "0000000000010000\n0000000000010001\n"},
		{"(LOOP)\nD=0\n@LOOP", "1110101010010000\n0000000000000000\n"},
		{"@32\nM=1\n@a\nMD=-1",
			"0000000000100000\n1110111111001000\n0000000000010000\n1110111010011000\n"},
		{testAsm, wantHack},
	}

	for _, tt := range runTests {
		var out bytes.Buffer
		asmblr, err := New(strings.NewReader(tt.src))
		if err != nil {
			t.Fatalf("New failed: %s", err.Error())
		}

		if e := asmblr.Run(&out); e != nil {
			t.Fatalf("%s", e.Error())
		}

		got := out.String()
		if got != tt.want {
			t.Errorf("\nsrc:\n%s\n\ngot:\n%s\nwant:\n%s", tt.src, got, tt.want)
		}
	}
}
<commit_msg>06/assembler/asm: add test case where @LABEL appear before (LABEL)<commit_after>package asm

import (
	"bytes"
	"strings"
	"testing"
)

// test assembly code
var testAsm = `

// This is a comment.
@256

// This is also a comment.
D=M
@i
MD=0
@j
AD=D|M;JGE
@i
AMD=D+1;JLT
@j
M+1;JLT
@END
D;JLE

(LOOP)
	@17 // indent spaces
	D=A // indent tab

	@LOOP
	D;JEQ

(END)
	@END
	0;JMP
`

// expected binary code converted from testAsm
var wantHack = `0000000100000000
1111110000010000
0000000000010000
1110101010011000
0000000000010001
1111010101110011
0000000000010000
1110011111111100
0000000000010001
1111110111000100
0000000000010001
1110001100000110
0000000000010001
1110110000010000
0000000000001100
1110001100000010
0000000000010001
1110101010000111
`

func TestDefineSymbols(t *testing.T) {
	symtbl := map[string]uintptr{
		"SP":     0x0,
		"LCL":    0x1,
		"ARG":    0x2,
		"THIS":   0x3,
		"THAT":   0x4,
		"R0":     0x0,
		"R4":     0x4,
		"R5":     0x5,
		"R15":    0xF,
		"SCREEN": 0x4000,
		"KBD":    0x6000,
	}

	asmblr, err := New(strings.NewReader(testAsm))
	if err != nil {
		t.Fatalf("New failed: %s", err.Error())
	}

	asmblr.DefineSymbols(symtbl)

	for symb, addr := range symtbl {
		got := asmblr.st.GetAddress(symb)
		if got != addr {
			t.Errorf("got = 0x%X; want = 0x%X", got, addr)
		}
	}
}

func TestRun(t *testing.T) {
	runTests := []struct {
		src  string
		want string
	}{
		{"@1", "0000000000000001\n"},
		{"@256", "0000000100000000\n"},
		{"(LOOP)", ""},
		{"(END)", ""},
		{"A=!A", "1110110001100000\n"},
		{"M=M-D", "1111000111001000\n"},
		{"1;JMP", "1110111111000111\n"},
		{"A-1;JNE", "1110110010000101\n"},
		{"AM=D&A;JLE", "1110000000101110\n"},
		{"@i\n@j", "0000000000010000\n0000000000010001\n"},
		{"(LOOP)\nD=0\n@LOOP", "1110101010010000\n0000000000000000\n"},
		{"@32\nM=1\n@a\nMD=-1",
			"0000000000100000\n1110111111001000\n0000000000010000\n1110111010011000\n"},
		{testAsm, wantHack},
	}

	for _, tt := range runTests {
		var out bytes.Buffer
		asmblr, err := New(strings.NewReader(tt.src))
		if err != nil {
			t.Fatalf("New failed: %s", err.Error())
		}

		if e := asmblr.Run(&out); e != nil {
			t.Fatalf("%s", e.Error())
		}

		got := strings.Split(out.String(), "\n")
		want := strings.Split(tt.want, "\n")
		if len(got) != len(want) {
			t.Fatalf("the number of lines should be %d, but got %d", len(want), len(got))
		}
		for i := range got {
			if got[i] != want[i] {
				t.Errorf("\nsrc:\n%s\n\nline %d: got: %s != want: %s", tt.src, i+1, got[i], want[i])
			}
		}
	}
}
<|endoftext|>


<commit_before>package kana

import (
	"strings"
	"unicode"
)

type Kana struct {
	kanaToRomajiTrie     *Trie
	romajiToHiraganaTrie *Trie
	romajiToKatakanaTrie *Trie
}

var consonants []string = []string{"b", "d", "f", "g", "h", "j", "k", "l", "m", "p", "r", "s", "t", "w", "z"}

func NewKana() *Kana {
	/*
	   Build a trie for efficient retrieval of entries
	*/
	kana := &Kana{newTrie(), newTrie(), newTrie()}
	kana.initialize()
	return kana
}

func (k *Kana) initialize() {
	/*
		Build the Hiragana + Katakana trie.

		Because there is no overlap between the hiragana and katakana sets,
		they both use the same trie without conflict. Nice bonus!
	*/
	tables := []string{HiraganaTable, KatakanaTable}
	for t, table := range tables {
		rows := strings.Split(table, "\n")
		colNames := strings.Split(string(rows[0]), "\t")[1:]
		for _, row := range rows[1:] {
			cols := strings.Split(string(row), "\t")
			rowName := cols[0]
			for i, kana := range cols[1:] {
				value := rowName + colNames[i]
				kanas := strings.Split(kana, "/")
				for _, singleKana := range kanas {
					if singleKana != "" {
						// add to tries
						k.kanaToRomajiTrie.insert(singleKana, value)
						if t == 0 {
							k.romajiToHiraganaTrie.insert(value, singleKana)
						} else if t == 1 {
							k.romajiToKatakanaTrie.insert(value, singleKana)
						}
					}
				}
			}
		}
	}
}

func (k Kana) KanaToRomaji(kana string) (romaji string) {
	romaji = k.kanaToRomajiTrie.convert(kana)

	// do some post-processing for the tsu and stripe characters
	// maybe a bit of a hacky solution - how can we improve?
	// (they act more like punctuation)
	tsus := []string{"っ", "ッ"}
	for _, tsu := range tsus {
		for i := strings.Index(romaji, tsu); i > -1; i = strings.Index(romaji, tsu) {
			rune_romaji := []rune(romaji)
			if len(rune_romaji) > i+2 {
				// TODO: should check if following letter is consonant
				followingLetter := string(rune_romaji[i+1 : i+2])
				romaji = strings.Replace(romaji, tsu, followingLetter, 1)
			} else {
				romaji = strings.Replace(romaji, tsu, "", 1)
			}
		}
	}

	line := "ー"
	for i := strings.Index(romaji, line); i > -1; i = strings.Index(romaji, line) {
		rune_romaji := []rune(romaji)
		if i > 0 {
			// TODO: should check if following letter is consonant
			previousLetter := string(rune_romaji[i-1 : i])
			romaji = strings.Replace(romaji, line, previousLetter, 1)
		} else {
			romaji = strings.Replace(romaji, line, "", 1)
		}
	}

	return romaji
}

func replace_tsus(romaji string, tsu string) (result string) {
	result = romaji
	for _, consonant := range consonants {
		result = strings.Replace(result, consonant+consonant, tsu+consonant, -1)
	}
	return result
}

func (k Kana) RomajiToHiragana(romaji string) (hiragana string) {
	romaji = strings.Replace(romaji, "-", "ー", -1)
	romaji = replace_tsus(romaji, "っ")
	hiragana = k.romajiToHiraganaTrie.convert(romaji)
	return hiragana
}

func (k Kana) RomajiToKatakana(romaji string) (katakana string) {
	romaji = strings.Replace(romaji, "-", "ー", -1)
	// convert double consonants to little tsus first
	romaji = replace_tsus(romaji, "ッ")
	katakana = k.romajiToKatakanaTrie.convert(romaji)
	return katakana
}

func (k Kana) IsLatin(s string) bool {
	isLatin := true
	runeForm := []rune(s)
	for _, r := range runeForm {
		isLatin = isLatin && unicode.IsOneOf([]*unicode.RangeTable{unicode.Latin, unicode.ASCII_Hex_Digit, unicode.White_Space}, r)
		if !isLatin {
			return isLatin
		}
	}
	return isLatin
}

func (k Kana) IsKana(s string) bool{
	isKana := true
	runeForm := []rune(s)
	for _, r := range runeForm {
		isKana = isKana && unicode.IsOneOf([]*unicode.RangeTable{unicode.Hiragana, unicode.Katakana, unicode.Hyphen, unicode.Diacritic}, r)
		if !isKana {
			return isKana
		}
	}
	return isKana
}

func (k Kana) IsKanji(s string) bool {
	isKanji := true
	runeForm := []rune(s)
	for _, r := range runeForm {
		isKanji = isKanji && unicode.IsOneOf([]*unicode.RangeTable{unicode.Ideographic}, r)
		if !isKanji {
			return isKanji
		}
	}
	return isKanji
}
<commit_msg>allow hyphens in isLatin<commit_after>package kana

import (
	"strings"
	"unicode"
)

type Kana struct {
	kanaToRomajiTrie     *Trie
	romajiToHiraganaTrie *Trie
	romajiToKatakanaTrie *Trie
}

var consonants []string = []string{"b", "d", "f", "g", "h", "j", "k", "l", "m", "p", "r", "s", "t", "w", "z"}

func NewKana() *Kana {
	/*
	   Build a trie for efficient retrieval of entries
	*/
	kana := &Kana{newTrie(), newTrie(), newTrie()}
	kana.initialize()
	return kana
}

func (k *Kana) initialize() {
	/*
		Build the Hiragana + Katakana trie.

		Because there is no overlap between the hiragana and katakana sets,
		they both use the same trie without conflict. Nice bonus!
	*/
	tables := []string{HiraganaTable, KatakanaTable}
	for t, table := range tables {
		rows := strings.Split(table, "\n")
		colNames := strings.Split(string(rows[0]), "\t")[1:]
		for _, row := range rows[1:] {
			cols := strings.Split(string(row), "\t")
			rowName := cols[0]
			for i, kana := range cols[1:] {
				value := rowName + colNames[i]
				kanas := strings.Split(kana, "/")
				for _, singleKana := range kanas {
					if singleKana != "" {
						// add to tries
						k.kanaToRomajiTrie.insert(singleKana, value)
						if t == 0 {
							k.romajiToHiraganaTrie.insert(value, singleKana)
						} else if t == 1 {
							k.romajiToKatakanaTrie.insert(value, singleKana)
						}
					}
				}
			}
		}
	}
}

func (k Kana) KanaToRomaji(kana string) (romaji string) {
	romaji = k.kanaToRomajiTrie.convert(kana)

	// do some post-processing for the tsu and stripe characters
	// maybe a bit of a hacky solution - how can we improve?
	// (they act more like punctuation)
	tsus := []string{"っ", "ッ"}
	for _, tsu := range tsus {
		for i := strings.Index(romaji, tsu); i > -1; i = strings.Index(romaji, tsu) {
			rune_romaji := []rune(romaji)
			if len(rune_romaji) > i+2 {
				// TODO: should check if following letter is consonant
				followingLetter := string(rune_romaji[i+1 : i+2])
				romaji = strings.Replace(romaji, tsu, followingLetter, 1)
			} else {
				romaji = strings.Replace(romaji, tsu, "", 1)
			}
		}
	}

	line := "ー"
	for i := strings.Index(romaji, line); i > -1; i = strings.Index(romaji, line) {
		rune_romaji := []rune(romaji)
		if i > 0 {
			// TODO: should check if following letter is consonant
			previousLetter := string(rune_romaji[i-1 : i])
			romaji = strings.Replace(romaji, line, previousLetter, 1)
		} else {
			romaji = strings.Replace(romaji, line, "", 1)
		}
	}

	return romaji
}

func replace_tsus(romaji string, tsu string) (result string) {
	result = romaji
	for _, consonant := range consonants {
		result = strings.Replace(result, consonant+consonant, tsu+consonant, -1)
	}
	return result
}

func (k Kana) RomajiToHiragana(romaji string) (hiragana string) {
	romaji = strings.Replace(romaji, "-", "ー", -1)
	romaji = replace_tsus(romaji, "っ")
	hiragana = k.romajiToHiraganaTrie.convert(romaji)
	return hiragana
}

func (k Kana) RomajiToKatakana(romaji string) (katakana string) {
	romaji = strings.Replace(romaji, "-", "ー", -1)
	// convert double consonants to little tsus first
	romaji = replace_tsus(romaji, "ッ")
	katakana = k.romajiToKatakanaTrie.convert(romaji)
	return katakana
}

func (k Kana) IsLatin(s string) bool {
	isLatin := true
	runeForm := []rune(s)
	for _, r := range runeForm {
		isLatin = isLatin && unicode.IsOneOf([]*unicode.RangeTable{unicode.Latin, unicode.ASCII_Hex_Digit, unicode.White_Space, unicode.Hyphen}, r)
		if !isLatin {
			return isLatin
		}
	}
	return isLatin
}

func (k Kana) IsKana(s string) bool{
	isKana := true
	runeForm := []rune(s)
	for _, r := range runeForm {
		isKana = isKana && unicode.IsOneOf([]*unicode.RangeTable{unicode.Hiragana, unicode.Katakana, unicode.Hyphen, unicode.Diacritic}, r)
		if !isKana {
			return isKana
		}
	}
	return isKana
}

func (k Kana) IsKanji(s string) bool {
	isKanji := true
	runeForm := []rune(s)
	for _, r := range runeForm {
		isKanji = isKanji && unicode.IsOneOf([]*unicode.RangeTable{unicode.Ideographic}, r)
		if !isKanji {
			return isKanji
		}
	}
	return isKanji
}
<|endoftext|>


<commit_before>/* Copyright 2016-2017 Vector Creations Ltd
 *
 * 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 gomatrixserverlib

import (
	"encoding/json"
	"strings"
	"time"
)

// ServerKeys are the ed25519 signing keys published by a matrix server.
// Contains SHA256 fingerprints of the TLS X509 certificates used by the server.
type ServerKeys struct {
	// Copy of the raw JSON for signature checking.
	Raw []byte
	// The decoded JSON fields.
	ServerKeyFields
}

// A TLSFingerprint is a SHA256 hash of an X509 certificate.
type TLSFingerprint struct {
	SHA256 Base64Bytes `json:"sha256"`
}

// A VerifyKey is a ed25519 public key for a server.
type VerifyKey struct {
	// The public key.
	Key Base64Bytes `json:"key"`
}

// An OldVerifyKey is an old ed25519 public key that is no longer valid.
type OldVerifyKey struct {
	VerifyKey
	// When this key stopped being valid for event signing in milliseconds.
	ExpiredTS Timestamp `json:"expired_ts"`
}

// ServerKeyFields are the parsed JSON contents of the ed25519 signing keys published by a matrix server.
type ServerKeyFields struct {
	// The name of the server
	ServerName ServerName `json:"server_name"`
	// List of SHA256 fingerprints of X509 certificates used by this server.
	TLSFingerprints []TLSFingerprint `json:"tls_fingerprints"`
	// The current signing keys in use on this server.
	// The keys of the map are the IDs of the keys.
	// These are valid while this response is valid.
	VerifyKeys map[KeyID]VerifyKey `json:"verify_keys"`
	// When this result is valid until in milliseconds.
	ValidUntilTS Timestamp `json:"valid_until_ts"`
	// Old keys that are now only valid for checking historic events.
	// The keys of the map are the IDs of the keys.
	OldVerifyKeys map[KeyID]OldVerifyKey `json:"old_verify_keys"`
}

// UnmarshalJSON implements json.Unmarshaler
func (keys *ServerKeys) UnmarshalJSON(data []byte) error {
	keys.Raw = data
	return json.Unmarshal(data, &keys.ServerKeyFields)
}

// MarshalJSON implements json.Marshaler
func (keys ServerKeys) MarshalJSON() ([]byte, error) {
	if len(keys.Raw) == 0 {
		js, err := json.Marshal(keys.ServerKeyFields)
		if err != nil {
			return nil, err
		}
		return js, nil
	}
	// We already have a copy of the serialised JSON for the keys so we can return that directly.
	return keys.Raw, nil
}

// PublicKey returns a public key with the given ID valid at the given TS or nil if no such key exists.
func (keys ServerKeys) PublicKey(keyID KeyID, atTS Timestamp) []byte {
	if currentKey, ok := keys.VerifyKeys[keyID]; ok && (atTS <= keys.ValidUntilTS) {
		return currentKey.Key
	}
	if oldKey, ok := keys.OldVerifyKeys[keyID]; ok && (atTS <= oldKey.ExpiredTS) {
		return oldKey.Key
	}
	return nil
}

// Ed25519Checks are the checks that are applied to Ed25519 keys in ServerKey responses.
type Ed25519Checks struct {
	ValidEd25519      bool // The verify key is valid Ed25519 keys.
	MatchingSignature bool // The verify key has a valid signature.
}

// KeyChecks are the checks that should be applied to ServerKey responses.
type KeyChecks struct {
	AllChecksOK        bool                    // Did all the checks pass?
	MatchingServerName bool                    // Does the server name match what was requested.
	FutureValidUntilTS bool                    // The valid until TS is in the future.
	HasEd25519Key      bool                    // The server has at least one ed25519 key.
	AllEd25519ChecksOK *bool                   // All the Ed25519 checks are ok. or null if there weren't any to check.
	Ed25519Checks      map[KeyID]Ed25519Checks // Checks for Ed25519 keys.
}

// CheckKeys checks the keys returned from a server to make sure they are valid.
// If the checks pass then also return a map of key_id to Ed25519 public key
func CheckKeys(
	serverName ServerName,
	now time.Time,
	keys ServerKeys,
) (
	checks KeyChecks,
	ed25519Keys map[KeyID]Base64Bytes,
) {
	checks.MatchingServerName = serverName == keys.ServerName
	checks.FutureValidUntilTS = keys.ValidUntilTS.Time().After(now)
	checks.AllChecksOK = checks.MatchingServerName && checks.FutureValidUntilTS

	ed25519Keys = checkVerifyKeys(keys, &checks)

	if !checks.AllChecksOK {
		ed25519Keys = nil
	}
	return
}

func checkVerifyKeys(keys ServerKeys, checks *KeyChecks) map[KeyID]Base64Bytes {
	allEd25519ChecksOK := true
	checks.Ed25519Checks = map[KeyID]Ed25519Checks{}
	verifyKeys := map[KeyID]Base64Bytes{}
	for keyID, keyData := range keys.VerifyKeys {
		algorithm := strings.SplitN(string(keyID), ":", 2)[0]
		publicKey := keyData.Key
		if algorithm == "ed25519" {
			checks.HasEd25519Key = true
			checks.AllEd25519ChecksOK = &allEd25519ChecksOK
			entry := Ed25519Checks{
				ValidEd25519: len(publicKey) == 32,
			}
			if entry.ValidEd25519 {
				err := VerifyJSON(string(keys.ServerName), keyID, []byte(publicKey), keys.Raw)
				entry.MatchingSignature = err == nil
			}
			checks.Ed25519Checks[keyID] = entry
			if entry.MatchingSignature {
				verifyKeys[keyID] = publicKey
			} else {
				allEd25519ChecksOK = false
			}
		}
	}
	if checks.AllChecksOK {
		checks.AllChecksOK = checks.HasEd25519Key && allEd25519ChecksOK
	}
	return verifyKeys
}
<commit_msg>Omit tls_fingerprints from server keys when empty (#223)<commit_after>/* Copyright 2016-2017 Vector Creations Ltd
 *
 * 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 gomatrixserverlib

import (
	"encoding/json"
	"strings"
	"time"
)

// ServerKeys are the ed25519 signing keys published by a matrix server.
// Contains SHA256 fingerprints of the TLS X509 certificates used by the server.
type ServerKeys struct {
	// Copy of the raw JSON for signature checking.
	Raw []byte
	// The decoded JSON fields.
	ServerKeyFields
}

// A TLSFingerprint is a SHA256 hash of an X509 certificate.
type TLSFingerprint struct {
	SHA256 Base64Bytes `json:"sha256"`
}

// A VerifyKey is a ed25519 public key for a server.
type VerifyKey struct {
	// The public key.
	Key Base64Bytes `json:"key"`
}

// An OldVerifyKey is an old ed25519 public key that is no longer valid.
type OldVerifyKey struct {
	VerifyKey
	// When this key stopped being valid for event signing in milliseconds.
	ExpiredTS Timestamp `json:"expired_ts"`
}

// ServerKeyFields are the parsed JSON contents of the ed25519 signing keys published by a matrix server.
type ServerKeyFields struct {
	// The name of the server
	ServerName ServerName `json:"server_name"`
	// List of SHA256 fingerprints of X509 certificates used by this server.
	TLSFingerprints []TLSFingerprint `json:"tls_fingerprints,omitempty"`
	// The current signing keys in use on this server.
	// The keys of the map are the IDs of the keys.
	// These are valid while this response is valid.
	VerifyKeys map[KeyID]VerifyKey `json:"verify_keys"`
	// When this result is valid until in milliseconds.
	ValidUntilTS Timestamp `json:"valid_until_ts"`
	// Old keys that are now only valid for checking historic events.
	// The keys of the map are the IDs of the keys.
	OldVerifyKeys map[KeyID]OldVerifyKey `json:"old_verify_keys"`
}

// UnmarshalJSON implements json.Unmarshaler
func (keys *ServerKeys) UnmarshalJSON(data []byte) error {
	keys.Raw = data
	return json.Unmarshal(data, &keys.ServerKeyFields)
}

// MarshalJSON implements json.Marshaler
func (keys ServerKeys) MarshalJSON() ([]byte, error) {
	if len(keys.Raw) == 0 {
		js, err := json.Marshal(keys.ServerKeyFields)
		if err != nil {
			return nil, err
		}
		return js, nil
	}
	// We already have a copy of the serialised JSON for the keys so we can return that directly.
	return keys.Raw, nil
}

// PublicKey returns a public key with the given ID valid at the given TS or nil if no such key exists.
func (keys ServerKeys) PublicKey(keyID KeyID, atTS Timestamp) []byte {
	if currentKey, ok := keys.VerifyKeys[keyID]; ok && (atTS <= keys.ValidUntilTS) {
		return currentKey.Key
	}
	if oldKey, ok := keys.OldVerifyKeys[keyID]; ok && (atTS <= oldKey.ExpiredTS) {
		return oldKey.Key
	}
	return nil
}

// Ed25519Checks are the checks that are applied to Ed25519 keys in ServerKey responses.
type Ed25519Checks struct {
	ValidEd25519      bool // The verify key is valid Ed25519 keys.
	MatchingSignature bool // The verify key has a valid signature.
}

// KeyChecks are the checks that should be applied to ServerKey responses.
type KeyChecks struct {
	AllChecksOK        bool                    // Did all the checks pass?
	MatchingServerName bool                    // Does the server name match what was requested.
	FutureValidUntilTS bool                    // The valid until TS is in the future.
	HasEd25519Key      bool                    // The server has at least one ed25519 key.
	AllEd25519ChecksOK *bool                   // All the Ed25519 checks are ok. or null if there weren't any to check.
	Ed25519Checks      map[KeyID]Ed25519Checks // Checks for Ed25519 keys.
}

// CheckKeys checks the keys returned from a server to make sure they are valid.
// If the checks pass then also return a map of key_id to Ed25519 public key
func CheckKeys(
	serverName ServerName,
	now time.Time,
	keys ServerKeys,
) (
	checks KeyChecks,
	ed25519Keys map[KeyID]Base64Bytes,
) {
	checks.MatchingServerName = serverName == keys.ServerName
	checks.FutureValidUntilTS = keys.ValidUntilTS.Time().After(now)
	checks.AllChecksOK = checks.MatchingServerName && checks.FutureValidUntilTS

	ed25519Keys = checkVerifyKeys(keys, &checks)

	if !checks.AllChecksOK {
		ed25519Keys = nil
	}
	return
}

func checkVerifyKeys(keys ServerKeys, checks *KeyChecks) map[KeyID]Base64Bytes {
	allEd25519ChecksOK := true
	checks.Ed25519Checks = map[KeyID]Ed25519Checks{}
	verifyKeys := map[KeyID]Base64Bytes{}
	for keyID, keyData := range keys.VerifyKeys {
		algorithm := strings.SplitN(string(keyID), ":", 2)[0]
		publicKey := keyData.Key
		if algorithm == "ed25519" {
			checks.HasEd25519Key = true
			checks.AllEd25519ChecksOK = &allEd25519ChecksOK
			entry := Ed25519Checks{
				ValidEd25519: len(publicKey) == 32,
			}
			if entry.ValidEd25519 {
				err := VerifyJSON(string(keys.ServerName), keyID, []byte(publicKey), keys.Raw)
				entry.MatchingSignature = err == nil
			}
			checks.Ed25519Checks[keyID] = entry
			if entry.MatchingSignature {
				verifyKeys[keyID] = publicKey
			} else {
				allEd25519ChecksOK = false
			}
		}
	}
	if checks.AllChecksOK {
		checks.AllChecksOK = checks.HasEd25519Key && allEd25519ChecksOK
	}
	return verifyKeys
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

var origTermios *Termios

/*** terminal ***/

func die(err error) {
	disableRawMode()
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting termial attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() byte {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]);
		cc != 1;
		cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	return buffer[0]
}

/*** input ***/

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		disableRawMode()
		os.Exit(0)
	}
}

/*** output ***/

func editorRefreshScreen() {
	io.WriteString(os.Stdout, "\x1b[2J");
}

/*** init ***/

func main() {
	enableRawMode()
	defer disableRawMode()

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<commit_msg>Step 23<commit_after>package main

import (
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

var origTermios *Termios

/*** terminal ***/

func die(err error) {
	disableRawMode()
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting termial attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() byte {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]);
		cc != 1;
		cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	return buffer[0]
}

/*** input ***/

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		disableRawMode()
		os.Exit(0)
	}
}

/*** output ***/

func editorRefreshScreen() {
	io.WriteString(os.Stdout, "\x1b[2J");
	io.WriteString(os.Stdout, "\x1b[H");
}

/*** init ***/

func main() {
	enableRawMode()
	defer disableRawMode()

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** defines ***/

const KILO_VERSION = "0.0.1"
const (
	ARROW_LEFT  = 1000 + iota
	ARROW_RIGHT = 1000 + iota
	ARROW_UP    = 1000 + iota
	ARROW_DOWN  = 1000 + iota
	DEL_KEY     = 1000 + iota
	HOME_KEY    = 1000 + iota
	END_KEY     = 1000 + iota
	PAGE_UP     = 1000 + iota
	PAGE_DOWN   = 1000 + iota
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

type erow struct {
	chars []byte
}

type editorConfig struct {
	cx          int
	cy          int
	screenRows  int
	screenCols  int
	numRows     int
	rows        []erow
	origTermios *Termios
}

type WinSize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

var E editorConfig

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	// TCSETS+1 == TCSETSW, because TCSAFLUSH doesn't exist
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting terminal attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	E.origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *E.origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), E.origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() int {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]); cc != 1; cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	if buffer[0] == '\x1b' {
		var seq [2]byte
		if cc, _ = os.Stdin.Read(seq[:]); cc != 2 {
			return '\x1b'
		}

		if seq[0] == '[' {
			if seq[1] >= '0' && seq[1] <= '9' {
				if cc, err = os.Stdin.Read(buffer[:]); cc != 1 {
					return '\x1b'
				}
				if buffer[0] == '~' {
					switch seq[1] {
					case '1':
						return HOME_KEY
					case '3':
						return DEL_KEY
					case '4':
						return END_KEY
					case '5':
						return PAGE_UP
					case '6':
						return PAGE_DOWN
					case '7':
						return HOME_KEY
					case '8':
						return END_KEY
					}
				}
				// XXX - what happens here?
			} else {
				switch seq[1] {
				case 'A':
					return ARROW_UP
				case 'B':
					return ARROW_DOWN
				case 'C':
					return ARROW_RIGHT
				case 'D':
					return ARROW_LEFT
				case 'H':
					return HOME_KEY
				case 'F':
					return END_KEY
				}
			}
		} else if seq[0] == '0' {
			switch seq[1] {
			case 'H':
				return HOME_KEY
			case 'F':
				return END_KEY
			}
		}

		return '\x1b'
	}
	return int(buffer[0])
}

func getCursorPosition(rows *int, cols *int) int {
	io.WriteString(os.Stdout, "\x1b[6n")
	var buffer [1]byte
	var buf []byte
	var cc int
	for cc, _ = os.Stdin.Read(buffer[:]); cc == 1; cc, _ = os.Stdin.Read(buffer[:]) {
		if buffer[0] == 'R' {
			break
		}
		buf = append(buf, buffer[0])
	}
	if string(buf[0:2]) != "\x1b[" {
		log.Printf("Failed to read rows;cols from tty\n")
		return -1
	}
	if n, e := fmt.Sscanf(string(buf[2:]), "%d;%d", rows, cols); n != 2 || e != nil {
		if e != nil {
			log.Printf("getCursorPosition: fmt.Sscanf() failed: %s\n", e)
		}
		if n != 2 {
			log.Printf("getCursorPosition: got %d items, wanted 2\n", n)
		}
		return -1
	}
	return 0
}

func getWindowSize(rows *int, cols *int) int {
	var w WinSize
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		os.Stdout.Fd(),
		syscall.TIOCGWINSZ,
		uintptr(unsafe.Pointer(&w)),
	)
	if err != 0 { // type syscall.Errno
		io.WriteString(os.Stdout, "\x1b[999C\x1b[999B")
		return getCursorPosition(rows, cols)
	} else {
		*rows = int(w.Row)
		*cols = int(w.Col)
		return 0
	}
	return -1
}

/*** row operations ***/

func editorAppendRow(s []byte) {
	var r erow
	r.chars = s
	E.rows = append(E.rows, r)
	E.numRows++
}

/*** file I/O ***/

func editorOpen(filename string) {
	fd, err := os.Open(filename)
	if err != nil {
		die(err)
	}
	defer fd.Close()
	fp := bufio.NewReader(fd)

	line, err := fp.ReadBytes('\n')
	if err != nil {
		die(err)
	}

	for c := line[len(line) - 1]; len(line) > 0 && (c == '\n' || c == '\r'); line = line[:len(line)-1] {
	}

	editorAppendRow(line)
}

/*** input ***/

func editorMoveCursor(key int) {
	switch key {
	case ARROW_LEFT:
		if E.cx != 0 {
			E.cx--
		}
	case ARROW_RIGHT:
		if E.cx != E.screenCols-1 {
			E.cx++
		}
	case ARROW_UP:
		if E.cy != 0 {
			E.cy--
		}
	case ARROW_DOWN:
		if E.cy != E.screenRows-1 {
			E.cy++
		}
	}
}

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J")
		io.WriteString(os.Stdout, "\x1b[H")
		disableRawMode()
		os.Exit(0)
	case HOME_KEY:
		E.cx = 0
	case END_KEY:
		E.cx = E.screenCols - 1
	case PAGE_UP, PAGE_DOWN:
		dir := ARROW_DOWN
		if c == PAGE_UP {
			dir = ARROW_UP
		}
		for times := E.screenRows; times > 0; times-- {
			editorMoveCursor(dir)
		}
	case ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT:
		editorMoveCursor(c)
	}
}

/*** append buffer ***/

type abuf struct {
	buf []byte
}

func (p abuf) String() string {
	return string(p.buf)
}

func (p *abuf) abAppend(s string) {
	p.buf = append(p.buf, []byte(s)...)
}

func (p *abuf) abAppendBytes(b []byte) {
	p.buf = append(p.buf, b...)
}

/*** output ***/

func editorRefreshScreen() {
	var ab abuf
	ab.abAppend("\x1b[25l")
	ab.abAppend("\x1b[H")
	editorDrawRows(&ab)
	ab.abAppend(fmt.Sprintf("\x1b[%d;%dH", E.cy+1, E.cx+1))
	ab.abAppend("\x1b[25h")
	io.WriteString(os.Stdout, ab.String())
}

func editorDrawRows(ab *abuf) {
	for y := 0; y < E.screenRows-1; y++ {
		if y >= E.numRows {
			if E.numRows == 0 && y == E.screenRows/3 {
				w := fmt.Sprintf("Kilo editor -- version %s", KILO_VERSION)
				if len(w) > E.screenCols {
					w = w[0:E.screenCols]
				}
				pad := "~ "
				for padding := (E.screenCols - len(w)) / 2; padding > 0; padding-- {
					ab.abAppend(pad)
					pad = " "
				}
				ab.abAppend(w)
			} else {
				ab.abAppend("~")
			}
		} else {
			length := len(E.rows.chars)
			if length > E.screenCols { length = E.screenCols }
			ab.abAppendBytes(E.rows.chars[:length])
		}
		ab.abAppend("\x1b[K")
		if y < E.screenRows-1 {
			ab.abAppend("\r\n")
		}
	}
}

/*** init ***/

func initEditor() {
	// Initialization a la C not necessary.
	if getWindowSize(&E.screenRows, &E.screenCols) == -1 {
		die(fmt.Errorf("couldn't get screen size"))
	}
}

func main() {
	enableRawMode()
	defer disableRawMode()
	initEditor()
	if len(os.Args) > 1 {
		editorOpen(os.Args[1])
	}

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<commit_msg>Step 65<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"syscall"
	"unsafe"
)

/*** defines ***/

const KILO_VERSION = "0.0.1"
const (
	ARROW_LEFT  = 1000 + iota
	ARROW_RIGHT = 1000 + iota
	ARROW_UP    = 1000 + iota
	ARROW_DOWN  = 1000 + iota
	DEL_KEY     = 1000 + iota
	HOME_KEY    = 1000 + iota
	END_KEY     = 1000 + iota
	PAGE_UP     = 1000 + iota
	PAGE_DOWN   = 1000 + iota
)

/*** data ***/

type Termios struct {
	Iflag  uint32
	Oflag  uint32
	Cflag  uint32
	Lflag  uint32
	Cc     [20]byte
	Ispeed uint32
	Ospeed uint32
}

type erow struct {
	chars []byte
}

type editorConfig struct {
	cx          int
	cy          int
	screenRows  int
	screenCols  int
	numRows     int
	rows        []erow
	origTermios *Termios
}

type WinSize struct {
	Row    uint16
	Col    uint16
	Xpixel uint16
	Ypixel uint16
}

var E editorConfig

/*** terminal ***/

func die(err error) {
	disableRawMode()
	io.WriteString(os.Stdout, "\x1b[2J")
	io.WriteString(os.Stdout, "\x1b[H")
	log.Fatal(err)
}

func TcSetAttr(fd uintptr, termios *Termios) error {
	// TCSETS+1 == TCSETSW, because TCSAFLUSH doesn't exist
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TCSETS+1), uintptr(unsafe.Pointer(termios))); err != 0 {
		return err
	}
	return nil
}

func TcGetAttr(fd uintptr) *Termios {
	var termios = &Termios{}
	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, syscall.TCGETS, uintptr(unsafe.Pointer(termios))); err != 0 {
		log.Fatalf("Problem getting terminal attributes: %s\n", err)
	}
	return termios
}

func enableRawMode() {
	E.origTermios = TcGetAttr(os.Stdin.Fd())
	var raw Termios
	raw = *E.origTermios
	raw.Iflag &^= syscall.BRKINT | syscall.ICRNL | syscall.INPCK | syscall.ISTRIP | syscall.IXON
	raw.Oflag &^= syscall.OPOST
	raw.Cflag |= syscall.CS8
	raw.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.IEXTEN | syscall.ISIG
	raw.Cc[syscall.VMIN+1] = 0
	raw.Cc[syscall.VTIME+1] = 1
	if e := TcSetAttr(os.Stdin.Fd(), &raw); e != nil {
		log.Fatalf("Problem enabling raw mode: %s\n", e)
	}
}

func disableRawMode() {
	if e := TcSetAttr(os.Stdin.Fd(), E.origTermios); e != nil {
		log.Fatalf("Problem disabling raw mode: %s\n", e)
	}
}

func editorReadKey() int {
	var buffer [1]byte
	var cc int
	var err error
	for cc, err = os.Stdin.Read(buffer[:]); cc != 1; cc, err = os.Stdin.Read(buffer[:]) {
	}
	if err != nil {
		die(err)
	}
	if buffer[0] == '\x1b' {
		var seq [2]byte
		if cc, _ = os.Stdin.Read(seq[:]); cc != 2 {
			return '\x1b'
		}

		if seq[0] == '[' {
			if seq[1] >= '0' && seq[1] <= '9' {
				if cc, err = os.Stdin.Read(buffer[:]); cc != 1 {
					return '\x1b'
				}
				if buffer[0] == '~' {
					switch seq[1] {
					case '1':
						return HOME_KEY
					case '3':
						return DEL_KEY
					case '4':
						return END_KEY
					case '5':
						return PAGE_UP
					case '6':
						return PAGE_DOWN
					case '7':
						return HOME_KEY
					case '8':
						return END_KEY
					}
				}
				// XXX - what happens here?
			} else {
				switch seq[1] {
				case 'A':
					return ARROW_UP
				case 'B':
					return ARROW_DOWN
				case 'C':
					return ARROW_RIGHT
				case 'D':
					return ARROW_LEFT
				case 'H':
					return HOME_KEY
				case 'F':
					return END_KEY
				}
			}
		} else if seq[0] == '0' {
			switch seq[1] {
			case 'H':
				return HOME_KEY
			case 'F':
				return END_KEY
			}
		}

		return '\x1b'
	}
	return int(buffer[0])
}

func getCursorPosition(rows *int, cols *int) int {
	io.WriteString(os.Stdout, "\x1b[6n")
	var buffer [1]byte
	var buf []byte
	var cc int
	for cc, _ = os.Stdin.Read(buffer[:]); cc == 1; cc, _ = os.Stdin.Read(buffer[:]) {
		if buffer[0] == 'R' {
			break
		}
		buf = append(buf, buffer[0])
	}
	if string(buf[0:2]) != "\x1b[" {
		log.Printf("Failed to read rows;cols from tty\n")
		return -1
	}
	if n, e := fmt.Sscanf(string(buf[2:]), "%d;%d", rows, cols); n != 2 || e != nil {
		if e != nil {
			log.Printf("getCursorPosition: fmt.Sscanf() failed: %s\n", e)
		}
		if n != 2 {
			log.Printf("getCursorPosition: got %d items, wanted 2\n", n)
		}
		return -1
	}
	return 0
}

func getWindowSize(rows *int, cols *int) int {
	var w WinSize
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		os.Stdout.Fd(),
		syscall.TIOCGWINSZ,
		uintptr(unsafe.Pointer(&w)),
	)
	if err != 0 { // type syscall.Errno
		io.WriteString(os.Stdout, "\x1b[999C\x1b[999B")
		return getCursorPosition(rows, cols)
	} else {
		*rows = int(w.Row)
		*cols = int(w.Col)
		return 0
	}
	return -1
}

/*** row operations ***/

func editorAppendRow(s []byte) {
	var r erow
	r.chars = s
	E.rows = append(E.rows, r)
	E.numRows++
}

/*** file I/O ***/

func editorOpen(filename string) {
	fd, err := os.Open(filename)
	if err != nil {
		die(err)
	}
	defer fd.Close()
	fp := bufio.NewReader(fd)

	for line, err := fp.ReadBytes('\n'); err == nil; line, err = fp.ReadBytes('\n') {
		// Trim trailing newlines and carriage returns
		for c := line[len(line) - 1]; len(line) > 0 && (c == '\n' || c == '\r'); {
			line = line[:len(line)-1]
			if len(line) > 0 {
				c = line[len(line) - 1]
			}
		}
		editorAppendRow(line)
	}

	if err != nil && err != io.EOF {
		die(err)
	}
}

/*** input ***/

func editorMoveCursor(key int) {
	switch key {
	case ARROW_LEFT:
		if E.cx != 0 {
			E.cx--
		}
	case ARROW_RIGHT:
		if E.cx != E.screenCols-1 {
			E.cx++
		}
	case ARROW_UP:
		if E.cy != 0 {
			E.cy--
		}
	case ARROW_DOWN:
		if E.cy != E.screenRows-1 {
			E.cy++
		}
	}
}

func editorProcessKeypress() {
	c := editorReadKey()
	switch c {
	case ('q' & 0x1f):
		io.WriteString(os.Stdout, "\x1b[2J")
		io.WriteString(os.Stdout, "\x1b[H")
		disableRawMode()
		os.Exit(0)
	case HOME_KEY:
		E.cx = 0
	case END_KEY:
		E.cx = E.screenCols - 1
	case PAGE_UP, PAGE_DOWN:
		dir := ARROW_DOWN
		if c == PAGE_UP {
			dir = ARROW_UP
		}
		for times := E.screenRows; times > 0; times-- {
			editorMoveCursor(dir)
		}
	case ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT:
		editorMoveCursor(c)
	}
}

/*** append buffer ***/

type abuf struct {
	buf []byte
}

func (p abuf) String() string {
	return string(p.buf)
}

func (p *abuf) abAppend(s string) {
	p.buf = append(p.buf, []byte(s)...)
}

func (p *abuf) abAppendBytes(b []byte) {
	p.buf = append(p.buf, b...)
}

/*** output ***/

func editorRefreshScreen() {
	var ab abuf
	ab.abAppend("\x1b[25l")
	ab.abAppend("\x1b[H")
	editorDrawRows(&ab)
	ab.abAppend(fmt.Sprintf("\x1b[%d;%dH", E.cy+1, E.cx+1))
	ab.abAppend("\x1b[25h")
	_, e := io.WriteString(os.Stdout, ab.String())
	if e != nil {
		log.Fatal(e)
	}
}

func editorDrawRows(ab *abuf) {
	for y := 0; y < E.screenRows; y++ {
		if y >= E.numRows {
			if E.numRows == 0 && y == E.screenRows/3 {
				w := fmt.Sprintf("Kilo editor -- version %s", KILO_VERSION)
				if len(w) > E.screenCols {
					w = w[0:E.screenCols]
				}
				pad := "~ "
				for padding := (E.screenCols - len(w)) / 2; padding > 0; padding-- {
					ab.abAppend(pad)
					pad = " "
				}
				ab.abAppend(w)
			} else {
				ab.abAppend("~")
			}
		} else {
			length := len(E.rows[y].chars)
			if length > E.screenCols { length = E.screenCols }
			ab.abAppendBytes(E.rows[y].chars[:length])
		}
		ab.abAppend("\x1b[K")
		if y < E.screenRows-1 {
			ab.abAppend("\r\n")
		}
	}
}

/*** init ***/

func initEditor() {
	// Initialization a la C not necessary.
	if getWindowSize(&E.screenRows, &E.screenCols) == -1 {
		die(fmt.Errorf("couldn't get screen size"))
	}
}

func main() {
	enableRawMode()
	defer disableRawMode()
	initEditor()
	if len(os.Args) > 1 {
		editorOpen(os.Args[1])
	}

	for {
		editorRefreshScreen()
		editorProcessKeypress()
	}
}
<|endoftext|>