<commit_before>package hashmap

import (
	"bytes"
	"fmt"
	"reflect"
	"sync"
	"sync/atomic"
	"unsafe"
)

// MaxFillRate is the maximum fill rate for the slice before a resize  will happen.
const MaxFillRate = 50

type (
	hashMapData struct {
		keyRightShifts uint64         // 64 - log2 of array size, to be used as index in the data array
		data           unsafe.Pointer // pointer to slice data array
		slice          []*ListElement // storage for the slice for the garbage collector to not clean it up
		count          uint64         // count of filled elements in the slice
	}

	// HashMap implements a read optimized hash map.
	HashMap struct {
		mapData    unsafe.Pointer // pointer to a map instance that gets replaced if the map resizes
		linkedList *List          // key sorted linked list of elements
		sync.Mutex                // mutex that is only used for resize operations
	}

	// KeyValue represents a key/value that is returned by the iterator.
	KeyValue struct {
		Key   interface{}
		Value unsafe.Pointer
	}
)

// New returns a new HashMap.
func New() *HashMap {
	return NewSize(8)
}

// NewSize returns a new HashMap instance with a specific initialization size.
func NewSize(size uint64) *HashMap {
	hashmap := &HashMap{
		linkedList: NewList(),
	}
	hashmap.Grow(size)
	return hashmap
}

// Len returns the number of elements within the map.
func (m *HashMap) Len() uint64 {
	return m.linkedList.Len()
}

// Fillrate returns the fill rate of the map as an percentage integer.
func (m *HashMap) Fillrate() uint64 {
	mapData := (*hashMapData)(atomic.LoadPointer(&m.mapData))
	count := atomic.LoadUint64(&mapData.count)
	sliceLen := uint64(len(mapData.slice))
	return (count * 100) / sliceLen
}

func (m *HashMap) getSliceItemForKey(hashedKey uint64) (mapData *hashMapData, item *ListElement) {
	mapData = (*hashMapData)(atomic.LoadPointer(&m.mapData))
	index := hashedKey >> mapData.keyRightShifts
	sliceDataIndexPointer := (*unsafe.Pointer)(unsafe.Pointer(uintptr(mapData.data) + uintptr(index*intSizeBytes)))
	item = (*ListElement)(atomic.LoadPointer(sliceDataIndexPointer))
	return
}

// Get retrieves an element from the map under given hash key.
func (m *HashMap) Get(hashedKey uint64) (unsafe.Pointer, bool) {
	// inline HashMap.getSliceItemForKey()
	mapData := (*hashMapData)(atomic.LoadPointer(&m.mapData))
	index := hashedKey >> mapData.keyRightShifts
	sliceDataIndexPointer := (*unsafe.Pointer)(unsafe.Pointer(uintptr(mapData.data) + uintptr(index*intSizeBytes)))
	entry := (*ListElement)(atomic.LoadPointer(sliceDataIndexPointer))

	for entry != nil {
		if entry.keyHash == hashedKey {
			if atomic.LoadUint64(&entry.deleted) == 1 { // inline ListElement.Deleted()
				return nil, false
			}
			return atomic.LoadPointer(&entry.value), true // inline ListElement.Value()
		}

		if entry.keyHash > hashedKey {
			return nil, false
		}

		entry = (*ListElement)(atomic.LoadPointer(&entry.nextElement)) // inline ListElement.Next()
	}
	return nil, false
}

// Del deletes the hashed key from the map.
func (m *HashMap) Del(hashedKey uint64) {
	for _, entry := m.getSliceItemForKey(hashedKey); entry != nil; entry = entry.Next() {
		if entry.keyHash == hashedKey {
			m.linkedList.Delete(entry)
			return
		}

		if entry.keyHash > hashedKey {
			return
		}
	}
}

// Set sets the value under the specified hash key to the map. An existing item for this key will be overwritten.
// Do not use non hashes as keys for this function, the performance would decrease!
// If a resizing operation is happening concurrently while calling Set, the item might show up in the map only after the resize operation is finished.
func (m *HashMap) Set(hashedKey uint64, value unsafe.Pointer) {
	newEntry := &ListElement{
		key:     hashedKey,
		keyHash: hashedKey,
		value:   value,
	}

	for {
		mapData, sliceItem := m.getSliceItemForKey(hashedKey)
		if !m.linkedList.Add(newEntry, sliceItem) {
			continue // a concurrent add did interfere, try again
		}

		newSliceCount := m.addItemToIndex(newEntry, mapData)
		if newSliceCount != 0 {
			sliceLen := uint64(len(mapData.slice))
			fillRate := (newSliceCount * 100) / sliceLen

			if fillRate > MaxFillRate { // check if the slice needs to be resized
				m.Lock()
				currentMapData := (*hashMapData)(atomic.LoadPointer(&m.mapData))
				if mapData == currentMapData { // double check that no other resize happened
					m.grow(0)
				}
				m.Unlock()
			}
		}
		return
	}
}

// adds an item to the index if needed and returns the new item counter if it changed, otherwise 0
func (m *HashMap) addItemToIndex(item *ListElement, mapData *hashMapData) uint64 {
	index := item.keyHash >> mapData.keyRightShifts
	sliceDataIndexPointer := (*unsafe.Pointer)(unsafe.Pointer(uintptr(mapData.data) + uintptr(index*intSizeBytes)))

	for { // loop until the smallest key hash is in the index
		sliceItem := (*ListElement)(atomic.LoadPointer(sliceDataIndexPointer)) // get the current item in the index
		if sliceItem == nil {                                                  // no item yet at this index
			if atomic.CompareAndSwapPointer((*unsafe.Pointer)(sliceDataIndexPointer), nil, unsafe.Pointer(item)) {
				return atomic.AddUint64(&mapData.count, 1)
			}
			continue // a new item was inserted concurrently, retry
		}

		if item.keyHash < sliceItem.keyHash {
			// the new item is the smallest for this index?
			if !atomic.CompareAndSwapPointer((*unsafe.Pointer)(sliceDataIndexPointer), unsafe.Pointer(sliceItem), unsafe.Pointer(item)) {
				continue // a new item was inserted concurrently, retry
			}
		}
		return 0
	}
}

// Grow resizes the hashmap to a new size, gets rounded up to next power of 2.
// To double the size of the hashmap use newSize 0.
func (m *HashMap) Grow(newSize uint64) {
	m.Lock()
	m.grow(newSize)
	m.Unlock()
}

func (m *HashMap) grow(newSize uint64) {
	mapData := (*hashMapData)(atomic.LoadPointer(&m.mapData))
	if newSize == 0 {
		newSize = uint64(len(mapData.slice)) << 1
	} else {
		newSize = roundUpPower2(newSize)
	}

	newSlice := make([]*ListElement, newSize)
	header := (*reflect.SliceHeader)(unsafe.Pointer(&newSlice))

	newMapData := &hashMapData{
		keyRightShifts: 64 - log2(newSize),
		data:           unsafe.Pointer(header.Data), // use address of slice data storage
		slice:          newSlice,
	}

	m.fillIndexItems(newMapData) // initialize new index slice with longer keys

	atomic.StorePointer(&m.mapData, unsafe.Pointer(newMapData))

	m.fillIndexItems(newMapData) // make sure that the new index is up to date with the current state of the linked list
}

func (m *HashMap) fillIndexItems(mapData *hashMapData) {
	first := m.linkedList.First()
	item := first
	lastIndex := uint64(0)

	for item != nil {
		index := item.keyHash >> mapData.keyRightShifts
		if item == first || index != lastIndex { // store item with smallest hash key for every index
			if !item.Deleted() {
				m.addItemToIndex(item, mapData)
				lastIndex = index
			}
		}
		item = item.Next()
	}
}

// String returns the map as a string, only hashed keys are printed.
func (m *HashMap) String() string {
	buffer := bytes.NewBufferString("")
	buffer.WriteRune('[')

	first := m.linkedList.First()
	item := first

	for item != nil {
		if !item.Deleted() {
			if item != first {
				buffer.WriteRune(',')
			}
			fmt.Fprint(buffer, item.keyHash)
		}

		item = item.Next()
	}
	buffer.WriteRune(']')
	return buffer.String()
}

// Iter returns an iterator which could be used in a for range loop.
// The order of the items is sorted by hash keys.
func (m *HashMap) Iter() <-chan KeyValue {
	ch := make(chan KeyValue) // do not use a size here since items can get added during iteration

	go func() {
		item := m.linkedList.First()
		for item != nil {
			if !item.Deleted() {
				ch <- KeyValue{item.key, item.Value()}
			}
			item = item.Next()
		}
		close(ch)
	}()

	return ch
}
<commit_msg>Code refactoring<commit_after>package hashmap

import (
	"bytes"
	"fmt"
	"reflect"
	"sync"
	"sync/atomic"
	"unsafe"
)

// MaxFillRate is the maximum fill rate for the slice before a resize  will happen.
const MaxFillRate = 50

type (
	hashMapData struct {
		keyRightShifts uint64         // 64 - log2 of array size, to be used as index in the data array
		data           unsafe.Pointer // pointer to slice data array
		slice          []*ListElement // storage for the slice for the garbage collector to not clean it up
		count          uint64         // count of filled elements in the slice
	}

	// HashMap implements a read optimized hash map.
	HashMap struct {
		mapDataPtr unsafe.Pointer // pointer to a map instance that gets replaced if the map resizes
		linkedList *List          // key sorted linked list of elements
		sync.Mutex                // mutex that is only used for resize operations
	}

	// KeyValue represents a key/value that is returned by the iterator.
	KeyValue struct {
		Key   interface{}
		Value unsafe.Pointer
	}
)

// New returns a new HashMap.
func New() *HashMap {
	return NewSize(8)
}

// NewSize returns a new HashMap instance with a specific initialization size.
func NewSize(size uint64) *HashMap {
	hashmap := &HashMap{
		linkedList: NewList(),
	}
	hashmap.Grow(size)
	return hashmap
}

// Len returns the number of elements within the map.
func (m *HashMap) Len() uint64 {
	return m.linkedList.Len()
}

func (m *HashMap) mapData() *hashMapData {
	return (*hashMapData)(atomic.LoadPointer(&m.mapDataPtr))
}

// Fillrate returns the fill rate of the map as an percentage integer.
func (m *HashMap) Fillrate() uint64 {
	mapData := m.mapData()
	count := atomic.LoadUint64(&mapData.count)
	sliceLen := uint64(len(mapData.slice))
	return (count * 100) / sliceLen
}

func (m *HashMap) getSliceItemForKey(hashedKey uint64) (mapData *hashMapData, item *ListElement) {
	mapData = m.mapData()
	index := hashedKey >> mapData.keyRightShifts
	sliceDataIndexPointer := (*unsafe.Pointer)(unsafe.Pointer(uintptr(mapData.data) + uintptr(index*intSizeBytes)))
	item = (*ListElement)(atomic.LoadPointer(sliceDataIndexPointer))
	return
}

// Get retrieves an element from the map under given hash key.
func (m *HashMap) Get(hashedKey uint64) (unsafe.Pointer, bool) {
	// inline HashMap.getSliceItemForKey()
	mapData := (*hashMapData)(atomic.LoadPointer(&m.mapDataPtr))
	index := hashedKey >> mapData.keyRightShifts
	sliceDataIndexPointer := (*unsafe.Pointer)(unsafe.Pointer(uintptr(mapData.data) + uintptr(index*intSizeBytes)))
	entry := (*ListElement)(atomic.LoadPointer(sliceDataIndexPointer))

	for entry != nil {
		if entry.keyHash == hashedKey {
			if atomic.LoadUint64(&entry.deleted) == 1 { // inline ListElement.Deleted()
				return nil, false
			}
			return atomic.LoadPointer(&entry.value), true // inline ListElement.Value()
		}

		if entry.keyHash > hashedKey {
			return nil, false
		}

		entry = (*ListElement)(atomic.LoadPointer(&entry.nextElement)) // inline ListElement.Next()
	}
	return nil, false
}

// Del deletes the hashed key from the map.
func (m *HashMap) Del(hashedKey uint64) {
	for _, entry := m.getSliceItemForKey(hashedKey); entry != nil; entry = entry.Next() {
		if entry.keyHash == hashedKey {
			m.linkedList.Delete(entry)
			return
		}

		if entry.keyHash > hashedKey {
			return
		}
	}
}

// Set sets the value under the specified hash key to the map. An existing item for this key will be overwritten.
// Do not use non hashes as keys for this function, the performance would decrease!
// If a resizing operation is happening concurrently while calling Set, the item might show up in the map only after the resize operation is finished.
func (m *HashMap) Set(hashedKey uint64, value unsafe.Pointer) {
	newEntry := &ListElement{
		key:     hashedKey,
		keyHash: hashedKey,
		value:   value,
	}

	for {
		mapData, sliceItem := m.getSliceItemForKey(hashedKey)
		if !m.linkedList.Add(newEntry, sliceItem) {
			continue // a concurrent add did interfere, try again
		}

		newSliceCount := mapData.addItemToIndex(newEntry)
		if newSliceCount != 0 {
			sliceLen := uint64(len(mapData.slice))
			fillRate := (newSliceCount * 100) / sliceLen

			if fillRate > MaxFillRate { // check if the slice needs to be resized
				m.Lock()
				currentMapData := m.mapData()
				if mapData == currentMapData { // double check that no other resize happened
					m.grow(0)
				}
				m.Unlock()
			}
		}
		return
	}
}

// adds an item to the index if needed and returns the new item counter if it changed, otherwise 0
func (mapData *hashMapData) addItemToIndex(item *ListElement) uint64 {
	index := item.keyHash >> mapData.keyRightShifts
	sliceDataIndexPointer := (*unsafe.Pointer)(unsafe.Pointer(uintptr(mapData.data) + uintptr(index*intSizeBytes)))

	for { // loop until the smallest key hash is in the index
		sliceItem := (*ListElement)(atomic.LoadPointer(sliceDataIndexPointer)) // get the current item in the index
		if sliceItem == nil {                                                  // no item yet at this index
			if atomic.CompareAndSwapPointer((*unsafe.Pointer)(sliceDataIndexPointer), nil, unsafe.Pointer(item)) {
				return atomic.AddUint64(&mapData.count, 1)
			}
			continue // a new item was inserted concurrently, retry
		}

		if item.keyHash < sliceItem.keyHash {
			// the new item is the smallest for this index?
			if !atomic.CompareAndSwapPointer((*unsafe.Pointer)(sliceDataIndexPointer), unsafe.Pointer(sliceItem), unsafe.Pointer(item)) {
				continue // a new item was inserted concurrently, retry
			}
		}
		return 0
	}
}

// Grow resizes the hashmap to a new size, gets rounded up to next power of 2.
// To double the size of the hashmap use newSize 0.
func (m *HashMap) Grow(newSize uint64) {
	m.Lock()
	m.grow(newSize)
	m.Unlock()
}

func (m *HashMap) grow(newSize uint64) {
	mapData := m.mapData()
	if newSize == 0 {
		newSize = uint64(len(mapData.slice)) << 1
	} else {
		newSize = roundUpPower2(newSize)
	}

	newSlice := make([]*ListElement, newSize)
	header := (*reflect.SliceHeader)(unsafe.Pointer(&newSlice))

	newMapData := &hashMapData{
		keyRightShifts: 64 - log2(newSize),
		data:           unsafe.Pointer(header.Data), // use address of slice data storage
		slice:          newSlice,
	}

	m.fillIndexItems(newMapData) // initialize new index slice with longer keys

	atomic.StorePointer(&m.mapDataPtr, unsafe.Pointer(newMapData))

	m.fillIndexItems(newMapData) // make sure that the new index is up to date with the current state of the linked list
}

func (m *HashMap) fillIndexItems(mapData *hashMapData) {
	first := m.linkedList.First()
	item := first
	lastIndex := uint64(0)

	for item != nil {
		index := item.keyHash >> mapData.keyRightShifts
		if item == first || index != lastIndex { // store item with smallest hash key for every index
			if !item.Deleted() {
				mapData.addItemToIndex(item)
				lastIndex = index
			}
		}
		item = item.Next()
	}
}

// String returns the map as a string, only hashed keys are printed.
func (m *HashMap) String() string {
	buffer := bytes.NewBufferString("")
	buffer.WriteRune('[')

	first := m.linkedList.First()
	item := first

	for item != nil {
		if !item.Deleted() {
			if item != first {
				buffer.WriteRune(',')
			}
			fmt.Fprint(buffer, item.keyHash)
		}

		item = item.Next()
	}
	buffer.WriteRune(']')
	return buffer.String()
}

// Iter returns an iterator which could be used in a for range loop.
// The order of the items is sorted by hash keys.
func (m *HashMap) Iter() <-chan KeyValue {
	ch := make(chan KeyValue) // do not use a size here since items can get added during iteration

	go func() {
		item := m.linkedList.First()
		for item != nil {
			if !item.Deleted() {
				ch <- KeyValue{item.key, item.Value()}
			}
			item = item.Next()
		}
		close(ch)
	}()

	return ch
}
<|endoftext|>


<commit_before>package main

import (
	"reflect"
)

func assertSeq(obj Object, msg string) Seq {
	switch s := obj.(type) {
	case Seq:
		return s
	case Sequenceable:
		return s.Seq()
	default:
		panic(RT.newError(msg))
	}
}

func ensureSeq(args []Object, index int) Seq {
	switch s := args[index].(type) {
	case Seq:
		return s
	case Sequenceable:
		return s.Seq()
	default:
		panic(RT.newArgTypeError(index, "Seq"))
	}
}

func ensureNumber(args []Object, index int) Number {
	switch obj := args[index].(type) {
	case Number:
		return obj
	default:
		panic(RT.newArgTypeError(index, "Number"))
	}
}

func ensureString(args []Object, index int) String {
	switch obj := args[index].(type) {
	case String:
		return obj
	default:
		panic(RT.newArgTypeError(index, "String"))
	}
}

func ensureType(args []Object, index int) *Type {
	switch obj := args[index].(type) {
	case *Type:
		return obj
	default:
		panic(RT.newArgTypeError(index, "Type"))
	}
}

func ensureMap(args []Object, index int) *ArrayMap {
	switch obj := args[index].(type) {
	case *ArrayMap:
		return obj
	default:
		panic(RT.newArgTypeError(index, "Map"))
	}
}

func ensureMeta(args []Object, index int) Meta {
	switch obj := args[index].(type) {
	case Meta:
		return obj
	default:
		panic(RT.newArgTypeError(index, "Meta"))
	}
}

var procMeta Proc = func(args []Object) Object {
	switch obj := args[0].(type) {
	case Meta:
		meta := obj.GetMeta()
		if meta != nil {
			return meta
		}
	}
	return NIL
}

var procWithMeta Proc = func(args []Object) Object {
	checkArity(args, 2, 2)
	return ensureMeta(args, 0).WithMeta(ensureMap(args, 1))
}

var procIsZero Proc = func(args []Object) Object {
	// checkArity(args, 1, "zero?")
	n := ensureNumber(args, 0)
	ops := GetOps(ensureNumber(args, 0))
	return Bool{b: ops.IsZero(n)}
}

var procAdd Proc = func(args []Object) Object {
	var res Number = Int{i: 0}
	for i, n := range args {
		ops := GetOps(res).Combine(GetOps(n))
		res = ops.Add(res, ensureNumber(args, i))
	}
	return res
}

var procMultiply Proc = func(args []Object) Object {
	var res Number = Int{i: 1}
	for i, n := range args {
		ops := GetOps(res).Combine(GetOps(n))
		res = ops.Multiply(res, ensureNumber(args, i))
	}
	return res
}

var procSubtract Proc = func(args []Object) Object {
	if len(args) == 0 {
		panicArity(0)
	}
	var res Number = Int{i: 0}
	start := 0
	if len(args) > 1 {
		res = ensureNumber(args, 0)
		start = 1
	}
	for i := start; i < len(args); i++ {
		ops := GetOps(res).Combine(GetOps(args[i]))
		res = ops.Subtract(res, ensureNumber(args, i))
	}
	return res
}

var procDivide Proc = func(args []Object) Object {
	if len(args) == 0 {
		panicArity(0)
	}
	var res Number = Int{i: 1}
	start := 0
	if len(args) > 1 {
		res = ensureNumber(args, 0)
		start = 1
	}
	for i := start; i < len(args); i++ {
		ops := GetOps(res).Combine(GetOps(args[i]))
		res = ops.Divide(res, ensureNumber(args, i))
	}
	return res
}

var procExInfo Proc = func(args []Object) Object {
	checkArity(args, 2, 2)
	return &ExInfo{
		msg:  ensureString(args, 0),
		data: ensureMap(args, 1),
		rt:   RT.clone(),
	}
}

var procPrint Proc = func(args []Object) Object {
	n := len(args)
	if n > 0 {
		for _, arg := range args[:n-1] {
			print(arg.ToString(false))
			print(" ")
		}
		print(args[n-1].ToString(false))
	}
	return NIL
}

var procSetMacro Proc = func(args []Object) Object {
	vr := args[0].(*Var)
	vr.isMacro = true
	return vr
}

var procList Proc = func(args []Object) Object {
	return NewListFrom(args...)
}

var procCons Proc = func(args []Object) Object {
	checkArity(args, 2, 2)
	s := ensureSeq(args, 1)
	return s.Cons(args[0])
}

var procFirst Proc = func(args []Object) Object {
	checkArity(args, 1, 1)
	s := ensureSeq(args, 0)
	return s.First()
}

var procNext Proc = func(args []Object) Object {
	checkArity(args, 1, 1)
	s := ensureSeq(args, 0)
	res := s.Rest()
	if res.IsEmpty() {
		return NIL
	}
	return res
}

var procRest Proc = func(args []Object) Object {
	checkArity(args, 1, 1)
	s := ensureSeq(args, 0)
	return s.Rest()
}

var procConj Proc = func(args []Object) Object {
	switch c := args[0].(type) {
	case Nil:
		return NewListFrom(args[1])
	case Conjable:
		return c.Conj(args[1])
	case Seq:
		return c.Cons(args[1])
	default:
		panic(RT.newError("conj's first argument must be a collection"))
	}
}

var procSeq Proc = func(args []Object) Object {
	checkArity(args, 1, 1)
	return ensureSeq(args, 0)
}

var procIsInstance Proc = func(args []Object) Object {
	checkArity(args, 2, 2)
	switch t := args[0].(type) {
	case *Type:
		if t.reflectType.Kind() == reflect.Interface {
			return Bool{b: args[1].GetType().reflectType.Implements(t.reflectType)}
		} else {
			return Bool{b: args[1].GetType().reflectType == t.reflectType}
		}
	default:
		panic(RT.newError("First argument to instance? must be a type"))
	}
}

var procAssoc Proc = func(args []Object) Object {
	return ensureMap(args, 0).Assoc(args[1], args[2])
}

var procEquals Proc = func(args []Object) Object {
	return Bool{b: args[0].Equals(args[1])}
}

var procCount Proc = func(args []Object) Object {
	switch obj := args[0].(type) {
	case Counted:
		return Int{i: obj.Count()}
	default:
		s := assertSeq(obj, "count not supported on this type: "+obj.GetType().ToString(false))
		c := 0
		for !s.IsEmpty() {
			c++
			s = s.Rest()
			switch obj := s.(type) {
			case Counted:
				return Int{i: c + obj.Count()}
			}
		}
		return Int{i: c}
	}
}

var procSubvec Proc = func(args []Object) Object {
	// TODO: implement proper Subvector structure
	v := args[0].(*Vector)
	start := args[1].(Int).i
	end := args[2].(Int).i
	subv := make([]Object, 0, end-start)
	for i := start; i < end; i++ {
		subv = append(subv, v.at(i))
	}
	return NewVectorFrom(subv...)
}

var procCast Proc = func(args []Object) Object {
	t := ensureType(args, 0)
	if t.reflectType.Kind() == reflect.Interface &&
		args[1].GetType().reflectType.Implements(t.reflectType) ||
		args[1].GetType().reflectType == t.reflectType {
		return args[1]
	}
	panic(RT.newError("Cannot cast " + args[1].GetType().ToString(false) + " to " + t.ToString(false)))
}

var procVector Proc = func(args []Object) Object {
	return NewVectorFrom(args...)
}

var procVec Proc = func(args []Object) Object {
	return NewVectorFromSeq(ensureSeq(args, 0))
}

var coreNamespace = GLOBAL_ENV.namespaces[MakeSymbol("gclojure.core").name]

func intern(name string, proc Proc) {
	coreNamespace.intern(MakeSymbol(name)).value = proc
}

func init() {
	intern("list*", procList)
	intern("cons*", procCons)
	intern("first*", procFirst)
	intern("next*", procNext)
	intern("rest*", procRest)
	intern("conj*", procConj)
	intern("seq*", procSeq)
	intern("instance?*", procIsInstance)
	intern("assoc*", procAssoc)
	intern("meta*", procMeta)
	intern("with-meta*", procWithMeta)
	intern("=*", procEquals)
	intern("count*", procCount)
	intern("subvec*", procSubvec)
	intern("cast*", procCast)
	intern("vector*", procVector)
	intern("vec*", procVec)

	intern("zero?", procIsZero)
	intern("+", procAdd)
	intern("-", procSubtract)
	intern("*", procMultiply)
	intern("/", procDivide)
	intern("ex-info", procExInfo)
	intern("print", procPrint)
	intern("set-macro*", procSetMacro)

	currentNamespace := GLOBAL_ENV.currentNamespace
	GLOBAL_ENV.currentNamespace = coreNamespace
	processFile("core.clj", EVAL)
	GLOBAL_ENV.currentNamespace = currentNamespace
}
<commit_msg>Remove unused code<commit_after>package main

import (
	"reflect"
)

func assertSeq(obj Object, msg string) Seq {
	switch s := obj.(type) {
	case Seq:
		return s
	case Sequenceable:
		return s.Seq()
	default:
		panic(RT.newError(msg))
	}
}

func ensureSeq(args []Object, index int) Seq {
	switch s := args[index].(type) {
	case Seq:
		return s
	case Sequenceable:
		return s.Seq()
	default:
		panic(RT.newArgTypeError(index, "Seq"))
	}
}

func ensureNumber(args []Object, index int) Number {
	switch obj := args[index].(type) {
	case Number:
		return obj
	default:
		panic(RT.newArgTypeError(index, "Number"))
	}
}

func ensureString(args []Object, index int) String {
	switch obj := args[index].(type) {
	case String:
		return obj
	default:
		panic(RT.newArgTypeError(index, "String"))
	}
}

func ensureType(args []Object, index int) *Type {
	switch obj := args[index].(type) {
	case *Type:
		return obj
	default:
		panic(RT.newArgTypeError(index, "Type"))
	}
}

func ensureMap(args []Object, index int) *ArrayMap {
	switch obj := args[index].(type) {
	case *ArrayMap:
		return obj
	default:
		panic(RT.newArgTypeError(index, "Map"))
	}
}

func ensureMeta(args []Object, index int) Meta {
	switch obj := args[index].(type) {
	case Meta:
		return obj
	default:
		panic(RT.newArgTypeError(index, "Meta"))
	}
}

var procMeta Proc = func(args []Object) Object {
	switch obj := args[0].(type) {
	case Meta:
		meta := obj.GetMeta()
		if meta != nil {
			return meta
		}
	}
	return NIL
}

var procWithMeta Proc = func(args []Object) Object {
	checkArity(args, 2, 2)
	return ensureMeta(args, 0).WithMeta(ensureMap(args, 1))
}

var procIsZero Proc = func(args []Object) Object {
	// checkArity(args, 1, "zero?")
	n := ensureNumber(args, 0)
	ops := GetOps(ensureNumber(args, 0))
	return Bool{b: ops.IsZero(n)}
}

var procAdd Proc = func(args []Object) Object {
	var res Number = Int{i: 0}
	for i, n := range args {
		ops := GetOps(res).Combine(GetOps(n))
		res = ops.Add(res, ensureNumber(args, i))
	}
	return res
}

var procMultiply Proc = func(args []Object) Object {
	var res Number = Int{i: 1}
	for i, n := range args {
		ops := GetOps(res).Combine(GetOps(n))
		res = ops.Multiply(res, ensureNumber(args, i))
	}
	return res
}

var procSubtract Proc = func(args []Object) Object {
	if len(args) == 0 {
		panicArity(0)
	}
	var res Number = Int{i: 0}
	start := 0
	if len(args) > 1 {
		res = ensureNumber(args, 0)
		start = 1
	}
	for i := start; i < len(args); i++ {
		ops := GetOps(res).Combine(GetOps(args[i]))
		res = ops.Subtract(res, ensureNumber(args, i))
	}
	return res
}

var procDivide Proc = func(args []Object) Object {
	if len(args) == 0 {
		panicArity(0)
	}
	var res Number = Int{i: 1}
	start := 0
	if len(args) > 1 {
		res = ensureNumber(args, 0)
		start = 1
	}
	for i := start; i < len(args); i++ {
		ops := GetOps(res).Combine(GetOps(args[i]))
		res = ops.Divide(res, ensureNumber(args, i))
	}
	return res
}

var procExInfo Proc = func(args []Object) Object {
	checkArity(args, 2, 2)
	return &ExInfo{
		msg:  ensureString(args, 0),
		data: ensureMap(args, 1),
		rt:   RT.clone(),
	}
}

var procPrint Proc = func(args []Object) Object {
	n := len(args)
	if n > 0 {
		for _, arg := range args[:n-1] {
			print(arg.ToString(false))
			print(" ")
		}
		print(args[n-1].ToString(false))
	}
	return NIL
}

var procSetMacro Proc = func(args []Object) Object {
	vr := args[0].(*Var)
	vr.isMacro = true
	return vr
}

var procList Proc = func(args []Object) Object {
	return NewListFrom(args...)
}

var procCons Proc = func(args []Object) Object {
	checkArity(args, 2, 2)
	s := ensureSeq(args, 1)
	return s.Cons(args[0])
}

var procFirst Proc = func(args []Object) Object {
	checkArity(args, 1, 1)
	s := ensureSeq(args, 0)
	return s.First()
}

var procNext Proc = func(args []Object) Object {
	checkArity(args, 1, 1)
	s := ensureSeq(args, 0)
	res := s.Rest()
	if res.IsEmpty() {
		return NIL
	}
	return res
}

var procRest Proc = func(args []Object) Object {
	checkArity(args, 1, 1)
	s := ensureSeq(args, 0)
	return s.Rest()
}

var procConj Proc = func(args []Object) Object {
	switch c := args[0].(type) {
	case Nil:
		return NewListFrom(args[1])
	case Conjable:
		return c.Conj(args[1])
	case Seq:
		return c.Cons(args[1])
	default:
		panic(RT.newError("conj's first argument must be a collection"))
	}
}

var procSeq Proc = func(args []Object) Object {
	checkArity(args, 1, 1)
	return ensureSeq(args, 0)
}

var procIsInstance Proc = func(args []Object) Object {
	checkArity(args, 2, 2)
	switch t := args[0].(type) {
	case *Type:
		if t.reflectType.Kind() == reflect.Interface {
			return Bool{b: args[1].GetType().reflectType.Implements(t.reflectType)}
		} else {
			return Bool{b: args[1].GetType().reflectType == t.reflectType}
		}
	default:
		panic(RT.newError("First argument to instance? must be a type"))
	}
}

var procAssoc Proc = func(args []Object) Object {
	return ensureMap(args, 0).Assoc(args[1], args[2])
}

var procEquals Proc = func(args []Object) Object {
	return Bool{b: args[0].Equals(args[1])}
}

var procCount Proc = func(args []Object) Object {
	switch obj := args[0].(type) {
	case Counted:
		return Int{i: obj.Count()}
	default:
		s := assertSeq(obj, "count not supported on this type: "+obj.GetType().ToString(false))
		c := 0
		for !s.IsEmpty() {
			c++
			s = s.Rest()
			switch obj := s.(type) {
			case Counted:
				return Int{i: c + obj.Count()}
			}
		}
		return Int{i: c}
	}
}

var procSubvec Proc = func(args []Object) Object {
	// TODO: implement proper Subvector structure
	v := args[0].(*Vector)
	start := args[1].(Int).i
	end := args[2].(Int).i
	subv := make([]Object, 0, end-start)
	for i := start; i < end; i++ {
		subv = append(subv, v.at(i))
	}
	return NewVectorFrom(subv...)
}

var procCast Proc = func(args []Object) Object {
	t := ensureType(args, 0)
	if t.reflectType.Kind() == reflect.Interface &&
		args[1].GetType().reflectType.Implements(t.reflectType) ||
		args[1].GetType().reflectType == t.reflectType {
		return args[1]
	}
	panic(RT.newError("Cannot cast " + args[1].GetType().ToString(false) + " to " + t.ToString(false)))
}

var procVec Proc = func(args []Object) Object {
	return NewVectorFromSeq(ensureSeq(args, 0))
}

var coreNamespace = GLOBAL_ENV.namespaces[MakeSymbol("gclojure.core").name]

func intern(name string, proc Proc) {
	coreNamespace.intern(MakeSymbol(name)).value = proc
}

func init() {
	intern("list*", procList)
	intern("cons*", procCons)
	intern("first*", procFirst)
	intern("next*", procNext)
	intern("rest*", procRest)
	intern("conj*", procConj)
	intern("seq*", procSeq)
	intern("instance?*", procIsInstance)
	intern("assoc*", procAssoc)
	intern("meta*", procMeta)
	intern("with-meta*", procWithMeta)
	intern("=*", procEquals)
	intern("count*", procCount)
	intern("subvec*", procSubvec)
	intern("cast*", procCast)
	intern("vec*", procVec)

	intern("zero?", procIsZero)
	intern("+", procAdd)
	intern("-", procSubtract)
	intern("*", procMultiply)
	intern("/", procDivide)
	intern("ex-info", procExInfo)
	intern("print", procPrint)
	intern("set-macro*", procSetMacro)

	currentNamespace := GLOBAL_ENV.currentNamespace
	GLOBAL_ENV.currentNamespace = coreNamespace
	processFile("core.clj", EVAL)
	GLOBAL_ENV.currentNamespace = currentNamespace
}
<|endoftext|>


<commit_before>package proxy

import (
	"errors"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"github.com/koding/websocketproxy"
)

type ProxyOptions struct {
	// Number of times a request should be tried
	Retries int

	// Period to wait between retries
	Period time.Duration

	// Returns a url that we should proxy to for a given request
	Balancer func(req *http.Request) (string, error)

	// A static backend to route to
	Backend string
}

type Proxy struct {
	*ProxyOptions

	// Http proxy
	httpProxy http.Handler

	// Websocket proxy
	websocketProxy http.Handler
}

// New returns a new Proxy instance based on the provided ProxyOptions
// either 'Backend' (static) or 'Balancer' must be provided
func New(opts ProxyOptions) (*Proxy, error) {
	// Validate Balancer and Backend options
	if opts.Balancer == nil {
		if opts.Backend == "" {
			return nil, errors.New("Please provide a Backend or a Balancer")
		} else if err := validateUrl(opts.Backend); err != nil {
			return nil, err
		}
	}

	// Default for Retries
	if opts.Retries == 0 {
		opts.Retries = 1
	}

	// Default for Period
	if opts.Period == 0 {
		opts.Period = 100 * time.Millisecond
	}

	p := &Proxy{
		ProxyOptions: &opts,
	}

	return p.init(), nil
}

// ServeHTTP allows us to comply to the http.Handler interface
func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if isWebsocket(req) {
		// we don't use https explicitly, ssl termination is done here
		req.URL.Scheme = "ws"
		p.websocketProxy.ServeHTTP(rw, req)
		return
	}

	p.httpProxy.ServeHTTP(rw, req)
}

// init sets up proxies and other stuff based on options
func (p *Proxy) init() *Proxy {
	// Setup http proxy
	p.httpProxy = &httputil.ReverseProxy{
		Director: p.director,
	}

	// Setup websocket proxy
	p.websocketProxy = &websocketproxy.WebsocketProxy{
		Backend: func(req *http.Request) *url.URL {
			url, _ := p.backend(req)
			return url
		},
		Upgrader: &websocket.Upgrader{
			ReadBufferSize:  4096,
			WriteBufferSize: 4096,
			CheckOrigin: func(r *http.Request) bool {
				return true
			},
		},
	}

	return p
}

// director rewrites a http.Request to route to the correct host
func (p *Proxy) director(req *http.Request) {
	url, err := p.backend(req)
	if url == nil || err != nil {
		return
	}

	// Rewrite outgoing request url
	req.URL.Scheme = url.Scheme
	req.URL.Host = url.Host
	req.URL.Path = url.Path

	req.Host = url.Host
}

// backend parses the result of getBackend and ensures it's validity
func (p *Proxy) backend(req *http.Request) (*url.URL, error) {
	rawurl, err := p.getBackend(req)
	if err != nil {
		return nil, err
	}

	if err := validateUrl(rawurl); err != nil {
		return nil, err
	}

	return url.Parse(rawurl)
}

// getBackend gets the backend selected by the balancer or the static one set by the 'Backend' attribute
func (p *Proxy) getBackend(req *http.Request) (string, error) {
	if p.Balancer == nil && p.Backend != "" {
		return p.Backend, nil
	}
	return p.Balancer(req)
}

// validateUrl generates an error if the the url isn't absolute or valid
func validateUrl(rawurl string) error {
	parsed, err := url.Parse(rawurl)
	if err != nil {
		return err
	}

	// Ensure url is absolute
	if !parsed.IsAbs() {
		return errors.New("Proxy must only proxy to absolute URLs")
	}

	// All is good
	return nil
}

// isWebsocket checks wether the incoming request is a part of websocket
// handshake
func isWebsocket(req *http.Request) bool {
	if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
		!strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
		return false
	}
	return true
}
<commit_msg>Add websocketScheme normalization func<commit_after>package proxy

import (
	"errors"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"github.com/koding/websocketproxy"
)

type ProxyOptions struct {
	// Number of times a request should be tried
	Retries int

	// Period to wait between retries
	Period time.Duration

	// Returns a url that we should proxy to for a given request
	Balancer func(req *http.Request) (string, error)

	// A static backend to route to
	Backend string
}

type Proxy struct {
	*ProxyOptions

	// Http proxy
	httpProxy http.Handler

	// Websocket proxy
	websocketProxy http.Handler
}

// New returns a new Proxy instance based on the provided ProxyOptions
// either 'Backend' (static) or 'Balancer' must be provided
func New(opts ProxyOptions) (*Proxy, error) {
	// Validate Balancer and Backend options
	if opts.Balancer == nil {
		if opts.Backend == "" {
			return nil, errors.New("Please provide a Backend or a Balancer")
		} else if err := validateUrl(opts.Backend); err != nil {
			return nil, err
		}
	}

	// Default for Retries
	if opts.Retries == 0 {
		opts.Retries = 1
	}

	// Default for Period
	if opts.Period == 0 {
		opts.Period = 100 * time.Millisecond
	}

	p := &Proxy{
		ProxyOptions: &opts,
	}

	return p.init(), nil
}

// ServeHTTP allows us to comply to the http.Handler interface
func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if isWebsocket(req) {
		// we don't use https explicitly, ssl termination is done here
		req.URL.Scheme = "ws"
		p.websocketProxy.ServeHTTP(rw, req)
		return
	}

	p.httpProxy.ServeHTTP(rw, req)
}

// init sets up proxies and other stuff based on options
func (p *Proxy) init() *Proxy {
	// Setup http proxy
	p.httpProxy = &httputil.ReverseProxy{
		Director: p.director,
	}

	// Setup websocket proxy
	p.websocketProxy = &websocketproxy.WebsocketProxy{
		Backend: func(req *http.Request) *url.URL {
			url, _ := p.backend(req)
			return url
		},
		Upgrader: &websocket.Upgrader{
			ReadBufferSize:  4096,
			WriteBufferSize: 4096,
			CheckOrigin: func(r *http.Request) bool {
				return true
			},
		},
	}

	return p
}

// director rewrites a http.Request to route to the correct host
func (p *Proxy) director(req *http.Request) {
	url, err := p.backend(req)
	if url == nil || err != nil {
		return
	}

	// Rewrite outgoing request url
	req.URL.Scheme = url.Scheme
	req.URL.Host = url.Host
	req.URL.Path = url.Path

	req.Host = url.Host
}

// backend parses the result of getBackend and ensures it's validity
func (p *Proxy) backend(req *http.Request) (*url.URL, error) {
	rawurl, err := p.getBackend(req)
	if err != nil {
		return nil, err
	}

	if err := validateUrl(rawurl); err != nil {
		return nil, err
	}

	return url.Parse(rawurl)
}

// getBackend gets the backend selected by the balancer or the static one set by the 'Backend' attribute
func (p *Proxy) getBackend(req *http.Request) (string, error) {
	if p.Balancer == nil && p.Backend != "" {
		return p.Backend, nil
	}
	return p.Balancer(req)
}

// validateUrl generates an error if the the url isn't absolute or valid
func validateUrl(rawurl string) error {
	parsed, err := url.Parse(rawurl)
	if err != nil {
		return err
	}

	// Ensure url is absolute
	if !parsed.IsAbs() {
		return errors.New("Proxy must only proxy to absolute URLs")
	}

	// All is good
	return nil
}

// websocketScheme picks a suitable websocket scheme
func websocketScheme(scheme string) string {
	switch scheme {
		case "http":
			return "ws"
		case "https":
			return "wss"
		case "ws":
		case "wss":
			return scheme
	}
	// Default
	return "ws"
}

// isWebsocket checks wether the incoming request is a part of websocket handshake
func isWebsocket(req *http.Request) bool {
	if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
		!strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
    "flag"
    "fmt"
    "github.com/miekg/dns"
    "io"
    "log"
    "net"
    "os"
    "os/signal"
    "strings"
    "syscall"
)

var zones map[string]net.IP

func ProxyMsg(m *dns.Msg) *dns.Msg {
    if len(m.Question) == 0 {
        return nil
    }
    q := m.Question[0]

    ip, exists := zones[q.Name]
    if !exists {
        return nil
    }

    if q.Qtype != dns.TypeA {
        response := new(dns.Msg)
        response.SetReply(m)
        return response
    }

    response := new(dns.Msg)
    response.SetReply(m)

    rr := new(dns.A)
    rr.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA,
        Class: dns.ClassINET, Ttl: 0}
    rr.A = ip.To4()
    response.Answer = append(m.Answer, rr)

    return response
}

func dnsHandler(w dns.ResponseWriter, m *dns.Msg) {
    if msg := ProxyMsg(m); msg != nil {
        log.Printf("Proxying request for %s IN A from %s",
            msg.Question[0].Name, w.RemoteAddr())
        w.WriteMsg(msg)
        return
    }

    c := new(dns.Client)
    c.Net = "udp"
    r, _, err := c.Exchange(m, "8.8.8.8:53")
    if err != nil {
        log.Print(err)
        return
    }
    w.WriteMsg(r)
}

func tcpProxy(local net.Conn, remoteAddr string) {
    remote, err := net.Dial("tcp", remoteAddr)
    if err != nil {
        log.Printf("Failed to connect to %s: %s", remoteAddr, err)
        return
    }
    go io.Copy(local, remote)
    go io.Copy(remote, local)
}

func listenAndServe() {
    go func() {
        err := dns.ListenAndServe(":53", "udp", dns.HandlerFunc(dnsHandler))
        if err != nil {
            log.Fatal(err)
        }
    }()
    go func() {
        err := dns.ListenAndServe(":53", "tcp", dns.HandlerFunc(dnsHandler))
        if err != nil {
            log.Fatal(err)
        }
    }()
    go func() {
        listener, err := net.Listen("tcp", ":80")
        if err != nil {
            log.Fatal(err)
        }
        for {
            conn, err := listener.Accept()
            if err != nil {
                log.Print(err)
            }
            go tcpProxy(conn, "movies.netflix.com:80")
        }
    }()
    go func() {
        listener, err := net.Listen("tcp", ":443")
        if err != nil {
            log.Fatal(err)
        }
        for {
            conn, err := listener.Accept()
            if err != nil {
                log.Print(err)
            }
            go tcpProxy(conn, "cbp-us.nccp.netflix.com:443")
        }
    }()
}

func printfErr(format string, a ...interface{}) {
    fmt.Fprintf(os.Stderr, format+"\n", a...)
    os.Exit(2)
}

func main() {
    flag.Parse()
    if flag.NArg() == 0 {
        printfErr("usage: %s zone:ip [zone:ip ...]", os.Args[0])
    }

    zones = make(map[string]net.IP, flag.NArg())
    for _, arg := range flag.Args() {
        zoneAndIp := strings.SplitN(arg, ":", 2)
        if len(zoneAndIp) != 2 {
            printfErr("Invalid zone mapping: %s", arg)
        }
        zone := dns.Fqdn(zoneAndIp[0])
        ip := net.ParseIP(zoneAndIp[1])
        if ip == nil {
            printfErr("Invalid IP address: %s", zoneAndIp[1])
        }
        zones[zone] = ip
        log.Printf("Answering %s with %s", zone, ip)
    }

    listenAndServe()

    sig := make(chan os.Signal)
    signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
    for {
        select {
        case s := <-sig:
            log.Fatalf("Signal (%d) received, stopping\n", s)
        }
    }
}
<commit_msg>Ensure resources are cleaned up<commit_after>package main

import (
    "flag"
    "fmt"
    "github.com/miekg/dns"
    "io"
    "log"
    "net"
    "os"
    "os/signal"
    "strings"
    "syscall"
)

var zones map[string]net.IP

func ProxyMsg(m *dns.Msg) *dns.Msg {
    if len(m.Question) == 0 {
        return nil
    }
    q := m.Question[0]

    ip, exists := zones[q.Name]
    if !exists {
        return nil
    }

    if q.Qtype != dns.TypeA {
        response := new(dns.Msg)
        response.SetReply(m)
        return response
    }

    response := new(dns.Msg)
    response.SetReply(m)

    rr := new(dns.A)
    rr.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA,
        Class: dns.ClassINET, Ttl: 0}
    rr.A = ip.To4()
    response.Answer = append(m.Answer, rr)

    return response
}

func dnsHandler(w dns.ResponseWriter, m *dns.Msg) {
    if msg := ProxyMsg(m); msg != nil {
        log.Printf("Proxying request for %s IN A from %s",
            msg.Question[0].Name, w.RemoteAddr())
        w.WriteMsg(msg)
        return
    }

    c := new(dns.Client)
    c.Net = "udp"
    r, _, err := c.Exchange(m, "8.8.8.8:53")
    if err != nil {
        log.Print(err)
        return
    }
    w.WriteMsg(r)
}

func copy(dst io.ReadWriteCloser, src io.ReadWriteCloser) {
    if _, err := io.Copy(dst, src); err != nil {
        log.Print(err)
    }
    dst.Close()
    src.Close()
}

func handleConn(local net.Conn, remoteAddr string) {
    remote, err := net.Dial("tcp", remoteAddr)
    if err != nil {
        log.Printf("Failed to connect to %s: %s", remoteAddr, err)
        return
    }
    go copy(local, remote)
    go copy(remote, local)
}

func tcpProxy(listenAddr string, remoteAddr string) {
    listener, err := net.Listen("tcp", listenAddr)
    if err != nil {
        log.Fatal(err)
    }
    defer listener.Close()
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err)
        }
        go handleConn(conn, remoteAddr)
    }
}

func listenAndServe() {
    go func() {
        err := dns.ListenAndServe(":53", "udp", dns.HandlerFunc(dnsHandler))
        if err != nil {
            log.Fatal(err)
        }
    }()
    go func() {
        err := dns.ListenAndServe(":53", "tcp", dns.HandlerFunc(dnsHandler))
        if err != nil {
            log.Fatal(err)
        }
    }()
    go tcpProxy(":80", "movies.netflix.com:80")
    go tcpProxy(":443", "cbp-us.nccp.netflix.com:443")
}

func printfErr(format string, a ...interface{}) {
    fmt.Fprintf(os.Stderr, format+"\n", a...)
    os.Exit(2)
}

func main() {
    flag.Parse()
    if flag.NArg() == 0 {
        printfErr("usage: %s zone:ip [zone:ip ...]", os.Args[0])
    }

    zones = make(map[string]net.IP, flag.NArg())
    for _, arg := range flag.Args() {
        zoneAndIp := strings.SplitN(arg, ":", 2)
        if len(zoneAndIp) != 2 {
            printfErr("Invalid zone mapping: %s", arg)
        }
        zone := dns.Fqdn(zoneAndIp[0])
        ip := net.ParseIP(zoneAndIp[1])
        if ip == nil {
            printfErr("Invalid IP address: %s", zoneAndIp[1])
        }
        zones[zone] = ip
        log.Printf("Answering %s with %s", zone, ip)
    }

    listenAndServe()

    sig := make(chan os.Signal)
    signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
    for {
        select {
        case s := <-sig:
            log.Fatalf("Signal (%d) received, stopping\n", s)
        }
    }
}
<|endoftext|>


<commit_before>package httplog

import (
	"fmt"
	"net/http"
	"strings"
	"time"
)

var (
	/* This default icon is empty with a long lived cache */
	DefaultFavIcon FavIcon = defaultFavIcon{}
)

type defaultFavIcon struct {
}

func (dfi defaultFavIcon) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	LogRequest(r, 200)
	w.Header().Set("Cache-Control", "max-age=315360000")
}

/* simple interface for a favicon */
type FavIcon interface {
	ServeHTTP(w http.ResponseWriter, r *http.Request)
}

// for debugging request headers
func LogHeaders(r *http.Request) {
	fmt.Printf("HEADERS:\n")
	for k, v := range r.Header {
		fmt.Printf("\t%s\n", k)
		for i, _ := range v {
			fmt.Printf("\t\t%s\n", v[i])
		}
	}
}

/* kindof a common log type output */
func LogRequest(r *http.Request, statusCode int) {
	var addr string
	var user_agent string

	user_agent = ""
	addr = RealIP(r)

	for k, v := range r.Header {
		if k == "User-Agent" {
			user_agent = strings.Join(v, " ")
		}
		if k == "X-Forwarded-For" {
			addr = strings.Join(v, " ")
		}
	}

	fmt.Printf("%s - - [%s] \"%s %s\" \"%s\" %d %d\n",
		addr,
		time.Now().Format(time.RFC1123Z),
		r.Method,
		r.URL.String(),
		user_agent,
		statusCode,
		r.ContentLength)
}

func RealIP(r *http.Request) string {
	rip := RealIPs(r)
	return rip[len(rip)]
}

func RealIPs(r *http.Request) (ips []string) {
	ip := r.RemoteAddr

	port_pos := strings.LastIndex(ip, ":")
	if port_pos != -1 {
		ip = ip[0:port_pos]
	}
	if ip != "" {
		ips = append(ips, ip)
	}

	val := r.Header.Get("X-Forwarded-For")
	if val != "" {
		for _, ip := range strings.Split(val, ", ") {
			ips = append(ips, ip)
		}
	}
	return ips
}
<commit_msg>httplog: off by one ...<commit_after>package httplog

import (
	"fmt"
	"net/http"
	"strings"
	"time"
)

var (
	/* This default icon is empty with a long lived cache */
	DefaultFavIcon FavIcon = defaultFavIcon{}
)

type defaultFavIcon struct {
}

func (dfi defaultFavIcon) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	LogRequest(r, 200)
	w.Header().Set("Cache-Control", "max-age=315360000")
}

/* simple interface for a favicon */
type FavIcon interface {
	ServeHTTP(w http.ResponseWriter, r *http.Request)
}

// for debugging request headers
func LogHeaders(r *http.Request) {
	fmt.Printf("HEADERS:\n")
	for k, v := range r.Header {
		fmt.Printf("\t%s\n", k)
		for i, _ := range v {
			fmt.Printf("\t\t%s\n", v[i])
		}
	}
}

/* kindof a common log type output */
func LogRequest(r *http.Request, statusCode int) {
	var addr string
	var user_agent string

	user_agent = ""
	addr = RealIP(r)

	for k, v := range r.Header {
		if k == "User-Agent" {
			user_agent = strings.Join(v, " ")
		}
		if k == "X-Forwarded-For" {
			addr = strings.Join(v, " ")
		}
	}

	fmt.Printf("%s - - [%s] \"%s %s\" \"%s\" %d %d\n",
		addr,
		time.Now().Format(time.RFC1123Z),
		r.Method,
		r.URL.String(),
		user_agent,
		statusCode,
		r.ContentLength)
}

func RealIP(r *http.Request) string {
	rip := RealIPs(r)
	return rip[len(rip)-1]
}

func RealIPs(r *http.Request) (ips []string) {
	ip := r.RemoteAddr

	port_pos := strings.LastIndex(ip, ":")
	if port_pos != -1 {
		ip = ip[0:port_pos]
	}
	if ip != "" {
		ips = append(ips, ip)
	}

	val := r.Header.Get("X-Forwarded-For")
	if val != "" {
		for _, ip := range strings.Split(val, ", ") {
			ips = append(ips, ip)
		}
	}
	return ips
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
Package pango provides a type-safe way to construct pango markup.
Using nested Span and Text nodes, pango formatted output can be easily constructed
with compile-time validation of nesting and automatic escaping.

For example, to construct pango markup for:
 Red Bold Text

the go code would be:
 pango.New(
   pango.Text("Red "),
   pango.Text("Bold Text").Bold()).
 Color(colors.Hex("#ff0000"))

or:
 pango.Text("Red ").
   Color(colors.Hex("#ff0000")).
   Append(pango.Text("Bold Text").Bold())
*/
package pango

import (
	"bytes"
	"fmt"
	"html"

	"github.com/soumya92/barista/bar"
)

type nodeType int

const (
	// ntElement is an element node with attributes and/or children.
	ntElement nodeType = iota
	// ntText is a text node with no markup or children.
	ntText
	// ntSizer is a <big> or  tag. It has no attributes,
	// and must be the only child of its parent.
	// It exists to support calls like:
	//   Text("x").Size(10.0).Smaller().Smaller().AppendText("y")
	// which would otherwise produce:
	//   xy
	// but should actually produce:
	//   xy
	ntSizer
)

// Node represents a node in a pango "document".
type Node struct {
	nodeType nodeType
	// For element nodes, this holds the tag name ("" = 'markup' node).
	// For text nodes, this holds the text content.
	content    string
	children   []*Node
	attributes map[string]string
}

// Append adds one or more nodes as children of the current node.
// The new nodes will inherit styles by virtue of being descendants,
// to insert them *adjacent* to the current node, use .Parent().Append(...).
func (n *Node) Append(nodes ...*Node) *Node {
	var insertPoint = n
	for len(insertPoint.children) == 1 &&
		insertPoint.children[0].nodeType == ntSizer {
		insertPoint = insertPoint.children[0]
	}
	for _, node := range nodes {
		if node.nodeType == ntElement && node.content == "" {
			// Collapse empty element nodes when appending, to reduce nesting.
			insertPoint.children = append(insertPoint.children, node.children...)
		} else {
			insertPoint.children = append(insertPoint.children, node)
		}
	}
	return n
}

// AppendText is a shortcut for Append(pango.Text(...), pango.Text(...), ...)
func (n *Node) AppendText(texts ...string) *Node {
	nodes := make([]*Node, len(texts))
	for i, t := range texts {
		nodes[i] = &Node{nodeType: ntText, content: t}
	}
	return n.Append(nodes...)
}

// AppendTextf is a shortcut for Append(pango.Textf(...))
func (n *Node) AppendTextf(format string, args ...interface{}) *Node {
	return n.Append(&Node{
		nodeType: ntText,
		content:  fmt.Sprintf(format, args...),
	})
}

// Concat adds the given nodes as siblings rather than children of the
// current node, and returns a wrapping node for further operations.
//
// For example,
//   Text("c").Condensed().Color(red).Concat(Text("foo")).UnderlineError()
// will create
//   cfoo
// where the appended "foo" is not condensed or red, and everything is underlined.
func (n *Node) Concat(nodes ...*Node) *Node {
	if n.nodeType != ntElement || n.content != "" {
		existingNode := *n
		n.nodeType = ntElement
		n.attributes = nil
		n.content = ""
		n.children = []*Node{&existingNode}
	}
	return n.Append(nodes...)
}

// Pango returns a pango-formatted version of the node.
func (n *Node) Pango() string {
	if n.nodeType == ntText {
		return html.EscapeString(n.content)
	}
	var out bytes.Buffer
	if n.content != "" {
		out.WriteString("<")
		out.WriteString(n.content)
		for attrName, attrVal := range n.attributes {
			out.WriteString(" ")
			out.WriteString(attrName)
			out.WriteString("='")
			out.WriteString(html.EscapeString(attrVal))
			out.WriteString("'")
		}
		out.WriteString(">")
	}
	for _, c := range n.children {
		out.WriteString(c.Pango())
	}
	if n.content != "" {
		out.WriteString("</")
		out.WriteString(n.content)
		out.WriteString(">")
	}
	return out.String()
}

// Segments implements bar.Output for a single pango Node.
func (n *Node) Segments() []*bar.Segment {
	return []*bar.Segment{bar.PangoSegment(n.Pango())}
}

// New constructs a markup node that wraps the given Nodes.
func New(children ...*Node) *Node {
	return &Node{children: children}
}

// Text constructs a text node.
func Text(s string) *Node {
	// Wrapped in a node to allow formatting, since formatting methods
	// don't work directly on text nodes.
	return New(&Node{nodeType: ntText, content: s})
}

// Textf constructs a text node by interpolating arguments.
// Note that it will escape both the format string and arguments,
// so you should use pango constructs to add formatting.
// i.e.,
//  Textf("%s", "red", "text")
// won't give you red text.
func Textf(format string, args ...interface{}) *Node {
	return Text(fmt.Sprintf(format, args...))
}
<commit_msg>Update comment to reflect the Parent() -> Concat() change<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
Package pango provides a type-safe way to construct pango markup.
Using nested Span and Text nodes, pango formatted output can be easily constructed
with compile-time validation of nesting and automatic escaping.

For example, to construct pango markup for:
 Red Bold Text

the go code would be:
 pango.New(
   pango.Text("Red "),
   pango.Text("Bold Text").Bold()).
 Color(colors.Hex("#ff0000"))

or:
 pango.Text("Red ").
   Color(colors.Hex("#ff0000")).
   Append(pango.Text("Bold Text").Bold())
*/
package pango

import (
	"bytes"
	"fmt"
	"html"

	"github.com/soumya92/barista/bar"
)

type nodeType int

const (
	// ntElement is an element node with attributes and/or children.
	ntElement nodeType = iota
	// ntText is a text node with no markup or children.
	ntText
	// ntSizer is a <big> or  tag. It has no attributes,
	// and must be the only child of its parent.
	// It exists to support calls like:
	//   Text("x").Size(10.0).Smaller().Smaller().AppendText("y")
	// which would otherwise produce:
	//   xy
	// but should actually produce:
	//   xy
	ntSizer
)

// Node represents a node in a pango "document".
type Node struct {
	nodeType nodeType
	// For element nodes, this holds the tag name ("" = 'markup' node).
	// For text nodes, this holds the text content.
	content    string
	children   []*Node
	attributes map[string]string
}

// Append adds one or more nodes as children of the current node.
// The new nodes will inherit styles by virtue of being descendants,
// to insert them *adjacent* to the current node, use .Concat(...).
func (n *Node) Append(nodes ...*Node) *Node {
	var insertPoint = n
	for len(insertPoint.children) == 1 &&
		insertPoint.children[0].nodeType == ntSizer {
		insertPoint = insertPoint.children[0]
	}
	for _, node := range nodes {
		if node.nodeType == ntElement && node.content == "" {
			// Collapse empty element nodes when appending, to reduce nesting.
			insertPoint.children = append(insertPoint.children, node.children...)
		} else {
			insertPoint.children = append(insertPoint.children, node)
		}
	}
	return n
}

// AppendText is a shortcut for Append(pango.Text(...), pango.Text(...), ...)
func (n *Node) AppendText(texts ...string) *Node {
	nodes := make([]*Node, len(texts))
	for i, t := range texts {
		nodes[i] = &Node{nodeType: ntText, content: t}
	}
	return n.Append(nodes...)
}

// AppendTextf is a shortcut for Append(pango.Textf(...))
func (n *Node) AppendTextf(format string, args ...interface{}) *Node {
	return n.Append(&Node{
		nodeType: ntText,
		content:  fmt.Sprintf(format, args...),
	})
}

// Concat adds the given nodes as siblings rather than children of the
// current node, and returns a wrapping node for further operations.
//
// For example,
//   Text("c").Condensed().Color(red).Concat(Text("foo")).UnderlineError()
// will create
//   cfoo
// where the appended "foo" is not condensed or red, and everything is underlined.
func (n *Node) Concat(nodes ...*Node) *Node {
	if n.nodeType != ntElement || n.content != "" {
		existingNode := *n
		n.nodeType = ntElement
		n.attributes = nil
		n.content = ""
		n.children = []*Node{&existingNode}
	}
	return n.Append(nodes...)
}

// Pango returns a pango-formatted version of the node.
func (n *Node) Pango() string {
	if n.nodeType == ntText {
		return html.EscapeString(n.content)
	}
	var out bytes.Buffer
	if n.content != "" {
		out.WriteString("<")
		out.WriteString(n.content)
		for attrName, attrVal := range n.attributes {
			out.WriteString(" ")
			out.WriteString(attrName)
			out.WriteString("='")
			out.WriteString(html.EscapeString(attrVal))
			out.WriteString("'")
		}
		out.WriteString(">")
	}
	for _, c := range n.children {
		out.WriteString(c.Pango())
	}
	if n.content != "" {
		out.WriteString("</")
		out.WriteString(n.content)
		out.WriteString(">")
	}
	return out.String()
}

// Segments implements bar.Output for a single pango Node.
func (n *Node) Segments() []*bar.Segment {
	return []*bar.Segment{bar.PangoSegment(n.Pango())}
}

// New constructs a markup node that wraps the given Nodes.
func New(children ...*Node) *Node {
	return &Node{children: children}
}

// Text constructs a text node.
func Text(s string) *Node {
	// Wrapped in a node to allow formatting, since formatting methods
	// don't work directly on text nodes.
	return New(&Node{nodeType: ntText, content: s})
}

// Textf constructs a text node by interpolating arguments.
// Note that it will escape both the format string and arguments,
// so you should use pango constructs to add formatting.
// i.e.,
//  Textf("%s", "red", "text")
// won't give you red text.
func Textf(format string, args ...interface{}) *Node {
	return Text(fmt.Sprintf(format, args...))
}
<|endoftext|>


<commit_before>// The idx package provides a metadata index for metrics

package idx

import (
	"encoding/hex"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	schema "gopkg.in/raintank/schema.v1"
)

var (
	BothBranchAndLeaf  = errors.New("node can't be both branch and leaf")
	BranchUnderLeaf    = errors.New("can't add branch under leaf")
	errInvalidQuery    = errors.New("invalid query")
	errInvalidIdString = errors.New("invalid ID string")
)

//go:generate msgp
type Node struct {
	Path        string
	Leaf        bool
	Defs        []Archive
	HasChildren bool
}

type Archive struct {
	schema.MetricDefinition
	SchemaId uint16 // index in mdata.schemas (not persisted)
	AggId    uint16 // index in mdata.aggregations (not persisted)
	LastSave uint32 // last time the metricDefinition was saved to a backend store (cassandra)
}

type MetricID struct {
	org int
	key [16]byte
}

func NewMetricIDFromString(s string) (MetricID, error) {
	id := MetricID{}
	err := id.FromString(s)
	return id, err
}

func (id *MetricID) FromString(s string) error {
	splits := strings.Split(s, ".")
	if len(splits) != 2 || len(splits[1]) != 32 {
		return errInvalidIdString
	}

	var err error
	id.org, err = strconv.Atoi(splits[0])
	if err != nil {
		return err
	}

	dst := make([]byte, 16)
	n, err := hex.Decode(dst, []byte(splits[1]))
	if n != 16 {
		return errInvalidIdString
	}
	copy(id.key[:], dst)
	return nil
}

func (id *MetricID) String() string {
	return fmt.Sprintf("%d.%x", id.org, id.key)
}

// used primarily by tests, for convenience
func NewArchiveBare(name string) Archive {
	return Archive{
		MetricDefinition: schema.MetricDefinition{
			Name: name,
		},
	}
}

/*
Currently the index is solely used for supporting Graphite style queries.
So, the index only needs to be able to search by a pattern that matches the
MetricDefinition.Name field. In future we plan to extend the searching
capabilities to include the other fields in the definition.

Note:

* metrictank is a multi-tenant system where different orgs cannot see each
  other's data

* any given metric may appear multiple times, under different organisations

* Each metric path can be mapped to multiple metricDefinitions in the case that
  fields other then the Name vary.  The most common occurrence of this is when
  the Interval at which the metric is being collected has changed.

Interface

* Init()
  This is the initialization step performed at startup. This method should
  block until the index is ready to handle searches.

* Stop():
 This will be called when metrictank is shutting down.

* AddOrUpdate(*schema.MetricData, int32) Archive:
  Every metric received will result in a call to this method to ensure the
  metric has been added to the index. The method is passed the metricData
  payload and the partition id of the metric

* Get(string) (Archive, bool):
  This method should return the MetricDefintion with the passed Id.

* GetPath(string) (Archive, bool) []Archive:
  This method should return the archives under the given path

* List(int) []Archive:
  This method should return all MetricDefinitions for the passed OrgId.  If the
  passed OrgId is "-1", then all metricDefinitions across all organisations
  should be returned.

* Find(int, string, int64) ([]Node, error):
  This method provides searches.  The method is passed an OrgId, a query
  pattern and a unix timestamp. Searches should return all nodes that match for
  the given OrgId and OrgId -1.  The pattern should be handled in the same way
  Graphite would. see https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards
  And the unix stimestamp is used to ignore series that have been stale since
  the timestamp.

* Delete(int, string) ([]Archive, error):
  This method is used for deleting items from the index. The method is passed
  an OrgId and a query pattern.  If the pattern matches a branch node, then
  all leaf nodes on that branch should also be deleted. So if the pattern is
  "*", all items in the index should be deleted.  A copy of all of the
  metricDefinitions deleted are returned.

* Prune(int, time.Time) ([]Archive, error):
  This method should delete all metrics from the index for the passed org where
  the last time the metric was seen is older then the passed timestamp. If the org
  passed is -1, then the all orgs should be examined for stale metrics to be deleted.
  The method returns a list of the metricDefinitions deleted from the index and any
  error encountered.

* TagList(int, string, int64) ([]string, error):
  This method returns a list of all tag keys associated with the metrics of a given
  organization. The return values are filtered by the regex in the second parameter.
  If the third parameter is >0 then only metrics will be account of which the
  LastUpdate time is >= the given value.

* TagDetails(int, string, string, int64) map[string]uint32:
  This method returns a list of all values associated with a given tag key in the
  given org. The occurences of each value is counted and the count is referred to by
  the series ids in the returned map.
  If the third parameter is not "" it will be used as a regular expression to filter
  the values before accouting for them.
  If the fourth parameter is > 0 then the metrics
  will be filtered and only those of which the LastUpdate time is >= the from
  timestamp will be considered while the others are being ignored.

* FindByTag(int, []string, int64) ([]string, error):
  This method takes a list of expressions in the format key<operator>value.
  The allowed operators are: =, !=, =~, !=~.
  It returns a slice of Metric names that match the given conditions, the
  conditions are logically AND-ed.
  If the third argument is > 0 then the results will be filtered and only those
  where the LastUpdate time is >= from will be returned as results.
*/

type MetricIndex interface {
	Init() error
	Stop()
	AddOrUpdate(*schema.MetricData, int32) Archive
	Get(string) (Archive, bool)
	GetPath(int, string) []Archive
	Delete(int, string) ([]Archive, error)
	Find(int, string, int64) ([]Node, error)
	List(int) []Archive
	Prune(int, time.Time) ([]Archive, error)
	FindByTag(int, []string, int64) ([]string, error)
	Tags(int, string, int64) ([]string, error)
	TagDetails(int, string, string, int64) (map[string]uint64, error)
}
<commit_msg>comments<commit_after>// The idx package provides a metadata index for metrics

package idx

import (
	"encoding/hex"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	schema "gopkg.in/raintank/schema.v1"
)

var (
	BothBranchAndLeaf  = errors.New("node can't be both branch and leaf")
	BranchUnderLeaf    = errors.New("can't add branch under leaf")
	errInvalidQuery    = errors.New("invalid query")
	errInvalidIdString = errors.New("invalid ID string")
)

//go:generate msgp
type Node struct {
	Path        string
	Leaf        bool
	Defs        []Archive
	HasChildren bool
}

type Archive struct {
	schema.MetricDefinition
	SchemaId uint16 // index in mdata.schemas (not persisted)
	AggId    uint16 // index in mdata.aggregations (not persisted)
	LastSave uint32 // last time the metricDefinition was saved to a backend store (cassandra)
}

type MetricID struct {
	org int
	key [16]byte
}

func NewMetricIDFromString(s string) (MetricID, error) {
	id := MetricID{}
	err := id.FromString(s)
	return id, err
}

func (id *MetricID) FromString(s string) error {
	splits := strings.Split(s, ".")
	if len(splits) != 2 || len(splits[1]) != 32 {
		return errInvalidIdString
	}

	var err error
	id.org, err = strconv.Atoi(splits[0])
	if err != nil {
		return err
	}

	dst := make([]byte, 16)
	n, err := hex.Decode(dst, []byte(splits[1]))
	if n != 16 {
		return errInvalidIdString
	}
	copy(id.key[:], dst)
	return nil
}

func (id *MetricID) String() string {
	return fmt.Sprintf("%d.%x", id.org, id.key)
}

// used primarily by tests, for convenience
func NewArchiveBare(name string) Archive {
	return Archive{
		MetricDefinition: schema.MetricDefinition{
			Name: name,
		},
	}
}

/*
Currently the index is solely used for supporting Graphite style queries.
So, the index only needs to be able to search by a pattern that matches the
MetricDefinition.Name field. In future we plan to extend the searching
capabilities to include the other fields in the definition.

Note:

* metrictank is a multi-tenant system where different orgs cannot see each
  other's data

* any given metric may appear multiple times, under different organisations

* Each metric path can be mapped to multiple metricDefinitions in the case that
  fields other then the Name vary.  The most common occurrence of this is when
  the Interval at which the metric is being collected has changed.

Interface

* Init()
  This is the initialization step performed at startup. This method should
  block until the index is ready to handle searches.

* Stop():
 This will be called when metrictank is shutting down.

* AddOrUpdate(*schema.MetricData, int32) Archive:
  Every metric received will result in a call to this method to ensure the
  metric has been added to the index. The method is passed the metricData
  payload and the partition id of the metric

* Get(string) (Archive, bool):
  This method should return the MetricDefintion with the passed Id.

* GetPath(string) (Archive, bool) []Archive:
  This method should return the archives under the given path

* List(int) []Archive:
  This method should return all MetricDefinitions for the passed OrgId.  If the
  passed OrgId is "-1", then all metricDefinitions across all organisations
  should be returned.

* Find(int, string, int64) ([]Node, error):
  This method provides searches.  The method is passed an OrgId, a query
  pattern and a unix timestamp. Searches should return all nodes that match for
  the given OrgId and OrgId -1.  The pattern should be handled in the same way
  Graphite would. see https://graphite.readthedocs.io/en/latest/render_api.html#paths-and-wildcards
  And the unix stimestamp is used to ignore series that have been stale since
  the timestamp.

* Delete(int, string) ([]Archive, error):
  This method is used for deleting items from the index. The method is passed
  an OrgId and a query pattern.  If the pattern matches a branch node, then
  all leaf nodes on that branch should also be deleted. So if the pattern is
  "*", all items in the index should be deleted.  A copy of all of the
  metricDefinitions deleted are returned.

* Prune(int, time.Time) ([]Archive, error):
  This method should delete all metrics from the index for the passed org where
  the last time the metric was seen is older then the passed timestamp. If the org
  passed is -1, then the all orgs should be examined for stale metrics to be deleted.
  The method returns a list of the metricDefinitions deleted from the index and any
  error encountered.

* Tags(int, string, int64) ([]string, error):
  This method returns a list of all tag keys associated with the metrics of a given
  organization. The return values are filtered by the regex in the second parameter.
  If the third parameter is >0 then only metrics will be accounted of which the
  LastUpdate time is >= the given value.

* TagDetails(int, string, string, int64) map[string]uint64:
  This method returns a list of all values associated with a given tag key in the
  given org. The occurences of each value is counted and the count is referred to by
  the metric names in the returned map.
  If the third parameter is not "" it will be used as a regular expression to filter
  the values before accouting for them.
  If the fourth parameter is > 0 then the metrics will be filtered and only those
  of which the LastUpdate time is >= the from timestamp will be considered while
  the others are being ignored.

* FindByTag(int, []string, int64) ([]string, error):
  This method takes a list of expressions in the format key<operator>value.
  The allowed operators are: =, !=, =~, !=~.
  It returns a slice of metric names that match the given conditions, the
  conditions are logically AND-ed.
  If the third argument is > 0 then the results will be filtered and only those
  where the LastUpdate time is >= from will be returned as results.
*/

type MetricIndex interface {
	Init() error
	Stop()
	AddOrUpdate(*schema.MetricData, int32) Archive
	Get(string) (Archive, bool)
	GetPath(int, string) []Archive
	Delete(int, string) ([]Archive, error)
	Find(int, string, int64) ([]Node, error)
	List(int) []Archive
	Prune(int, time.Time) ([]Archive, error)
	FindByTag(int, []string, int64) ([]string, error)
	Tags(int, string, int64) ([]string, error)
	TagDetails(int, string, string, int64) (map[string]uint64, error)
}
<|endoftext|>


<commit_before>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package api

import (
	"fmt"
	"net/url"

	"github.com/google/go-querystring/query"
)

// FallBackServerOrg holds fallback server organization
type FallBackServerOrg struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

// FallBackServer holds organization fallback servers
type FallBackServer struct {
	ID           int               `json:"id,omitempty"`
	Address      string            `json:"address"`
	Protocol     int               `json:"protocol"`
	Port         int               `json:"port"`
	RequireTLS   bool              `json:"require_tls"`
	Enabled      bool              `json:"enabled"`
	Organization FallBackServerOrg `json:"organization"`
}

// GetFallBackServer returns radius settings
// https://www.baruwa.com/docs/api/#retrieve-a-fallback-server
func (c *Client) GetFallBackServer(serverID int) (server *FallBackServer, err error) {
	if serverID <= 0 {
		err = fmt.Errorf("The serverID param should be > 0")
		return
	}

	err = c.get(fmt.Sprintf("failbackservers/%d", serverID), nil, server)

	return
}

// CreateFallBackServer creates radius settings
// https://www.baruwa.com/docs/api/#create-a-fallback-server
func (c *Client) CreateFallBackServer(organizationID int, server *FallBackServer) (err error) {
	var v url.Values

	if organizationID <= 0 {
		err = fmt.Errorf("The organizationID param should be > 0")
		return
	}

	if server == nil {
		err = fmt.Errorf("The server param cannot be nil")
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.post(fmt.Sprintf("failbackservers/%d", organizationID), v, server)

	return
}

// UpdateFallBackServer updates radius settings
// https://www.baruwa.com/docs/api/#update-a-fallback-server
func (c *Client) UpdateFallBackServer(server *FallBackServer) (err error) {
	var v url.Values

	if server == nil {
		err = fmt.Errorf("The server param cannot be nil")
		return
	}

	if server.ID <= 0 {
		err = fmt.Errorf("The server.ID param should be > 0")
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.put(fmt.Sprintf("failbackservers/%d", server.ID), v, server)

	return
}

// DeleteFallBackServer deletes radius settings
// https://www.baruwa.com/docs/api/#delete-a-fallback-server
func (c *Client) DeleteFallBackServer(server *FallBackServer) (err error) {
	var v url.Values

	if server == nil {
		err = fmt.Errorf("The server param cannot be nil")
		return
	}

	if server.ID <= 0 {
		err = fmt.Errorf("The server.ID param should be > 0")
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.delete(fmt.Sprintf("failbackservers/%d", server.ID), v)

	return
}
<commit_msg>FET: Add Fallback Server Implementation<commit_after>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package api

import (
	"fmt"
	"net/url"

	"github.com/google/go-querystring/query"
)

// FallBackServerOrg holds fallback server organization
type FallBackServerOrg struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

// FallBackServer holds organization fallback servers
type FallBackServer struct {
	ID           int                `json:"id,omitempty"`
	Address      string             `json:"address"`
	Protocol     int                `json:"protocol"`
	Port         int                `json:"port"`
	RequireTLS   bool               `json:"require_tls"`
	Enabled      bool               `json:"enabled"`
	Organization *FallBackServerOrg `json:"organization"`
}

// FallBackServerList holds users
type FallBackServerList struct {
	Items []FallBackServer `json:"items"`
	Links Links            `json:"links"`
	Meta  Meta             `json:"meta"`
}

// GetFallBackServers returns a FallBackServerList object
// This contains a paginated list of fallback servers and links
// to the neigbouring pages.
// https://www.baruwa.com/docs/api/#fallback-servers
func (c *Client) GetFallBackServers(organizationID int, opts *ListOptions) (l *FallBackServerList, err error) {
	if organizationID <= 0 {
		err = fmt.Errorf(organizationIDError)
		return
	}

	l = &FallBackServerList{}

	err = c.get(fmt.Sprintf("failbackservers/%d", organizationID), opts, l)

	return
}

// GetFallBackServer returns radius settings
// https://www.baruwa.com/docs/api/#retrieve-a-fallback-server
func (c *Client) GetFallBackServer(serverID int) (server *FallBackServer, err error) {
	if serverID <= 0 {
		err = fmt.Errorf(serverIDError)
		return
	}

	server = &FallBackServer{}

	err = c.get(fmt.Sprintf("failbackservers/%d", serverID), nil, server)

	return
}

// CreateFallBackServer creates radius settings
// https://www.baruwa.com/docs/api/#create-a-fallback-server
func (c *Client) CreateFallBackServer(organizationID int, server *FallBackServer) (err error) {
	var v url.Values

	if organizationID <= 0 {
		err = fmt.Errorf(organizationIDError)
		return
	}

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.post(fmt.Sprintf("failbackservers/%d", organizationID), v, server)

	return
}

// UpdateFallBackServer updates radius settings
// https://www.baruwa.com/docs/api/#update-a-fallback-server
func (c *Client) UpdateFallBackServer(server *FallBackServer) (err error) {
	var v url.Values

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if server.ID <= 0 {
		err = fmt.Errorf(serverSIDError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.put(fmt.Sprintf("failbackservers/%d", server.ID), v, server)

	return
}

// DeleteFallBackServer deletes radius settings
// https://www.baruwa.com/docs/api/#delete-a-fallback-server
func (c *Client) DeleteFallBackServer(server *FallBackServer) (err error) {
	var v url.Values

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if server.ID <= 0 {
		err = fmt.Errorf(serverSIDError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.delete(fmt.Sprintf("failbackservers/%d", server.ID), v)

	return
}
<|endoftext|>


<commit_before>package gitosis

import (
	"github.com/timeredbull/tsuru/config"
	. "launchpad.net/gocheck"
	"os"
	"os/exec"
	"path"
	"testing"
)

func Test(t *testing.T) { TestingT(t) }

type S struct {
	gitRoot     string
	gitosisBare string
	gitosisRepo string
}

var _ = Suite(&S{})

func (s *S) SetUpSuite(c *C) {
	err := config.ReadConfigFile("../../../etc/tsuru.conf")
	c.Assert(err, IsNil)
	s.gitRoot, err = config.GetString("git:root")
	c.Assert(err, IsNil)
	s.gitosisBare, err = config.GetString("git:gitosis-bare")
	c.Assert(err, IsNil)
	s.gitosisRepo, err = config.GetString("git:gitosis-repo")
	currentDir := os.Getenv("PWD")
	err = os.Mkdir(s.gitRoot, 0777)
	c.Assert(err, IsNil)
	err = os.Chdir(s.gitRoot)
	c.Assert(err, IsNil)
	err = exec.Command("ls").Run()
	c.Assert(err, IsNil)
	err = exec.Command("git", "init", "--bare", "gitosis-admin.git").Run()
	c.Assert(err, IsNil)
	err = exec.Command("git", "clone", "gitosis-admin.git").Run()
	c.Assert(err, IsNil)
	err = os.Chdir(currentDir)
	c.Assert(err, IsNil)
}

func (s *S) SetUpTest(c *C) {
	pwd, err := os.Getwd()
	c.Assert(err, IsNil)
	err = os.Chdir(path.Join(s.gitRoot, "gitosis-admin"))
	_, err = os.Create("gitosis.conf")
	c.Assert(err, IsNil)
	err = os.Chdir(pwd)
}

func (s *S) TearDownSuite(c *C) {
	err := os.RemoveAll(s.gitRoot)
	c.Assert(err, IsNil)
}

func (s *S) TearDownTest(c *C) {
	pwd, err := os.Getwd()
	c.Assert(err, IsNil)
	err = os.Chdir(path.Join(s.gitRoot, "gitosis-admin"))
	err = exec.Command("git", "rm", "gitosis.conf").Run()
	if err == nil {
		err = pushToGitosis("removing test file")
		c.Assert(err, IsNil)
	}
	err = os.Chdir(pwd)
}

func (s *S) lastBareCommit(c *C) string {
	pwd, err := os.Getwd()
	c.Assert(err, IsNil)
	os.Chdir(s.gitosisBare)
	bareOutput, err := exec.Command("git", "log", "-1", "--pretty=format:%s").CombinedOutput()
	c.Assert(err, IsNil)
	os.Chdir(pwd)
	return string(bareOutput)
}
<commit_msg>gitosis: using MkdirAll instead of Mkdir<commit_after>package gitosis

import (
	"github.com/timeredbull/tsuru/config"
	. "launchpad.net/gocheck"
	"os"
	"os/exec"
	"path"
	"testing"
)

func Test(t *testing.T) { TestingT(t) }

type S struct {
	gitRoot     string
	gitosisBare string
	gitosisRepo string
}

var _ = Suite(&S{})

func (s *S) SetUpSuite(c *C) {
	err := config.ReadConfigFile("../../../etc/tsuru.conf")
	c.Assert(err, IsNil)
	s.gitRoot, err = config.GetString("git:root")
	c.Assert(err, IsNil)
	s.gitosisBare, err = config.GetString("git:gitosis-bare")
	c.Assert(err, IsNil)
	s.gitosisRepo, err = config.GetString("git:gitosis-repo")
	currentDir := os.Getenv("PWD")
	err = os.MkdirAll(s.gitRoot, 0777)
	c.Assert(err, IsNil)
	err = os.Chdir(s.gitRoot)
	c.Assert(err, IsNil)
	err = exec.Command("ls").Run()
	c.Assert(err, IsNil)
	err = exec.Command("git", "init", "--bare", "gitosis-admin.git").Run()
	c.Assert(err, IsNil)
	err = exec.Command("git", "clone", "gitosis-admin.git").Run()
	c.Assert(err, IsNil)
	err = os.Chdir(currentDir)
	c.Assert(err, IsNil)
}

func (s *S) SetUpTest(c *C) {
	pwd, err := os.Getwd()
	c.Assert(err, IsNil)
	err = os.Chdir(path.Join(s.gitRoot, "gitosis-admin"))
	_, err = os.Create("gitosis.conf")
	c.Assert(err, IsNil)
	err = os.Chdir(pwd)
}

func (s *S) TearDownSuite(c *C) {
	err := os.RemoveAll(s.gitRoot)
	c.Assert(err, IsNil)
}

func (s *S) TearDownTest(c *C) {
	pwd, err := os.Getwd()
	c.Assert(err, IsNil)
	err = os.Chdir(path.Join(s.gitRoot, "gitosis-admin"))
	err = exec.Command("git", "rm", "gitosis.conf").Run()
	if err == nil {
		err = pushToGitosis("removing test file")
		c.Assert(err, IsNil)
	}
	err = os.Chdir(pwd)
}

func (s *S) lastBareCommit(c *C) string {
	pwd, err := os.Getwd()
	c.Assert(err, IsNil)
	os.Chdir(s.gitosisBare)
	bareOutput, err := exec.Command("git", "log", "-1", "--pretty=format:%s").CombinedOutput()
	c.Assert(err, IsNil)
	os.Chdir(pwd)
	return string(bareOutput)
}
<|endoftext|>


<commit_before>// Copyright 2015 The rkt Authors
//
// 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 testutils

import (
	"fmt"
	"net"
	"strings"

	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/vishvananda/netlink"
)

func getDefaultGW(family int) (string, error) {
	l, err := netlink.LinkByName("lo")
	if err != nil {
		return "", err
	}

	routes, err := netlink.RouteList(l, family)
	if err != nil {
		return "", err
	}

	return routes[0].Gw.String(), nil
}
func GetDefaultGWv4() (string, error) {
	return getDefaultGW(netlink.FAMILY_V4)
}

func GetDefaultGWv6() (string, error) {
	return getDefaultGW(netlink.FAMILY_V6)
}

func GetIPs(ifaceWanted string, familyWanted int) ([]string, error) {
	ips := make([]string, 0)
	ifaces, err := net.Interfaces()
	if err != nil {
		return ips, err
	}
	for _, iface := range ifaces {
		if iface.Name != ifaceWanted {
			continue
		}

		addrs, _ := iface.Addrs()
		for _, addr := range addrs {
			addrString := addr.String()
			ip, _, err := net.ParseCIDR(addrString)
			if err != nil {
				return ips, err
			}

			if strings.Contains(addrString, ".") && familyWanted == netlink.FAMILY_V4 ||
				strings.Contains(addrString, ":") && familyWanted == netlink.FAMILY_V6 {
				ips = append(ips, ip.String())
			}
		}
	}
	return ips, err
}

func GetIPsv4(iface string) ([]string, error) {
	return GetIPs(iface, netlink.FAMILY_V4)
}
func GetIPsv6(iface string) ([]string, error) {
	return GetIPs(iface, netlink.FAMILY_V6)
}

func GetGW(iface string, family int) (string, error) {
	return "", fmt.Errorf("Not implemented")
}
func GetGWv4(iface string) (string, error) {
	return GetGW(iface, netlink.FAMILY_V4)
}

func GetGWv6(iface string) (string, error) {
	return GetGW(iface, netlink.FAMILY_V4)
}
<commit_msg>testutils: extend iputils with iface discovery<commit_after>// Copyright 2015 The rkt Authors
//
// 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 testutils

import (
	"fmt"
	"net"
	"strings"

	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/vishvananda/netlink"
)

func getDefaultGW(family int) (string, error) {
	l, err := netlink.LinkByName("lo")
	if err != nil {
		return "", err
	}

	routes, err := netlink.RouteList(l, family)
	if err != nil {
		return "", err
	}

	return routes[0].Gw.String(), nil
}
func GetDefaultGWv4() (string, error) {
	return getDefaultGW(netlink.FAMILY_V4)
}

func GetDefaultGWv6() (string, error) {
	return getDefaultGW(netlink.FAMILY_V6)
}

func GetIPs(ifaceWanted string, familyWanted int) ([]string, error) {
	ips := make([]string, 0)
	ifaces, err := net.Interfaces()
	if err != nil {
		return ips, err
	}
	for _, iface := range ifaces {
		if iface.Name != ifaceWanted {
			continue
		}

		addrs, _ := iface.Addrs()
		for _, addr := range addrs {
			addrString := addr.String()
			ip, _, err := net.ParseCIDR(addrString)
			if err != nil {
				return ips, err
			}

			if strings.Contains(addrString, ".") && familyWanted == netlink.FAMILY_V4 ||
				strings.Contains(addrString, ":") && familyWanted == netlink.FAMILY_V6 {
				ips = append(ips, ip.String())
			}
		}
	}
	return ips, err
}

func GetIPsv4(iface string) ([]string, error) {
	return GetIPs(iface, netlink.FAMILY_V4)
}
func GetIPsv6(iface string) ([]string, error) {
	return GetIPs(iface, netlink.FAMILY_V6)
}

func GetGW(iface string, family int) (string, error) {
	return "", fmt.Errorf("Not implemented")
}
func GetGWv4(iface string) (string, error) {
	return GetGW(iface, netlink.FAMILY_V4)
}

func GetGWv6(iface string) (string, error) {
	return GetGW(iface, netlink.FAMILY_V4)
}

func GetNonLoIfaceWithAddrs() (iface net.Interface, err error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return iface, err
	}

	for _, i := range ifaces {
		if i.Flags&net.FlagLoopback == 0 {
			ifaceNameLower := strings.ToLower(i.Name)
			// Don't use rkt's interfaces
			if strings.HasSuffix(ifaceNameLower, "cni") ||
				strings.HasSuffix(ifaceNameLower, "veth") {
				continue
			}
			addrs, err := i.Addrs()
			if err != nil {
				return iface, fmt.Errorf("Cannot get IPV4 address for interface %v: %v", i.Name, err)
			}
			if len(addrs) > 0 {
				iface = i
				break
			}
		}
	}
	return iface, err
}

func GetNonLoIfaceIPv4() (string, error) {
	iface, err := GetNonLoIfaceWithAddrs()
	if err != nil {
		return "", fmt.Errorf("Error while getting non-lo host interface: %v\n", err)
	}
	if iface.Name == "" {
		return "", nil
	}

	ifaceIPsv4, err := GetIPsv4(iface.Name)
	if err != nil {
		return "", fmt.Errorf("Cannot get IPV4 address for interface %v: %v", iface.Name, err)
	}
	if len(ifaceIPsv4) == 0 {
		return "", nil
	}
	return ifaceIPsv4[0], nil
}
<|endoftext|>


<commit_before>//
//  Majordomo Protocol client example - asynchronous.
//  Uses the mdcli API to hide all MDP aspects
//
//  Lets us build this source without creating a library
package main

import (
	"github.com/pebbe/zmq2/examples/mdapi"

	"fmt"
	"os"
)

func main() {
	var verbose bool
	if len(os.Args) > 1 && os.Args[1] == "-v" {
		verbose = true
	}
	session, _ := mdapi.NewMdcli2("tcp://localhost:5555", verbose)

    var count int
    for count = 0; count < 100000; count++ {
		session.Send("echo", "Hello world")
    }
    for count = 0; count < 100000; count++ {
		_, err := session.Recv()
		if err != nil {
			break	      //  Interrupted by Ctrl-C
		}
    }
    fmt.Printf("%d replies received\n", count)
}
<commit_msg>Modified example: mdclient2<commit_after>//
//  Majordomo Protocol client example - asynchronous.
//  Uses the mdcli API to hide all MDP aspects
//
//  Lets us build this source without creating a library
package main

import (
	"github.com/pebbe/zmq2/examples/mdapi"

	"fmt"
	"log"
	"os"
)

func main() {
	var verbose bool
	if len(os.Args) > 1 && os.Args[1] == "-v" {
		verbose = true
	}
	session, _ := mdapi.NewMdcli2("tcp://localhost:5555", verbose)

	var count int
	for count = 0; count < 100000; count++ {
		err := session.Send("echo", "Hello world")
		if err != nil {
			log.Println("Send:", err)
			break
		}
	}
	for count = 0; count < 100000; count++ {
		_, err := session.Recv()
		if err != nil {
			log.Println("Recv:", err)
			break
		}
	}
	fmt.Printf("%d replies received\n", count)
}
<|endoftext|>


<commit_before>package scene

import (
	"image/color"
	"math"
	"strconv"
	"sync"
	"time"

	"github.com/pankona/gomo-simra/simra"
	"github.com/pankona/gomo-simra/simra/image"
)

// Title represents a scene object for Title
type Title struct {
	simra        simra.Simraer
	screenWidth  int
	screenHeight int
	sprites      []simra.Spriter
	numOfSprite  simra.Spriter
	fps          int
	fpsText      simra.Spriter
	mu           sync.Mutex
	kokeshiTex   *simra.Texture
}

// Initialize initializes title scene
// This is called from simra.
// simra.SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (t *Title) Initialize(sim simra.Simraer) {
	t.simra = sim

	t.screenHeight = 1080 / 2
	t.screenWidth = 1920 / 2
	t.simra.SetDesiredScreenSize((float32)(t.screenHeight), (float32)(t.screenWidth))

	// initialize sprites
	t.initialize()

	t.numOfSprite = t.simra.NewSprite()
	t.numOfSprite.SetPosition(float32(t.screenWidth/2), 100)
	t.numOfSprite.SetScale(float32(t.screenWidth), 80)
	t.simra.AddSprite(t.numOfSprite)

	tex := t.simra.NewTextTexture("0",
		60, color.RGBA{255, 255, 255, 255}, image.Rect(0, 0, float32(t.screenWidth), 80))
	t.numOfSprite.ReplaceTexture(tex)

	t.fpsText = t.simra.NewSprite()
	t.fpsText.SetPosition(float32(t.screenWidth/4), 100)
	t.fpsText.SetScale(float32(t.screenWidth), 80)
	t.simra.AddSprite(t.fpsText)

	tex = t.simra.NewTextTexture("0",
		60, color.RGBA{255, 255, 255, 255}, image.Rect(0, 0, float32(t.screenWidth), 80))
	t.fpsText.ReplaceTexture(tex)
	go func() {
		for {
			<-time.After(1 * time.Second)
			tex = t.simra.NewTextTexture(strconv.Itoa(t.fps),
				60, color.RGBA{255, 255, 255, 255}, image.Rect(0, 0, float32(t.screenWidth), 80))
			t.fpsText.ReplaceTexture(tex)
			t.mu.Lock()
			t.fps = 0
			t.mu.Unlock()
		}
	}()

	t.kokeshiTex = t.simra.NewImageTexture("sample2.png", image.Rect(0, 0, 64, 64))
}

func (t *Title) initialize() {
	t.simra.AddTouchListener(t)
}

var degree int

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (t *Title) Drive() {
	degree = (degree - 1) % 360
	for i := range t.sprites {
		r := float32(degree) * math.Pi / 180
		t.sprites[i].SetRotate(r)
	}
	t.mu.Lock()
	t.fps++
	t.mu.Unlock()
	//runtime.GC()
}

// OnTouchBegin is called when Title scene is Touched.
// It is caused by calling AddtouchListener for title.background sprite.
func (t *Title) OnTouchBegin(x, y float32) {
	t.spawnKokeshi(x, y)
}

// OnTouchMove is called when Title scene is Touched and moved.
// It is caused by calling AddtouchListener for title.background sprite.
func (t *Title) OnTouchMove(x, y float32) {
	t.spawnKokeshi(x, y)
}

// OnTouchEnd is called when Title scene is Touched and it is released.
// It is caused by calling AddtouchListener for title.background sprite.
func (t *Title) OnTouchEnd(x, y float32) {
	t.spawnKokeshi(x, y)
}

func (t *Title) spawnKokeshi(x, y float32) {
	// scene end. go to next scene
	sprite := t.simra.NewSprite()
	sprite.SetPosition(x, y)
	sprite.SetScale(128, 128)
	t.simra.AddSprite(sprite)
	t.sprites = append(t.sprites, sprite)
	sprite.ReplaceTexture(t.kokeshiTex)

	tex := t.simra.NewTextTexture(strconv.Itoa(len(t.sprites)),
		60, color.RGBA{255, 255, 255, 255}, image.Rect(0, 0, float32(t.screenWidth), 80))
	t.numOfSprite.ReplaceTexture(tex)

	// later sprite goes far side
	t.simra.SetZIndex(sprite, len(t.sprites))
}
<commit_msg>[#66] remove inappropriate comments<commit_after>package scene

import (
	"image/color"
	"math"
	"strconv"
	"sync"
	"time"

	"github.com/pankona/gomo-simra/simra"
	"github.com/pankona/gomo-simra/simra/image"
)

// Title represents a scene object for Title
type Title struct {
	simra        simra.Simraer
	screenWidth  int
	screenHeight int
	sprites      []simra.Spriter
	numOfSprite  simra.Spriter
	fps          int
	fpsText      simra.Spriter
	mu           sync.Mutex
	kokeshiTex   *simra.Texture
}

// Initialize initializes title scene
// This is called from simra.
// simra.SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (t *Title) Initialize(sim simra.Simraer) {
	t.simra = sim

	t.screenHeight = 1080 / 2
	t.screenWidth = 1920 / 2
	t.simra.SetDesiredScreenSize((float32)(t.screenHeight), (float32)(t.screenWidth))

	// initialize sprites
	t.initialize()

	t.numOfSprite = t.simra.NewSprite()
	t.numOfSprite.SetPosition(float32(t.screenWidth/2), 100)
	t.numOfSprite.SetScale(float32(t.screenWidth), 80)
	t.simra.AddSprite(t.numOfSprite)

	tex := t.simra.NewTextTexture("0",
		60, color.RGBA{255, 255, 255, 255}, image.Rect(0, 0, float32(t.screenWidth), 80))
	t.numOfSprite.ReplaceTexture(tex)

	t.fpsText = t.simra.NewSprite()
	t.fpsText.SetPosition(float32(t.screenWidth/4), 100)
	t.fpsText.SetScale(float32(t.screenWidth), 80)
	t.simra.AddSprite(t.fpsText)

	tex = t.simra.NewTextTexture("0",
		60, color.RGBA{255, 255, 255, 255}, image.Rect(0, 0, float32(t.screenWidth), 80))
	t.fpsText.ReplaceTexture(tex)
	go func() {
		for {
			<-time.After(1 * time.Second)
			tex = t.simra.NewTextTexture(strconv.Itoa(t.fps),
				60, color.RGBA{255, 255, 255, 255}, image.Rect(0, 0, float32(t.screenWidth), 80))
			t.fpsText.ReplaceTexture(tex)
			t.mu.Lock()
			t.fps = 0
			t.mu.Unlock()
		}
	}()

	t.kokeshiTex = t.simra.NewImageTexture("sample2.png", image.Rect(0, 0, 64, 64))
}

func (t *Title) initialize() {
	t.simra.AddTouchListener(t)
}

var degree int

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (t *Title) Drive() {
	degree = (degree - 1) % 360
	for i := range t.sprites {
		r := float32(degree) * math.Pi / 180
		t.sprites[i].SetRotate(r)
	}
	t.mu.Lock()
	t.fps++
	t.mu.Unlock()
	//runtime.GC()
}

// OnTouchBegin is called when Title scene is Touched.
// It is caused by calling AddtouchListener for title.background sprite.
func (t *Title) OnTouchBegin(x, y float32) {
	t.spawnKokeshi(x, y)
}

// OnTouchMove is called when Title scene is Touched and moved.
// It is caused by calling AddtouchListener for title.background sprite.
func (t *Title) OnTouchMove(x, y float32) {
	t.spawnKokeshi(x, y)
}

// OnTouchEnd is called when Title scene is Touched and it is released.
// It is caused by calling AddtouchListener for title.background sprite.
func (t *Title) OnTouchEnd(x, y float32) {
	t.spawnKokeshi(x, y)
}

func (t *Title) spawnKokeshi(x, y float32) {
	sprite := t.simra.NewSprite()
	sprite.SetPosition(x, y)
	sprite.SetScale(128, 128)
	t.simra.AddSprite(sprite)
	t.sprites = append(t.sprites, sprite)
	sprite.ReplaceTexture(t.kokeshiTex)

	tex := t.simra.NewTextTexture(strconv.Itoa(len(t.sprites)),
		60, color.RGBA{255, 255, 255, 255}, image.Rect(0, 0, float32(t.screenWidth), 80))
	t.numOfSprite.ReplaceTexture(tex)

	// later sprite goes far side
	t.simra.SetZIndex(sprite, len(t.sprites))
}
<|endoftext|>