<commit_before>package async

import (
	"container/list"
	"errors"
	"sync"
	"time"
)

type command struct {
	action   int8
	keys     []interface{}
	values   []interface{}
	callback chan []interface{}
}

type item struct {
	key    interface{}
	expire int64
}

type TTLCache struct {
	data      map[interface{}]interface{}
	ttl       *list.List
	index     map[interface{}]*list.Element
	expire    time.Duration
	queue     chan command
	shutdown  chan bool
	desLock   sync.RWMutex
	isDestory bool
}

func NewTTLCache(expire time.Duration) *TTLCache {
	c := &TTLCache{
		queue:     make(chan command, 32),
		data:      make(map[interface{}]interface{}),
		index:     make(map[interface{}]*list.Element),
		shutdown:  make(chan bool),
		ttl:       list.New(),
		expire:    expire,
		isDestory: false}
	go c.run()
	return c
}

func (c *TTLCache) Destory() {
	c.desLock.Lock()
	if c.isDestory {
		return
	}
	c.isDestory = true
	defer c.desLock.Unlock()
	c.shutdown <- true
	close(c.shutdown)
}

func (c *TTLCache) processCommand(cmd command) {
	now := time.Now()
	switch cmd.action {
	case 0: //mset
		{
			expire := now.Add(c.expire).UnixNano()
			for i, k := range cmd.keys {
				_, ok := c.data[k]
				if ok {
					ele, ele_ok := c.index[k]
					if ele_ok {
						c.ttl.Remove(ele)
						delete(c.index, k)
					}
				}
				c.data[k] = cmd.values[i]
				c.ttl.PushBack(item{key: k, expire: expire})
				c.index[k] = c.ttl.Back()
			}
		}
	case 1: //mget
		{
			result := make([]interface{}, len(cmd.keys))
			for i, k := range cmd.keys {
				v, ok := c.data[k]
				if ok {
					result[i] = v
				} else {
					result[i] = errors.New("Invalid_Key")
				}
			}
			cmd.callback <- result
		}
	case 2: //mdel
		{
			for _, k := range cmd.keys {
				_, ok := c.data[k]
				if ok {
					ele, ele_ok := c.index[k]
					if ele_ok {
						c.ttl.Remove(ele)
						delete(c.index, k)
					}
					delete(c.data, k)
				}
			}
		}
	case 3: //keys
		{
			result := make([]interface{}, len(c.data))
			index := 0
			for k, _ := range c.data {
				result[index] = k
				index++
			}
			cmd.callback <- result
		}
	case 4: //ttl
		{
			for {
				if c.ttl.Len() == 0 {
					break
				}
				ele := c.ttl.Front()
				tn := ele.Value.(item)
				if tn.expire > now.UnixNano() {
					break
				}
				delete(c.data, tn.key)
				delete(c.index, tn.key)
				c.ttl.Remove(ele)

			}
		}
	}
}

func (c *TTLCache) run() {
	timer := time.NewTimer(10 * time.Second)
	for {
		select {
		case <-c.shutdown:
			{
				timer.Stop()
				goto End
			}
		case <-timer.C:
			{
				c.processCommand(command{action: 4})
				timer.Reset(10 * time.Second)
			}
		case cmd := <-c.queue:
			{
				c.processCommand(cmd)
			}
		}
	}
End:
	c.data = nil
	c.ttl = nil
	c.index = nil
	close(c.queue)
}

func (c *TTLCache) Set(key interface{}, value interface{}) {
	c.MSet([]interface{}{key}, []interface{}{value})
}

func (c *TTLCache) MSet(keys []interface{}, values []interface{}) {
	c.desLock.RLock()
	defer c.desLock.RUnlock()
	c.queue <- command{action: 0, keys: keys, values: values}
}

func (c *TTLCache) Get(key interface{}) (interface{}, error) {
	result := c.MGet([]interface{}{key})
	switch result[0].(type) {
	case error:
		{
			return nil, result[0].(error)
		}
	default:
		{
			return result[0], nil
		}
	}
}

func (c *TTLCache) MGet(keys []interface{}) []interface{} {
	callback := make(chan []interface{})
	defer close(callback)
	c.desLock.RLock()
	c.queue <- command{action: 1, keys: keys, callback: callback}
	c.desLock.RUnlock()
	return <-callback
}

func (c *TTLCache) Del(key interface{}) {
	c.MDel([]interface{}{key})
}

func (c *TTLCache) MDel(keys []interface{}) {
	c.desLock.RLock()
	defer c.desLock.RUnlock()
	c.queue <- command{action: 2, keys: keys}
}

func (c *TTLCache) Keys() []interface{} {
	callback := make(chan []interface{})
	defer close(callback)
	c.desLock.RLock()
	c.queue <- command{action: 3, callback: callback}
	c.desLock.RUnlock()
	return <-callback
}
<commit_msg>Delete ttlcache.go<commit_after><|endoftext|>


<commit_before>package reflect2

import (
	"reflect"
	"runtime"
	"strings"
	"sync"
	"unsafe"
)

// typelinks1 for 1.5 ~ 1.6
//go:linkname typelinks1 reflect.typelinks
func typelinks1() [][]unsafe.Pointer

// typelinks2 for 1.7 ~
//go:linkname typelinks2 reflect.typelinks
func typelinks2() (sections []unsafe.Pointer, offset [][]int32)

// initOnce guards initialization of types and packages
var initOnce sync.Once

var types map[string]reflect.Type
var packages map[string]map[string]reflect.Type

// discoverTypes initializes types and packages
func discoverTypes() {
	types = make(map[string]reflect.Type)
	packages = make(map[string]map[string]reflect.Type)

	ver := runtime.Version()
	if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") {
		loadGo15Types()
	} else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") {
		loadGo15Types()
	} else {
		loadGo17Types()
	}
}

func loadGo15Types() {
	var obj interface{} = reflect.TypeOf(0)
	typePtrss := typelinks1()
	for _, typePtrs := range typePtrss {
		for _, typePtr := range typePtrs {
			(*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr
			typ := obj.(reflect.Type)
			if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
				loadedType := typ.Elem()
				pkgTypes := packages[loadedType.PkgPath()]
				if pkgTypes == nil {
					pkgTypes = map[string]reflect.Type{}
					packages[loadedType.PkgPath()] = pkgTypes
				}
				types[loadedType.String()] = loadedType
				pkgTypes[loadedType.Name()] = loadedType
			}
			if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr &&
				typ.Elem().Elem().Kind() == reflect.Struct {
				loadedType := typ.Elem().Elem()
				pkgTypes := packages[loadedType.PkgPath()]
				if pkgTypes == nil {
					pkgTypes = map[string]reflect.Type{}
					packages[loadedType.PkgPath()] = pkgTypes
				}
				types[loadedType.String()] = loadedType
				pkgTypes[loadedType.Name()] = loadedType
			}
		}
	}
}

func loadGo17Types() {
	var obj interface{} = reflect.TypeOf(0)
	sections, offset := typelinks2()
	for i, offs := range offset {
		rodata := sections[i]
		for _, off := range offs {
			(*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off)
			typ := obj.(reflect.Type)
			if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
				loadedType := typ.Elem()
				pkgTypes := packages[loadedType.PkgPath()]
				if pkgTypes == nil {
					pkgTypes = map[string]reflect.Type{}
					packages[loadedType.PkgPath()] = pkgTypes
				}
				types[loadedType.String()] = loadedType
				pkgTypes[loadedType.Name()] = loadedType
			}
		}
	}
}

type emptyInterface struct {
	typ  unsafe.Pointer
	word unsafe.Pointer
}

// TypeByName return the type by its name, just like Class.forName in java
func TypeByName(typeName string) Type {
	initOnce.Do(discoverTypes)
	return Type2(types[typeName])
}

// TypeByPackageName return the type by its package and name
func TypeByPackageName(pkgPath string, name string) Type {
	initOnce.Do(discoverTypes)
	pkgTypes := packages[pkgPath]
	if pkgTypes == nil {
		return nil
	}
	return Type2(pkgTypes[name])
}
<commit_msg>#6, #9: TypeByName/TypeByPackageName use a hack that only works with gcgo and doesn't work with gccgo. Disabling compilation of type_map.go for gccgo.<commit_after>// +build !gccgo

package reflect2

import (
	"reflect"
	"runtime"
	"strings"
	"sync"
	"unsafe"
)

// typelinks1 for 1.5 ~ 1.6
//go:linkname typelinks1 reflect.typelinks
func typelinks1() [][]unsafe.Pointer

// typelinks2 for 1.7 ~
//go:linkname typelinks2 reflect.typelinks
func typelinks2() (sections []unsafe.Pointer, offset [][]int32)

// initOnce guards initialization of types and packages
var initOnce sync.Once

var types map[string]reflect.Type
var packages map[string]map[string]reflect.Type

// discoverTypes initializes types and packages
func discoverTypes() {
	types = make(map[string]reflect.Type)
	packages = make(map[string]map[string]reflect.Type)

	ver := runtime.Version()
	if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") {
		loadGo15Types()
	} else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") {
		loadGo15Types()
	} else {
		loadGo17Types()
	}
}

func loadGo15Types() {
	var obj interface{} = reflect.TypeOf(0)
	typePtrss := typelinks1()
	for _, typePtrs := range typePtrss {
		for _, typePtr := range typePtrs {
			(*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr
			typ := obj.(reflect.Type)
			if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
				loadedType := typ.Elem()
				pkgTypes := packages[loadedType.PkgPath()]
				if pkgTypes == nil {
					pkgTypes = map[string]reflect.Type{}
					packages[loadedType.PkgPath()] = pkgTypes
				}
				types[loadedType.String()] = loadedType
				pkgTypes[loadedType.Name()] = loadedType
			}
			if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr &&
				typ.Elem().Elem().Kind() == reflect.Struct {
				loadedType := typ.Elem().Elem()
				pkgTypes := packages[loadedType.PkgPath()]
				if pkgTypes == nil {
					pkgTypes = map[string]reflect.Type{}
					packages[loadedType.PkgPath()] = pkgTypes
				}
				types[loadedType.String()] = loadedType
				pkgTypes[loadedType.Name()] = loadedType
			}
		}
	}
}

func loadGo17Types() {
	var obj interface{} = reflect.TypeOf(0)
	sections, offset := typelinks2()
	for i, offs := range offset {
		rodata := sections[i]
		for _, off := range offs {
			(*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off)
			typ := obj.(reflect.Type)
			if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
				loadedType := typ.Elem()
				pkgTypes := packages[loadedType.PkgPath()]
				if pkgTypes == nil {
					pkgTypes = map[string]reflect.Type{}
					packages[loadedType.PkgPath()] = pkgTypes
				}
				types[loadedType.String()] = loadedType
				pkgTypes[loadedType.Name()] = loadedType
			}
		}
	}
}

type emptyInterface struct {
	typ  unsafe.Pointer
	word unsafe.Pointer
}

// TypeByName return the type by its name, just like Class.forName in java
func TypeByName(typeName string) Type {
	initOnce.Do(discoverTypes)
	return Type2(types[typeName])
}

// TypeByPackageName return the type by its package and name
func TypeByPackageName(pkgPath string, name string) Type {
	initOnce.Do(discoverTypes)
	pkgTypes := packages[pkgPath]
	if pkgTypes == nil {
		return nil
	}
	return Type2(pkgTypes[name])
}
<|endoftext|>


<commit_before>// +build ignore

package mp

// #include <vlc/vlc.h>
// #include <stdlib.h>
// #cgo LDFLAGS: -lvlc
//
// extern void vlc_callback_helper_go(struct libvlc_event_t *event, void *userdata);
//
// static inline void callback_helper(const struct libvlc_event_t *event, void *userdata) {
//     /* wrap it here to get rid of the 'const' parameter which doesn't exist in Go */
//     vlc_callback_helper_go((struct libvlc_event_t*)event, userdata);
// }
// static inline libvlc_callback_t callback_helper_var() {
//     return callback_helper;
// }
import "C"
import "unsafe"

import (
	"fmt"
	"time"
)

type VLC struct {
	commandChan chan func(*vlcInstance)
}

// this data is separate to ensure it is only used synchronously
type vlcInstance struct {
	instance  *C.libvlc_instance_t
	player    *C.libvlc_media_player_t
	eventChan chan State
	isPlaying bool
}

type vlcEvent struct {
	id        int
	eventType C.libvlc_event_type_t
	callback  func()
}

// store event data here so the garbage collector doesn't trash them
var vlcEvents = make(map[int]*vlcEvent)
var vlcNextEventId int

//export vlc_callback_helper_go
func vlc_callback_helper_go(event *C.struct_libvlc_event_t, userdata unsafe.Pointer) {
	eventData := (*vlcEvent)(userdata)
	if event._type != C.libvlc_MediaPlayerTimeChanged { // suppress this noisy event
		fmt.Println(time.Now().Format("15:04:05.000"), "vlc event:", C.GoString(C.libvlc_event_type_name(C.libvlc_event_type_t(event._type))))
	}
	eventData.callback() // Yeah! We're finally running our callback!
}

func (v *VLC) initialize() chan State {

	i := vlcInstance{}
	i.instance = C.libvlc_new(0, nil)
	if i.instance == nil {
		panic("C.libvlc_new returned NULL")
	}
	i.player = C.libvlc_media_player_new(i.instance)
	if i.player == nil {
		panic("C.libvlc_media_player_new returned NULL")
	}

	v.commandChan = make(chan func(*vlcInstance))
	i.eventChan = make(chan State)

	eventManager := C.libvlc_media_player_event_manager(i.player)
	// all empty event handlers are there just to trigger the log
	v.addEvent(eventManager, C.libvlc_MediaPlayerMediaChanged, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerTimeChanged, func() {
		if !i.isPlaying {
			i.isPlaying = true
			i.eventChan <- STATE_PLAYING
		}
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEncounteredError, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerOpening, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerBuffering, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPlaying, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPaused, func() {
		i.isPlaying = false
		i.eventChan <- STATE_PAUSED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerStopped, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEndReached, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})

	go v.run(&i)

	return i.eventChan
}

func (v *VLC) run(i *vlcInstance) {

	for {
		select {
		case c, ok := <-v.commandChan:
			if !ok {
				C.libvlc_media_player_release(i.player)
				i.player = nil
				C.libvlc_release(i.instance)
				i.instance = nil
				// channel is closed when player must quit

				close(i.eventChan)
				return
			}
			c(i)
		}
	}
}

func (v *VLC) quit() {
	// signal the end of the player
	// Don't allow new commands to be sent
	close(v.commandChan)
}

func (v *VLC) play(stream string, position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		cStream := C.CString(stream)
		defer C.free(unsafe.Pointer(cStream))

		media := C.libvlc_media_new_location(i.instance, cStream)
		defer C.libvlc_media_release(media)

		C.libvlc_media_player_set_media(i.player, media)

		// TODO seek to position if needed

		v.checkError(C.libvlc_media_player_play(i.player))
	}
}

func (v *VLC) pause() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 1)
	}
}

func (v *VLC) resume() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 0)
	}
}

func (v *VLC) getPosition() time.Duration {
	posChan := make(chan time.Duration)
	v.commandChan <- func(i *vlcInstance) {
		position := C.libvlc_media_player_get_time(i.player)
		if position == -1 {
			panic("there is no media while getting position")
		}
		posChan <- time.Duration(position) * time.Millisecond
	}
	return <-posChan
}

func (v *VLC) setPosition(position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
	}
}

func (v *VLC) getVolume() int {
	volumeChan := make(chan int)
	v.commandChan <- func(i *vlcInstance) {
		volume := C.libvlc_audio_get_volume(i.player)
		volumeChan <- int(volume)
	}
	return <-volumeChan
}

func (v *VLC) setVolume(volume int) {
	v.commandChan <- func(i *vlcInstance) {
		v.checkError(C.libvlc_audio_set_volume(i.player, C.int(volume)))
	}
}

func (v *VLC) stop() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_stop(i.player)
	}
}

func (v *VLC) checkError(status C.int) {
	if status < 0 {
		panic(fmt.Sprintf("libvlc error: %s (%d)\n", C.GoString(C.libvlc_errmsg()), int(status)))
	}
}

func (v *VLC) addEvent(manager *C.libvlc_event_manager_t, eventType C.libvlc_event_type_t, callback func()) {
	id := vlcNextEventId
	vlcNextEventId++

	event := &vlcEvent{id, eventType, callback}
	vlcEvents[id] = event

	v.checkError(C.libvlc_event_attach(manager, eventType, C.callback_helper_var(), unsafe.Pointer(event)))
}
<commit_msg>Remove select with only a single case<commit_after>// +build ignore

package mp

// #include <vlc/vlc.h>
// #include <stdlib.h>
// #cgo LDFLAGS: -lvlc
//
// extern void vlc_callback_helper_go(struct libvlc_event_t *event, void *userdata);
//
// static inline void callback_helper(const struct libvlc_event_t *event, void *userdata) {
//     /* wrap it here to get rid of the 'const' parameter which doesn't exist in Go */
//     vlc_callback_helper_go((struct libvlc_event_t*)event, userdata);
// }
// static inline libvlc_callback_t callback_helper_var() {
//     return callback_helper;
// }
import "C"
import "unsafe"

import (
	"fmt"
	"time"
)

type VLC struct {
	commandChan chan func(*vlcInstance)
}

// this data is separate to ensure it is only used synchronously
type vlcInstance struct {
	instance  *C.libvlc_instance_t
	player    *C.libvlc_media_player_t
	eventChan chan State
	isPlaying bool
}

type vlcEvent struct {
	id        int
	eventType C.libvlc_event_type_t
	callback  func()
}

// store event data here so the garbage collector doesn't trash them
var vlcEvents = make(map[int]*vlcEvent)
var vlcNextEventId int

//export vlc_callback_helper_go
func vlc_callback_helper_go(event *C.struct_libvlc_event_t, userdata unsafe.Pointer) {
	eventData := (*vlcEvent)(userdata)
	if event._type != C.libvlc_MediaPlayerTimeChanged { // suppress this noisy event
		fmt.Println(time.Now().Format("15:04:05.000"), "vlc event:", C.GoString(C.libvlc_event_type_name(C.libvlc_event_type_t(event._type))))
	}
	eventData.callback() // Yeah! We're finally running our callback!
}

func (v *VLC) initialize() chan State {

	i := vlcInstance{}
	i.instance = C.libvlc_new(0, nil)
	if i.instance == nil {
		panic("C.libvlc_new returned NULL")
	}
	i.player = C.libvlc_media_player_new(i.instance)
	if i.player == nil {
		panic("C.libvlc_media_player_new returned NULL")
	}

	v.commandChan = make(chan func(*vlcInstance))
	i.eventChan = make(chan State)

	eventManager := C.libvlc_media_player_event_manager(i.player)
	// all empty event handlers are there just to trigger the log
	v.addEvent(eventManager, C.libvlc_MediaPlayerMediaChanged, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerTimeChanged, func() {
		if !i.isPlaying {
			i.isPlaying = true
			i.eventChan <- STATE_PLAYING
		}
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEncounteredError, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerOpening, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerBuffering, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPlaying, func() {})
	v.addEvent(eventManager, C.libvlc_MediaPlayerPaused, func() {
		i.isPlaying = false
		i.eventChan <- STATE_PAUSED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerStopped, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})
	v.addEvent(eventManager, C.libvlc_MediaPlayerEndReached, func() {
		i.isPlaying = false
		i.eventChan <- STATE_STOPPED
	})

	go v.run(&i)

	return i.eventChan
}

func (v *VLC) run(i *vlcInstance) {

	for {
		c, ok := <-v.commandChan;

		if !ok {
			C.libvlc_media_player_release(i.player)
			i.player = nil
			C.libvlc_release(i.instance)
			i.instance = nil
			// channel is closed when player must quit

			close(i.eventChan)
			return
		}

		c(i)
	}
}

func (v *VLC) quit() {
	// signal the end of the player
	// Don't allow new commands to be sent
	close(v.commandChan)
}

func (v *VLC) play(stream string, position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		cStream := C.CString(stream)
		defer C.free(unsafe.Pointer(cStream))

		media := C.libvlc_media_new_location(i.instance, cStream)
		defer C.libvlc_media_release(media)

		C.libvlc_media_player_set_media(i.player, media)

		// TODO seek to position if needed

		v.checkError(C.libvlc_media_player_play(i.player))
	}
}

func (v *VLC) pause() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 1)
	}
}

func (v *VLC) resume() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_pause(i.player, 0)
	}
}

func (v *VLC) getPosition() time.Duration {
	posChan := make(chan time.Duration)
	v.commandChan <- func(i *vlcInstance) {
		position := C.libvlc_media_player_get_time(i.player)
		if position == -1 {
			panic("there is no media while getting position")
		}
		posChan <- time.Duration(position) * time.Millisecond
	}
	return <-posChan
}

func (v *VLC) setPosition(position time.Duration) {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_set_time(i.player, C.libvlc_time_t(position.Seconds()*1000+0.5))
	}
}

func (v *VLC) getVolume() int {
	volumeChan := make(chan int)
	v.commandChan <- func(i *vlcInstance) {
		volume := C.libvlc_audio_get_volume(i.player)
		volumeChan <- int(volume)
	}
	return <-volumeChan
}

func (v *VLC) setVolume(volume int) {
	v.commandChan <- func(i *vlcInstance) {
		v.checkError(C.libvlc_audio_set_volume(i.player, C.int(volume)))
	}
}

func (v *VLC) stop() {
	v.commandChan <- func(i *vlcInstance) {
		C.libvlc_media_player_stop(i.player)
	}
}

func (v *VLC) checkError(status C.int) {
	if status < 0 {
		panic(fmt.Sprintf("libvlc error: %s (%d)\n", C.GoString(C.libvlc_errmsg()), int(status)))
	}
}

func (v *VLC) addEvent(manager *C.libvlc_event_manager_t, eventType C.libvlc_event_type_t, callback func()) {
	id := vlcNextEventId
	vlcNextEventId++

	event := &vlcEvent{id, eventType, callback}
	vlcEvents[id] = event

	v.checkError(C.libvlc_event_attach(manager, eventType, C.callback_helper_var(), unsafe.Pointer(event)))
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 1&1 Internet AG, http://1und1.de . All rights reserved. Licensed under the Apache v2 License.
 */

package oneandone_cloudserver_api

import (
	"github.com/docker/machine/log"
	"net/http"
)

type ServerAppliance struct {
	withId
	withName
	OsImageType        string                   `json:"os_image_type"`
	OsFamily           string                   `json:"os_family"`
	Os                 string                   `json:"os"`
	OsVersion          string                   `json:"os_version"`
	MinHddSize         int                      `json:"min_hdd_size"`
	Architecture       int                      `json:"architecture"`
	Licenses           []ServerApplianceLicence `json:"licenses"`
	IsAutomaticInstall bool                     `json:"automatic_installation"`
	Type               string                   `json:"type"`
	withApi
}

type ServerApplianceLicence struct {
	withName
}

// GET /server_appliances
func (api *API) GetServerAppliances() ([]ServerAppliance, error) {
	log.Debug("requesting information about server appliances")
	res := []ServerAppliance{}
	err := api.Client.Get(createUrl(api, "server_appliances"), &res, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range res {
		res[index].api = api
	}
	return res, nil
}

// GET /server_appliances/{id}
func (api *API) GetServerAppliance(Id string) (*ServerAppliance, error) {
	log.Debug("requesting information about server appliance", Id)
	res := new(ServerAppliance)
	err := api.Client.Get(createUrl(api, "server_appliances", Id), &res, http.StatusOK)
	if err != nil {
		return nil, err
	}
	res.api = api
	return res, nil
}

func (api* API) ServerApplianceListArchitectures(family string, os string, osType string) ([]int, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	architectures := make(map[int]int)
	for index, _ := range apps {
		if apps[index].OsFamily == family && apps[index].Os == os && apps[index].OsImageType == osType {
			log.Debug(apps[index])
			architectures[apps[index].Architecture] = 1
		}
	}
	return GetMapKeysInt(architectures), nil
}

func (api *API) ServerApplianceListTypes(family string, os string) ([]string, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	osTypes := make(map[string]int)
	for index, _ := range apps {
		if apps[index].OsFamily == family && apps[index].Os == os {
			log.Debug(apps[index])
			osTypes[apps[index].OsImageType] = 1
		}
	}
	return GetMapKeysString(osTypes), nil
}

func (api *API) ServerApplianceListOperationSystems(family string) ([]string, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	os := make(map[string]int)
	for index, _ := range apps {
		if apps[index].OsFamily == family {
			log.Debug(apps[index])
			os[apps[index].OsVersion] = 1
		}
	}
	return GetMapKeysString(os), nil
}

func (api *API) ServerApplianceListFamilies() ([]string, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	osFamilies := make(map[string]int)
	for index, _ := range apps {
		log.Debug(apps[index])
		osFamilies[apps[index].OsFamily] = 1
	}
	return GetMapKeysString(osFamilies), nil
}

func (api *API) FindNewest(family string, os string, osType string, architecture int, autoInstall bool) (/*ServerAppliance, error*/) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return //nil, err
	}
	architectures := []ServerAppliance{}
	for index, _ := range apps {
		//log.Debug(apps[index])
		if apps[index].OsFamily == family && apps[index].Os == os && apps[index].OsImageType == osType &&
		apps[index].Architecture == architecture && apps[index].IsAutomaticInstall == autoInstall {
			architectures = append(architectures, apps[index])
		}
	}
	log.Debug(architectures)
}

<commit_msg>Implement error handling and sort features<commit_after>/*
 * Copyright 2015 1&1 Internet AG, http://1und1.de . All rights reserved. Licensed under the Apache v2 License.
 */

package oneandone_cloudserver_api

import (
	"github.com/docker/machine/log"
	"net/http"
	"sort"
	"errors"
)

type ServerAppliance struct {
	withId
	withName
	OsImageType        string                   `json:"os_image_type"`
	OsFamily           string                   `json:"os_family"`
	Os                 string                   `json:"os"`
	OsVersion          string                   `json:"os_version"`
	MinHddSize         int                      `json:"min_hdd_size"`
	Architecture       int                      `json:"architecture"`
	Licenses           []ServerApplianceLicence `json:"licenses"`
	IsAutomaticInstall bool                     `json:"automatic_installation"`
	Type               string                   `json:"type"`
	withApi
}

type ServerApplianceLicence struct {
	withName
}

// GET /server_appliances
func (api *API) GetServerAppliances() ([]ServerAppliance, error) {
	log.Debug("requesting information about server appliances")
	res := []ServerAppliance{}
	err := api.Client.Get(createUrl(api, "server_appliances"), &res, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range res {
		res[index].api = api
	}
	return res, nil
}

// GET /server_appliances/{id}
func (api *API) GetServerAppliance(Id string) (*ServerAppliance, error) {
	log.Debug("requesting information about server appliance", Id)
	res := new(ServerAppliance)
	err := api.Client.Get(createUrl(api, "server_appliances", Id), &res, http.StatusOK)
	if err != nil {
		return nil, err
	}
	res.api = api
	return res, nil
}

//Functions for the sort.Sort interface to sort the serverAppliance struct by OsVersion
type sortServerAppliance []ServerAppliance

func (s sortServerAppliance) Less(i, j int) (bool) {
	return s[i].OsVersion > s [j].OsVersion
}

func (s sortServerAppliance) Swap (i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s sortServerAppliance) Len() (int) {
	return len(s)
}

// Function to get the available architectures for the given operating system
//
// Returns the available architectures. i.E. [32, 64]
func (api* API) ServerApplianceListArchitectures(family string, os string, osType string) ([]int, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	architectures := make(map[int]int)
	for index, _ := range apps {
		if apps[index].OsFamily == family && apps[index].Os == os && apps[index].OsImageType == osType {
			log.Debug(apps[index])
			architectures[apps[index].Architecture] = 1
		}
	}
	if len(architectures) >= 1 {
		return GetMapKeysInt(architectures), nil
	}
	return nil, errors.New("No entries found with given parameters")
}

// Function to get the available operating system type images
//
//Returns the available operating system types. i.E. [Minimal, Standard, ISO_OS]
func (api *API) ServerApplianceListTypes(family string, os string) ([]string, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	osTypes := make(map[string]int)
	for index, _ := range apps {
		if apps[index].OsFamily == family && apps[index].Os == os {
			log.Debug(apps[index])
			osTypes[apps[index].OsImageType] = 1
		}
	}
	if len(osTypes) > 1 {
		return GetMapKeysString(osTypes), nil
	}
	return nil, errors.New("No entries found with given parameters")
}

// Function to get the available operating system by the os family
//
// Returns all operating systems who are in the given family. i.E. Linux: [Ubuntu, Debian] and so on..
func (api *API) ServerApplianceListOperationSystems(family string) ([]string, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	os := make(map[string]int)
	for index, _ := range apps {
		if apps[index].OsFamily == family {
			log.Debug(apps[index])
			os[apps[index].Os] = 1
		}
	}
	if len(os) >= 1 {
		return GetMapKeysString(os), nil
	}
	return nil, errors.New("No entries found with given parameters")
}

// Function to get the available operating system families
//
// Returns the available operating system families. i.E. [Linux, Windows]
func (api *API) ServerApplianceListFamilies() ([]string, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	osFamilies := make(map[string]int)
	for index, _ := range apps {
		log.Debug(apps[index])
		osFamilies[apps[index].OsFamily] = 1
	}
	if len(osFamilies) >= 1 {
		return GetMapKeysString(osFamilies), nil
	}
	return nil, errors.New("No entries found")
}

// Function to get the newest operating system
//
// Returns the newest operating system as ServerAppliance object
func (api *API) ServerApplianceFindNewest(family string, os string, osType string, architecture int, autoInstall bool) (*ServerAppliance, error) {
	apps, err := api.GetServerAppliances()
	if err != nil {
		return nil, err
	}
	filteredApps := sortServerAppliance{}
	for index, _ := range apps {
		if apps[index].OsFamily == family && apps[index].Os == os && apps[index].OsImageType == osType &&
		apps[index].Architecture == architecture && apps[index].IsAutomaticInstall == autoInstall {
			log.Debug(apps[index])
			filteredApps = append(filteredApps, apps[index])
		}
	}
	sort.Sort(filteredApps)
	if len(filteredApps) >= 1 {
		return &filteredApps[0], nil
	}
	return nil, errors.New("No entries found with given parameters")
}

<|endoftext|>


<commit_before>package main

import (
	"github.com/KIT-MAMID/mamid/master"
	"github.com/KIT-MAMID/mamid/master/masterapi"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/KIT-MAMID/mamid/msp"
	"github.com/gorilla/mux"
	"net/http"
)

func main() {

	// Setup controllers

	bus := master.NewBus()
	go bus.Run()

	db, err := model.InitializeInMemoryDB("")
	dieOnError(err)

	clusterAllocator := &master.ClusterAllocator{}

	mainRouter := mux.NewRouter().StrictSlash(true)

	httpStatic := http.FileServer(http.Dir("./gui/"))
	mainRouter.Handle("/", httpStatic)
	mainRouter.PathPrefix("/static/").Handler(httpStatic)
	mainRouter.PathPrefix("/pages/").Handler(httpStatic)

	masterAPI := &masterapi.MasterAPI{
		DB:               db,
		ClusterAllocator: clusterAllocator,
		Router:           mainRouter.PathPrefix("/api/").Subrouter(),
	}
	masterAPI.Setup()

	monitor := master.Monitor{
		DB:              db,
		BusWriteChannel: bus.GetNewWriteChannel(),
		MSPClient:       msp.MSPClientImpl{},
	}
	go monitor.Run()

	problemManager := master.ProblemManager{
		DB:             db,
		BusReadChannel: bus.GetNewReadChannel(),
	}
	go problemManager.Run()

	// Listen

	err = http.ListenAndServe(":8080", mainRouter)
	dieOnError(err)
}

func dieOnError(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>UPD: master: use on disk db<commit_after>package main

import (
	"github.com/KIT-MAMID/mamid/master"
	"github.com/KIT-MAMID/mamid/master/masterapi"
	"github.com/KIT-MAMID/mamid/model"
	"github.com/KIT-MAMID/mamid/msp"
	"github.com/gorilla/mux"
	"net/http"
)

func main() {

	// Setup controllers

	bus := master.NewBus()
	go bus.Run()

	db, err := model.InitializeFileFromFile("mamid.sqlite3")
	dieOnError(err)

	clusterAllocator := &master.ClusterAllocator{}

	mainRouter := mux.NewRouter().StrictSlash(true)

	httpStatic := http.FileServer(http.Dir("./gui/"))
	mainRouter.Handle("/", httpStatic)
	mainRouter.PathPrefix("/static/").Handler(httpStatic)
	mainRouter.PathPrefix("/pages/").Handler(httpStatic)

	masterAPI := &masterapi.MasterAPI{
		DB:               db,
		ClusterAllocator: clusterAllocator,
		Router:           mainRouter.PathPrefix("/api/").Subrouter(),
	}
	masterAPI.Setup()

	monitor := master.Monitor{
		DB:              db,
		BusWriteChannel: bus.GetNewWriteChannel(),
		MSPClient:       msp.MSPClientImpl{},
	}
	go monitor.Run()

	problemManager := master.ProblemManager{
		DB:             db,
		BusReadChannel: bus.GetNewReadChannel(),
	}
	go problemManager.Run()

	// Listen

	err = http.ListenAndServe(":8080", mainRouter)
	dieOnError(err)
}

func dieOnError(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>// Copyright © 2013, Greg Ward. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE.txt file.

// +build python

package plugins

import (
	"errors"
	"fmt"
	"strings"
	"unsafe"

	py "github.com/sbinet/go-python"

	"fubsy/log"
	"fubsy/types"
)

// #include <stdlib.h>
// #include "empython.h"
import "C"

type PythonPlugin struct {
}

func NewPythonPlugin() (MetaPlugin, error) {
	py.Initialize()
	return PythonPlugin{}, nil
}

func (self PythonPlugin) String() string {
	return "PythonPlugin"
}

func (self PythonPlugin) InstallBuiltins(builtins BuiltinList) error {
	fmt.Printf("InstallBuiltins: builtins = %T %v (num = %d)\n",
		builtins, builtins, builtins.NumBuiltins())
	for idx := 0; idx < builtins.NumBuiltins(); idx++ {
		_, code := builtins.Builtin(idx)
		fnptr := *(*unsafe.Pointer)(unsafe.Pointer(&code))
		fmt.Printf("InstallBuiltins(): setting callback %d = %p (from %p)\n",
			idx, fnptr, code)
		C.setCallback(C.int(idx), fnptr)
	}

	if C.installBuiltins() < 0 {
		return errors.New(
			"unknown error setting up Python environment (out of memory?)")
	}
	return nil
}

//export callBuiltin
func callBuiltin(
	pfunc unsafe.Pointer, numargs C.int, cargs unsafe.Pointer) (
	*C.char, *C.char) {

	log.Debug(log.PLUGINS, "callBuiltin: calling Go function at %p", pfunc)
	var fn types.FuCode

	fuargs := make([]types.FuObject, numargs)
	for i := uintptr(0); i < uintptr(numargs); i++ {
		// cargs is really a C char **, i.e. a pointer to an array of
		// char *. argp is a pointer to the i'th member of cargs. This
		// is just C-style array lookup with pointer arithmetic, but
		// in Go syntax.
		argp := unsafe.Pointer(uintptr(cargs) + i*unsafe.Sizeof(cargs))
		arg := C.GoString(*(**C.char)(argp))
		fuargs[i] = types.FuString(arg)
	}
	args := types.MakeBasicArgs(nil, fuargs, nil)

	fn = *(*types.FuCode)(unsafe.Pointer(&pfunc))
	log.Debug(log.PLUGINS, "followed unsafe.Pointer to get %p", fn)
	result, err := fn(args)

	if len(err) > 0 {
		errmsgs := make([]string, len(err))
		for i, err := range err {
			errmsgs[i] = err.Error()
		}
		return nil, C.CString(strings.Join(errmsgs, "\n"))
	}
	var cresult *C.char
	if result != nil {
		cresult = C.CString(result.String())
	}
	return cresult, nil
}

func (self PythonPlugin) Run(content string) (
	types.ValueMap, error) {

	result := py.PyRun_SimpleString(content)
	if result < 0 {
		// there's no way to get the traceback info... but it doesn't
		// really matter, since Python prints the traceback to stderr
		return nil, errors.New("inline Python plugin raised an exception")
	}
	return nil, nil
}

func (self PythonPlugin) Close() {
	// argh, go-python doesn't wrap this
	//py.Py_Finalize()
}
<commit_msg>plugins: remove some debugging prints<commit_after>// Copyright © 2013, Greg Ward. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE.txt file.

// +build python

package plugins

import (
	"errors"
	//"fmt"
	"strings"
	"unsafe"

	py "github.com/sbinet/go-python"

	"fubsy/log"
	"fubsy/types"
)

// #include <stdlib.h>
// #include "empython.h"
import "C"

type PythonPlugin struct {
}

func NewPythonPlugin() (MetaPlugin, error) {
	py.Initialize()
	return PythonPlugin{}, nil
}

func (self PythonPlugin) String() string {
	return "PythonPlugin"
}

func (self PythonPlugin) InstallBuiltins(builtins BuiltinList) error {
	for idx := 0; idx < builtins.NumBuiltins(); idx++ {
		_, code := builtins.Builtin(idx)
		fnptr := *(*unsafe.Pointer)(unsafe.Pointer(&code))
		C.setCallback(C.int(idx), fnptr)
	}

	if C.installBuiltins() < 0 {
		return errors.New(
			"unknown error setting up Python environment (out of memory?)")
	}
	return nil
}

//export callBuiltin
func callBuiltin(
	pfunc unsafe.Pointer, numargs C.int, cargs unsafe.Pointer) (
	*C.char, *C.char) {

	log.Debug(log.PLUGINS, "callBuiltin: calling Go function at %p", pfunc)
	var fn types.FuCode

	fuargs := make([]types.FuObject, numargs)
	for i := uintptr(0); i < uintptr(numargs); i++ {
		// cargs is really a C char **, i.e. a pointer to an array of
		// char *. argp is a pointer to the i'th member of cargs. This
		// is just C-style array lookup with pointer arithmetic, but
		// in Go syntax.
		argp := unsafe.Pointer(uintptr(cargs) + i*unsafe.Sizeof(cargs))
		arg := C.GoString(*(**C.char)(argp))
		fuargs[i] = types.FuString(arg)
	}
	args := types.MakeBasicArgs(nil, fuargs, nil)

	fn = *(*types.FuCode)(unsafe.Pointer(&pfunc))
	log.Debug(log.PLUGINS, "followed unsafe.Pointer to get %p", fn)
	result, err := fn(args)

	if len(err) > 0 {
		errmsgs := make([]string, len(err))
		for i, err := range err {
			errmsgs[i] = err.Error()
		}
		return nil, C.CString(strings.Join(errmsgs, "\n"))
	}
	var cresult *C.char
	if result != nil {
		cresult = C.CString(result.String())
	}
	return cresult, nil
}

func (self PythonPlugin) Run(content string) (
	types.ValueMap, error) {

	result := py.PyRun_SimpleString(content)
	if result < 0 {
		// there's no way to get the traceback info... but it doesn't
		// really matter, since Python prints the traceback to stderr
		return nil, errors.New("inline Python plugin raised an exception")
	}
	return nil, nil
}

func (self PythonPlugin) Close() {
	// argh, go-python doesn't wrap this
	//py.Py_Finalize()
}
<|endoftext|>


<commit_before>package main

import (
  "os"
  "os/exec"
  "log"
  "io"
  "path"
  "errors"
  "strings"
  "bytes"
)

func executablePath() string {
  fullpath, _ := exec.LookPath(os.Args[0])
  return fullpath
}

func copyFile(src, dst string) (err error) {
  in, err := os.Open(src)
  if err != nil {
    log.Printf("Failed to open source: %v", err)
    return
  }

  defer in.Close()

  out, err := os.Create(dst)
  if err != nil {
    log.Printf("Failed to create destination: %v", err)
    return
  }

  defer func() {
    cerr := out.Close()
    if err == nil {
      err = cerr
    }
  }()

  if _, err = io.Copy(out, in); err != nil {
    return
  }

  err = out.Sync()
  return
}

func ensureDirExists(fullpath string) (err error) {
  log.Printf("Ensure directory exists for file %v", fullpath)
  dirpath := path.Dir(fullpath)
  err = os.MkdirAll(dirpath, os.ModePerm)
  if err != nil {
    log.Printf("Failed to create directory %v", dirpath)
  }

  return err
}

func parseLddOutputLine(line string) (string, string, error) {
  if len(line) == 0 { return "", "", errors.New("Empty") }

  var libpath, libname string

  if strings.Contains(line, " => ") {
    parts := strings.Split(line, " => ")

    if len(parts) != 2 {
      return "", "", errors.New("Wrong format")
    }

    libname = strings.TrimSpace(parts[0])

    if parts[1] == "not found" { return parts[0], "", nil }

    lastUseful := strings.LastIndex(parts[1], "(0x")
    if lastUseful != -1 {
      libpath = strings.TrimSpace(parts[1][:lastUseful])
    }
  } else {
    log.Printf("Skipping ldd line: %v", line)
    return "", "", errors.New("Not with =>")
  }

  return libname, libpath, nil
}

func replaceQtPathVariable(buffer []byte, varname []byte, replacement []byte) {
  index := bytes.Index(buffer, varname)
  if index == -1 {
    log.Printf("Not found %v when replacing Qt Path", varname)
    return
  }

  nextIndex := len(varname) + index
  endIndex := bytes.IndexByte(buffer[nextIndex:], byte(0))
  if endIndex == -1 {
    log.Printf("End not found for %v when replacing Qt Path", varname)
    return
  }

  if (endIndex - index) < len(replacement) {
    log.Printf("Cannot exceed length when replacing %v in Qt Path", varname)
    return
  }

  i := index
  j := 0
  replacementSize := len(replacement)

  for (i < endIndex) && (j < replacementSize) {
    buffer[i] = replacement[j]
    j++
    i++
  }

  // pad with zeroes
  for (i < endIndex) {
    buffer[i] = byte(0)
  }

  log.Printf("Replaced %v to %v for Qt Path", varname, replacement)
}
<commit_msg>Update utils.go<commit_after>package main

import (
  "os"
  "os/exec"
  "log"
  "io"
  "path"
  "errors"
  "strings"
  "bytes"
)

func executablePath() string {
  fullpath, _ := exec.LookPath(os.Args[0])
  return fullpath
}

func copyFile(src, dst string) (err error) {
  in, err := os.Open(src)
  if err != nil {
    log.Printf("Failed to open source: %v", err)
    return
  }

  defer in.Close()

  out, err := os.Create(dst)
  if err != nil {
    log.Printf("Failed to create destination: %v", err)
    return
  }

  defer func() {
    cerr := out.Close()
    if err == nil {
      err = cerr
    }
  }()

  if _, err = io.Copy(out, in); err != nil {
    return
  }

  err = out.Sync()
  return
}

func ensureDirExists(fullpath string) (err error) {
  log.Printf("Ensure directory exists for file %v", fullpath)
  dirpath := path.Dir(fullpath)
  err = os.MkdirAll(dirpath, os.ModePerm)
  if err != nil {
    log.Printf("Failed to create directory %v", dirpath)
  }

  return err
}

func parseLddOutputLine(line string) (string, string, error) {
  if len(line) == 0 { return "", "", errors.New("Empty") }

  var libpath, libname string

  if strings.Contains(line, " => ") {
    parts := strings.Split(line, " => ")

    if len(parts) != 2 {
      return "", "", errors.New("Wrong format")
    }

    libname = strings.TrimSpace(parts[0])

    if parts[1] == "not found" { return parts[0], "", nil }

    lastUseful := strings.LastIndex(parts[1], "(0x")
    if lastUseful != -1 {
      libpath = strings.TrimSpace(parts[1][:lastUseful])
    }
  } else {
    log.Printf("Skipping ldd line: %v", line)
    return "", "", errors.New("Not with =>")
  }

  return libname, libpath, nil
}

func replaceQtPathVariable(buffer []byte, varname []byte, replacement []byte) {
  index := bytes.Index(buffer, varname)
  if index == -1 {
    log.Printf("Not found %v when replacing Qt Path", varname)
    return
  }

  nextIndex := len(varname) + index
  endIndex := bytes.IndexByte(buffer[nextIndex:], byte(0))
  if endIndex == -1 {
    log.Printf("End not found for %v when replacing Qt Path", varname)
    return
  }

  if (endIndex - nextIndex) < len(replacement) {
    log.Printf("Cannot exceed length when replacing %v in Qt Path", varname)
    return
  }

  i := nextIndex
  j := 0
  replacementSize := len(replacement)

  for (i < endIndex) && (j < replacementSize) {
    buffer[i] = replacement[j]
    j++
    i++
  }

  // pad with zeroes
  for (i < endIndex) {
    buffer[i] = byte(0)
  }

  log.Printf("Replaced %v to %v for Qt Path", varname, replacement)
}
<|endoftext|>


<commit_before>package gcsproxy

import (
	"fmt"
	"regexp"
	"strconv"
)

type (
	Variable struct {
		data map[string]interface{}
		// quoteString boolean
	}
)

func (v *Variable)expand(str string) (string, error) {
	re0 := regexp.MustCompile(`\%\{\s*([\w.]+)\s*\}`)
	re1 := regexp.MustCompile(`\A\%\{\s*`)
	re2 := regexp.MustCompile(`\s*\}\z`)
	res := re0.ReplaceAllStringFunc("A/%{  foo  }/B/%{bar}/D", func(raw string) string{
		expr := re1.ReplaceAllString(re2.ReplaceAllString(raw, ""), "")
		value, err := dig_variables(expr)
		if err != nil {
			return err
		}
		switch value.(type) {
		case string: return value
		case []interface{}:
			return v.flatten(value)
		case map[string]interface{}:
			return v.flatten(value)
		default:
			return fmt.Sprintf("%v", value)
		}
	})
	return res, nil
}

func (v *Variable)dig_variables(expr string) interface{} {
	var_names := strings.Split(expr, expr_separator)
	return v.inject(var_names, v.data, func(tmp interface{}, name string) interface{}{
		return v.dig_variable(tmp, name, expr)
	})
}

func (v *Variable)dig_variable(tmp interface{}, name, expr string) (interface{}, error) {
	if regexp.MatchString(`\A\d+\z`, name) {
		idx := strconv.Atoi(name)
		switch tmp.(type) {
		case []string:
			return tmp.([]string)[idx]
		case []interface{}:
			return tmp.([]interface{})[idx]
		case map[string]interface{}:
			return tmp.(map[string]interface{})[name]
		}
	} else {
		switch tmp.(type) {
		case map[string]interface{}:
			return tmp.(map[string]interface{})[name]
		}
	}
	retur nil, fmt.Errorf("Invalid Reference")
}

func (v *Variable) inject(var_names []string, tmp interface{}, f func(interface{}, name string) interface{}) interface{} {
	name := var_names[0]
	rest := var_names[1:]
	res := f(tmp, name)
	if len(rest) == 0 {
		return res
	} else {
		return inject(rest, res, f)
	}
}

const (
	expr_separator = "."
	variable_separator = " "
)

func (v *Variable)flatten(obj interface{}) string {
	switch obj.(type) {
	case string:
		return obj.(string)
	case []string:
		return strings.Join(obj.([]string), variable_separator)
	case []interface{}:
		res := []string
		for _, i := range obj.([]interface{}) {
			res = append(res, v.flatten(i))
		}
		return strings.Join(res, variable_separator)
	case map[string]interface{}:
		res := []string
		for _, i := range obj.(map[string]interface{}) {
			res = append(res, v.flatten(i))
		}
		return strings.Join(res, variable_separator)
	default:
		return fmt.Sprintf("%v", obj)
	}
}
<commit_msg>:+1: Fix to pass compiler<commit_after>package gcsproxy

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

type (
	Variable struct {
		data map[string]interface{}
		// quoteString boolean
	}
)

func (v *Variable)expand(str string) (string, error) {
	re0 := regexp.MustCompile(`\%\{\s*([\w.]+)\s*\}`)
	re1 := regexp.MustCompile(`\A\%\{\s*`)
	re2 := regexp.MustCompile(`\s*\}\z`)
	res := re0.ReplaceAllStringFunc("A/%{  foo  }/B/%{bar}/D", func(raw string) string{
		expr := re1.ReplaceAllString(re2.ReplaceAllString(raw, ""), "")
		value, err := v.dig_variables(expr)
		if err != nil {
			// return err
			value = ""
		}
		switch value.(type) {
		case string: return value.(string)
		case []interface{}:
			return v.flatten(value)
		case map[string]interface{}:
			return v.flatten(value)
		default:
			return fmt.Sprintf("%v", value)
		}
	})
	return res, nil
}

func (v *Variable)dig_variables(expr string) (interface{}, error) {
	var_names := strings.Split(expr, expr_separator)
	res, err := v.inject(var_names, v.data, func(tmp interface{}, name string) (interface{}, error) {
		res, err := v.dig_variable(tmp, name, expr)
		if err != nil { return nil, err }
		return res, nil
	})
	if err != nil { return nil, err }
	return res, nil
}

func (v *Variable)dig_variable(tmp interface{}, name, expr string) (interface{}, error) {
	matched, err := regexp.MatchString(`\A\d+\z`, name)
	if err != nil {
		return nil, err
	}
	if matched {
		idx, err := strconv.Atoi(name)
		if err != nil { return nil, err }
		switch tmp.(type) {
		case []string:
			return tmp.([]string)[idx], nil
		case []interface{}:
			return tmp.([]interface{})[idx], nil
		case map[string]interface{}:
			return tmp.(map[string]interface{})[name], nil
		}
	} else {
		switch tmp.(type) {
		case map[string]interface{}:
			return tmp.(map[string]interface{})[name], nil
		}
	}
	return nil, fmt.Errorf("Invalid Reference")
}

func (v *Variable) inject(var_names []string, tmp interface{}, f func(interface{}, string) (interface{}, error)) (interface{}, error) {
	name := var_names[0]
	rest := var_names[1:]
	res, err := f(tmp, name)
	if err != nil {
		return nil, err
	}
	if len(rest) == 0 {
		return res, nil
	} else {
		return v.inject(rest, res, f)
	}
}

const (
	expr_separator = "."
	variable_separator = " "
)

func (v *Variable)flatten(obj interface{}) string {
	switch obj.(type) {
	case string:
		return obj.(string)
	case []string:
		return strings.Join(obj.([]string), variable_separator)
	case []interface{}:
		res := []string{}
		for _, i := range obj.([]interface{}) {
			res = append(res, v.flatten(i))
		}
		return strings.Join(res, variable_separator)
	case map[string]interface{}:
		res := []string{}
		for _, i := range obj.(map[string]interface{}) {
			res = append(res, v.flatten(i))
		}
		return strings.Join(res, variable_separator)
	default:
		return fmt.Sprintf("%v", obj)
	}
}
<|endoftext|>


<commit_before>//
// util.go
//

package main

import (
  "log"
  "os"
  "strings"
)

func CheckFile(fname string) bool {
  if _, err := os.Stat(fname) ; os.IsNotExist(err) {
    return false
  }
  return true
}

// ensure a directory exists
func EnsureDir(dirname string) {
  stat, err := os.Stat(dirname)
  if os.IsNotExist(err) {
    os.Mkdir(dirname, 0755)
  } else if ! stat.IsDir() {
    os.Remove(dirname)
    os.Mkdir(dirname, 0755)
  }
}

// TODO make this work better
func ValidMessageID(id string) bool {

  if id[0] != '<' || id[len(id)-1] != '>' {
    log.Println(id[0], id[len(id)-1])
    return false
  }
  if strings.Count(id, "@") != 1 {
    return false
  }
  if strings.Count(id, "/") > 0 {
    return false
  }
  return true
}
<commit_msg>check for zero length string<commit_after>//
// util.go
//

package main

import (
  "log"
  "os"
  "strings"
)

func CheckFile(fname string) bool {
  if _, err := os.Stat(fname) ; os.IsNotExist(err) {
    return false
  }
  return true
}

// ensure a directory exists
func EnsureDir(dirname string) {
  stat, err := os.Stat(dirname)
  if os.IsNotExist(err) {
    os.Mkdir(dirname, 0755)
  } else if ! stat.IsDir() {
    os.Remove(dirname)
    os.Mkdir(dirname, 0755)
  }
}

// TODO make this work better
func ValidMessageID(id string) bool {
  if len(id) == 0 {
    return false
  }
  if id[0] != '<' || id[len(id)-1] != '>' {
    log.Println(id[0], id[len(id)-1])
    return false
  }
  if strings.Count(id, "@") != 1 {
    return false
  }
  if strings.Count(id, "/") > 0 {
    return false
  }
  return true
}
<|endoftext|>


<commit_before>package ginDoi

import (
	"encoding/json"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"html/template"
	"io/ioutil"
	"net/http"
	"path/filepath"
)

var (
	MS_NODOIFILE      = "Could not locate a cloudberry file. Please visit https://web.gin.g-node.org/info/doi for a guide"
	MS_INVALIDDOIFILE = "The doi File was not Valid. Please visit https://web.gin.g-node.org/info/doi for a guide"
	MS_URIINVALID     = "Please provide a valid repository URI"
	MS_SERVERWORKS    = "The Doi Server has started doifying you repository. " +
		"Once finnished it will be availible here. Please return to that location to check for " +
		"availibility

" +
		"We will try to resgister the follwoing doi:
%s
 " +
		"for your dataset. Please note, however, that in rare cases the final doi might be different."
	MS_NOLOGIN = "You are not logged in with the gin service. Login at http://gin.g-node.org/"
	MS_NOTOKEN = "No authentication token provided"
	MS_NOUSER  = "No username provided"
)

// Job holds the attributes needed to perform unit of work.
type Job struct {
	Name    string
	Source  string
	Storage LocalStorage
	User    OauthIdentity
	DoiReq  DoiReq
}

// Responsible for storing smth defined by source to a kind of Storage
// defined by target
type StorageElement interface {
	// Should return true if the target location is alredy there
	Exists(target string) (bool, error)
	// Store the things specifies by source in target
	Put(source string, target string) (bool, error)
	GetDataSource() (*GinDataSource, error)
}

type OauthIdentity struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Token     string
	EmailRaw  json.RawMessage `json:"email"`
}

type OauthProvider struct {
	Name   string
	Uri    string
	ApiKey string
}

type DoiUser struct {
	Name       string
	Identities []OauthIdentity
	MainOId    OauthIdentity
}

type DoiReq struct {
	URI          string
	User         DoiUser
	GinAuthUname string
	Token        string
	Mess         string
	DoiInfo      CBerry
}

// Check the current user. Return a user if logged in
func loggedInUser(r *http.Request, pr *OauthProvider) (*DoiUser, error) {
	return &DoiUser{}, nil
}

func readBody(r *http.Request) (*string, error) {
	body, err := ioutil.ReadAll(r.Body)
	x := string(body)
	return &x, err
}

func DoDoiJob(w http.ResponseWriter, r *http.Request, jobQueue chan Job, storage LocalStorage, op *OauthProvider) {
	// Make sure we can only be called with an HTTP POST request.
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	dReq := DoiReq{}
	//ToDo Error checking
	body, _ := ioutil.ReadAll(r.Body)
	json.Unmarshal(body, &dReq)
	log.WithFields(log.Fields{
		"request": fmt.Sprintf("%+v", dReq),
		"source":  "DoDoiJob",
	}).Debug("Unmarshaled a doi request")

	user, err := op.getUser(dReq.GinAuthUname, dReq.Token)
	if err != nil {
		log.WithFields(log.Fields{
			"request": fmt.Sprintf("%+v", dReq),
			"source":  "DoDoiJob",
			"error":   err,
		}).Debug("Could not authenticate user")
		dReq.Mess = MS_NOLOGIN
		w.WriteHeader(http.StatusUnauthorized)
		return
	}
	dReq.User = DoiUser{MainOId: user}
	//ToDo Error checking
	ds, _ := storage.GetDataSource()
	df, _ := ds.GetDoiFile(dReq.URI)
	uuid, _ := ds.MakeUUID(dReq.URI)

	if ok, doiInfo := validDoiFile(df); !ok {
		w.WriteHeader(http.StatusBadRequest)
		return
	} else {
		doiInfo.UUID = uuid
		doi := storage.DProvider.MakeDoi(doiInfo)
		dReq.DoiInfo = *doiInfo
		job := Job{Source: dReq.URI, Storage: storage, User: user, DoiReq: dReq, Name: doiInfo.UUID}
		jobQueue <- job
		// Render success.
		w.WriteHeader(http.StatusCreated)
		w.Write([]byte(fmt.Sprintf(MS_SERVERWORKS, storage.HttpBase+uuid, doi)))
	}
}

func InitDoiJob(w http.ResponseWriter, r *http.Request, ds *GinDataSource, op *OauthProvider) {
	log.Infof("Got a new DOI request")
	if err := r.ParseForm(); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	URI := r.Form.Get("repo")
	token := r.Form.Get("token")
	username := r.Form.Get("user")
	dReq := DoiReq{URI: URI, GinAuthUname: username, Token: token}
	log.WithFields(log.Fields{
		"request": fmt.Sprintf("%+v", dReq),
		"source":  "Init",
	}).Debug("Got DOI Request")
	log.Infof("Will Doify %s", dReq.URI)

	t, err := template.ParseFiles(filepath.Join("tmpl", "initjob.html")) // Parse template file.
	if err != nil {
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "DoDoiJob",
			"error":   err,
		}).Debug("Could not parse init template")
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// Test whether URi was provided
	if !(len(URI) > 0) {
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "Init",
			"error":   err,
		}).Debug("No Repo URI provided")
		dReq.Mess = MS_URIINVALID
		err := t.Execute(w, dReq)
		if err != nil {
			log.WithFields(log.Fields{
				"request": dReq,
				"source":  "Init",
				"error":   err,
			}).Debug("Template not parsed")
			return
		}
		return
	}

	// Test whether token was provided
	if !(len(token) > 0) {
		dReq.Mess = MS_NOTOKEN
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "Init",
			"error":   err,
		}).Debug("No Token provided")
		err := t.Execute(w, dReq)
		if err != nil {
			log.Print(err)
			return
		}
		return
	}

	// Test whether username was provided
	if !(len(username) > 0) {
		dReq.Mess = MS_NOUSER
		err := t.Execute(w, dReq)
		if err != nil {
			log.Print(err)
			return
		}
		return
	}

	// test user login
	_, err = op.getUser(username, token)
	if err != nil {
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "Init",
			"error":   err,
		}).Debug("Could not authenticate user")
		dReq.Mess = MS_NOLOGIN
		t.Execute(w, dReq)
		return
	}

	doiI, err := ds.GetDoiFile(URI)
	if err != nil {
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "Init",
			"error":   err,
		}).Debug("Could not get Cloudberry File")
		dReq.Mess = MS_NODOIFILE
		t.Execute(w, dReq)
		return
	}

	if ok, doiInfo := validDoiFile(doiI); ok {
		log.WithFields(log.Fields{
			"doiInfo": doiInfo,
			"source":  "Init",
		}).Debug("Received Doi information")
		dReq.DoiInfo = *doiInfo
		err := t.Execute(w, dReq)
		if err != nil {
			log.WithFields(log.Fields{
				"request": dReq,
				"source":  "Init",
				"error":   err,
			}).Error("Could not parse template")
			return
		}
	} else {
		log.WithFields(log.Fields{
			"doiInfo": doiInfo,
			"source":  "Init",
			"error":   err,
		}).Debug("Cloudberry File invalid")
		dReq.Mess = MS_INVALIDDOIFILE + " Issue: " + doiInfo.Missing[0]
		t.Execute(w, dReq)
		if err != nil {
			log.WithFields(log.Fields{
				"request": dReq,
				"source":  "Init",
				"error":   err,
			}).Error("Could not parse template")
			return
		}
		return
	}
}
<commit_msg>Fix spelling at doifying info page<commit_after>package ginDoi

import (
	"encoding/json"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"html/template"
	"io/ioutil"
	"net/http"
	"path/filepath"
)

var (
	MS_NODOIFILE      = "Could not locate a cloudberry file. Please visit https://web.gin.g-node.org/info/doi for a guide"
	MS_INVALIDDOIFILE = "The doi File was not Valid. Please visit https://web.gin.g-node.org/info/doi for a guide"
	MS_URIINVALID     = "Please provide a valid repository URI"
	MS_SERVERWORKS    = "The doi server has started doifying you repository. " +
		"Once finnished it will be availible here. Please return to that location to check for " +
		"availibility

" +
		"We will try to resgister the following doi:
%s
 " +
		"for your dataset. Please note, however, that in rare cases the final doi might be different."
	MS_NOLOGIN = "You are not logged in with the gin service. Login at http://gin.g-node.org/"
	MS_NOTOKEN = "No authentication token provided"
	MS_NOUSER  = "No username provided"
)

// Job holds the attributes needed to perform unit of work.
type Job struct {
	Name    string
	Source  string
	Storage LocalStorage
	User    OauthIdentity
	DoiReq  DoiReq
}

// Responsible for storing smth defined by source to a kind of Storage
// defined by target
type StorageElement interface {
	// Should return true if the target location is alredy there
	Exists(target string) (bool, error)
	// Store the things specifies by source in target
	Put(source string, target string) (bool, error)
	GetDataSource() (*GinDataSource, error)
}

type OauthIdentity struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Token     string
	EmailRaw  json.RawMessage `json:"email"`
}

type OauthProvider struct {
	Name   string
	Uri    string
	ApiKey string
}

type DoiUser struct {
	Name       string
	Identities []OauthIdentity
	MainOId    OauthIdentity
}

type DoiReq struct {
	URI          string
	User         DoiUser
	GinAuthUname string
	Token        string
	Mess         string
	DoiInfo      CBerry
}

// Check the current user. Return a user if logged in
func loggedInUser(r *http.Request, pr *OauthProvider) (*DoiUser, error) {
	return &DoiUser{}, nil
}

func readBody(r *http.Request) (*string, error) {
	body, err := ioutil.ReadAll(r.Body)
	x := string(body)
	return &x, err
}

func DoDoiJob(w http.ResponseWriter, r *http.Request, jobQueue chan Job, storage LocalStorage, op *OauthProvider) {
	// Make sure we can only be called with an HTTP POST request.
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}

	dReq := DoiReq{}
	//ToDo Error checking
	body, _ := ioutil.ReadAll(r.Body)
	json.Unmarshal(body, &dReq)
	log.WithFields(log.Fields{
		"request": fmt.Sprintf("%+v", dReq),
		"source":  "DoDoiJob",
	}).Debug("Unmarshaled a doi request")

	user, err := op.getUser(dReq.GinAuthUname, dReq.Token)
	if err != nil {
		log.WithFields(log.Fields{
			"request": fmt.Sprintf("%+v", dReq),
			"source":  "DoDoiJob",
			"error":   err,
		}).Debug("Could not authenticate user")
		dReq.Mess = MS_NOLOGIN
		w.WriteHeader(http.StatusUnauthorized)
		return
	}
	dReq.User = DoiUser{MainOId: user}
	//ToDo Error checking
	ds, _ := storage.GetDataSource()
	df, _ := ds.GetDoiFile(dReq.URI)
	uuid, _ := ds.MakeUUID(dReq.URI)

	if ok, doiInfo := validDoiFile(df); !ok {
		w.WriteHeader(http.StatusBadRequest)
		return
	} else {
		doiInfo.UUID = uuid
		doi := storage.DProvider.MakeDoi(doiInfo)
		dReq.DoiInfo = *doiInfo
		job := Job{Source: dReq.URI, Storage: storage, User: user, DoiReq: dReq, Name: doiInfo.UUID}
		jobQueue <- job
		// Render success.
		w.WriteHeader(http.StatusCreated)
		w.Write([]byte(fmt.Sprintf(MS_SERVERWORKS, storage.HttpBase+uuid, doi)))
	}
}

func InitDoiJob(w http.ResponseWriter, r *http.Request, ds *GinDataSource, op *OauthProvider) {
	log.Infof("Got a new DOI request")
	if err := r.ParseForm(); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	URI := r.Form.Get("repo")
	token := r.Form.Get("token")
	username := r.Form.Get("user")
	dReq := DoiReq{URI: URI, GinAuthUname: username, Token: token}
	log.WithFields(log.Fields{
		"request": fmt.Sprintf("%+v", dReq),
		"source":  "Init",
	}).Debug("Got DOI Request")
	log.Infof("Will Doify %s", dReq.URI)

	t, err := template.ParseFiles(filepath.Join("tmpl", "initjob.html")) // Parse template file.
	if err != nil {
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "DoDoiJob",
			"error":   err,
		}).Debug("Could not parse init template")
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// Test whether URi was provided
	if !(len(URI) > 0) {
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "Init",
			"error":   err,
		}).Debug("No Repo URI provided")
		dReq.Mess = MS_URIINVALID
		err := t.Execute(w, dReq)
		if err != nil {
			log.WithFields(log.Fields{
				"request": dReq,
				"source":  "Init",
				"error":   err,
			}).Debug("Template not parsed")
			return
		}
		return
	}

	// Test whether token was provided
	if !(len(token) > 0) {
		dReq.Mess = MS_NOTOKEN
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "Init",
			"error":   err,
		}).Debug("No Token provided")
		err := t.Execute(w, dReq)
		if err != nil {
			log.Print(err)
			return
		}
		return
	}

	// Test whether username was provided
	if !(len(username) > 0) {
		dReq.Mess = MS_NOUSER
		err := t.Execute(w, dReq)
		if err != nil {
			log.Print(err)
			return
		}
		return
	}

	// test user login
	_, err = op.getUser(username, token)
	if err != nil {
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "Init",
			"error":   err,
		}).Debug("Could not authenticate user")
		dReq.Mess = MS_NOLOGIN
		t.Execute(w, dReq)
		return
	}

	doiI, err := ds.GetDoiFile(URI)
	if err != nil {
		log.WithFields(log.Fields{
			"request": dReq,
			"source":  "Init",
			"error":   err,
		}).Debug("Could not get Cloudberry File")
		dReq.Mess = MS_NODOIFILE
		t.Execute(w, dReq)
		return
	}

	if ok, doiInfo := validDoiFile(doiI); ok {
		log.WithFields(log.Fields{
			"doiInfo": doiInfo,
			"source":  "Init",
		}).Debug("Received Doi information")
		dReq.DoiInfo = *doiInfo
		err := t.Execute(w, dReq)
		if err != nil {
			log.WithFields(log.Fields{
				"request": dReq,
				"source":  "Init",
				"error":   err,
			}).Error("Could not parse template")
			return
		}
	} else {
		log.WithFields(log.Fields{
			"doiInfo": doiInfo,
			"source":  "Init",
			"error":   err,
		}).Debug("Cloudberry File invalid")
		dReq.Mess = MS_INVALIDDOIFILE + " Issue: " + doiInfo.Missing[0]
		t.Execute(w, dReq)
		if err != nil {
			log.WithFields(log.Fields{
				"request": dReq,
				"source":  "Init",
				"error":   err,
			}).Error("Could not parse template")
			return
		}
		return
	}
}
<|endoftext|>


<commit_before>/*
Package config provides types and a function for getting grush configuration.

Configuration is read the file grush.ini. An possible content of such file could be
	[default]
	port=8080
	queueSize=100000
	consumers=1000
	storeType=redis

The storeType chooses an store and implies that there is a section in the configuration
file for the type chosen
*/
package config

import (
	"gopkg.in/yaml.v1"
	"io/ioutil"
	"os"
)

//General configuration data
type Config struct {
	//Port to listen to
	Port string
	//Maximun number of request enqueued, waiting for being processed
	QueueSize int
	//Maximun number of concurrent requests being processed
	Consumers int
	//MongoDB host
	Mongo string
	//Database
	Database string
	//Petitions collection
	PetitionsColl string
	//Responses collection
	ResponsesColl string
	//Errors collection
	ErrorsColl string
	//Instance ID for isolating recoverers
	Instance string
}

//ReadConfig reads configuration from file with name filename.
func ReadConfig(filename string) (*Config, error) {

	cfg := Config{}
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	data, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal(data, &cfg)
	if err != nil {
		return nil, err
	}
	//TODO: Check values!!
	return &cfg, nil
}
<commit_msg>better order of imports<commit_after>/*
Package config provides types and a function for getting grush configuration.

Configuration is read the file grush.ini. An possible content of such file could be
	[default]
	port=8080
	queueSize=100000
	consumers=1000
	storeType=redis

The storeType chooses an store and implies that there is a section in the configuration
file for the type chosen
*/
package config

import (
	"io/ioutil"
	"os"

	"gopkg.in/yaml.v1"
)

//General configuration data
type Config struct {
	//Port to listen to
	Port string
	//Maximun number of request enqueued, waiting for being processed
	QueueSize int
	//Maximun number of concurrent requests being processed
	Consumers int
	//MongoDB host
	Mongo string
	//Database
	Database string
	//Petitions collection
	PetitionsColl string
	//Responses collection
	ResponsesColl string
	//Errors collection
	ErrorsColl string
	//Instance ID for isolating recoverers
	Instance string
}

//ReadConfig reads configuration from file with name filename.
func ReadConfig(filename string) (*Config, error) {

	cfg := Config{}
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	data, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal(data, &cfg)
	if err != nil {
		return nil, err
	}
	//TODO: Check values!!
	return &cfg, nil
}
<|endoftext|>


<commit_before>// Package old implements a plugin to remember URLs and announce duplicates.
package old

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"github.com/StalkR/goircbot/bot"
	"github.com/StalkR/goircbot/lib/duration"
	"github.com/StalkR/goircbot/lib/nohl"
	"github.com/fluffle/goirc/client"
)

var (
	linkRE    = regexp.MustCompile(`(?:^|\s)(https?://[^\s]+)`)
	backlogRE = regexp.MustCompile("<[+%@&~]?[a-zA-Z0-9_`^\\[\\]-]+>")
)

func readURLs(b *bot.Bot, line *client.Line, o *Old, ignore map[string]bool) {
	target := line.Args[0]
	if !strings.HasPrefix(target, "#") {
		return
	}
	if _, ignore := ignore[line.Nick]; ignore {
		return
	}
	text := line.Args[1]
	if backlogRE.MatchString(text) {
		return
	}

	matches := linkRE.FindAllStringSubmatch(text, -1)
	if matches == nil {
		return
	}
	for _, submatches := range matches {
		url := submatches[1]
		i, err := o.Old(url)
		if err != nil {
			if err = o.Add(url, target, line.Nick); err != nil {
				log.Print(err)
			}
			return
		}
		ago := duration.Format(time.Since(i.Time))
		nick := nohl.Nick(b, target, i.Nick)
		b.Conn.Privmsg(target, fmt.Sprintf("old! first shared by %v %v ago", nick, ago))
	}
}

// Register registers the plugin with a bot.
func Register(b *bot.Bot, oldfile string, ignore []string) {
	ignoremap := make(map[string]bool)
	for _, nick := range ignore {
		ignoremap[nick] = true
	}

	o := load(oldfile)

	b.Conn.HandleFunc("privmsg",
		func(conn *client.Conn, line *client.Line) { readURLs(b, line, o, ignoremap) })

	if len(oldfile) > 0 {
		b.AddCron("old-save", bot.Cron{
			Handler:  func(b *bot.Bot) { save(oldfile, o) },
			Duration: time.Minute})
	}

	// Every day, clean URLs older than a year so it does not grow infinitely.
	b.AddCron("old-clean", bot.Cron{
		Handler:  func(b *bot.Bot) { o.Clean(time.Hour * 24 * 365) },
		Duration: time.Hour * 24})
}
<commit_msg>plugins/old: remove AddCron<commit_after>// Package old implements a plugin to remember URLs and announce duplicates.
package old

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"github.com/StalkR/goircbot/bot"
	"github.com/StalkR/goircbot/lib/duration"
	"github.com/StalkR/goircbot/lib/nohl"
	"github.com/fluffle/goirc/client"
)

var (
	linkRE    = regexp.MustCompile(`(?:^|\s)(https?://[^\s]+)`)
	backlogRE = regexp.MustCompile("<[+%@&~]?[a-zA-Z0-9_`^\\[\\]-]+>")
)

func readURLs(b *bot.Bot, line *client.Line, o *Old, ignore map[string]bool) {
	target := line.Args[0]
	if !strings.HasPrefix(target, "#") {
		return
	}
	if _, ignore := ignore[line.Nick]; ignore {
		return
	}
	text := line.Args[1]
	if backlogRE.MatchString(text) {
		return
	}

	matches := linkRE.FindAllStringSubmatch(text, -1)
	if matches == nil {
		return
	}
	for _, submatches := range matches {
		url := submatches[1]
		i, err := o.Old(url)
		if err != nil {
			if err = o.Add(url, target, line.Nick); err != nil {
				log.Print(err)
			}
			return
		}
		ago := duration.Format(time.Since(i.Time))
		nick := nohl.Nick(b, target, i.Nick)
		b.Conn.Privmsg(target, fmt.Sprintf("old! first shared by %v %v ago", nick, ago))
	}
}

// Register registers the plugin with a bot.
func Register(b *bot.Bot, oldfile string, ignore []string) {
	ignoremap := make(map[string]bool)
	for _, nick := range ignore {
		ignoremap[nick] = true
	}

	o := load(oldfile)

	b.Conn.HandleFunc("privmsg",
		func(conn *client.Conn, line *client.Line) { readURLs(b, line, o, ignoremap) })

	// Every minute, save to file.
	if len(oldfile) > 0 {
		go func() {
			for _ = range time.Tick(time.Minute) {
				save(oldfile, o)
			}
		}()
	}

	// Every day, clean URLs older than a year so it does not grow infinitely.
	go func() {
		for _ = range time.Tick(time.Hour * 24) {
			o.Clean(time.Hour * 24 * 365)
		}
	}()
}
<|endoftext|>


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

package main

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime/pprof"

	"github.com/DevMine/srcanlzr/anlzr"
	"github.com/DevMine/srcanlzr/src"
)

const (
	version = "0.0.0"
)

func formatOutput(r *anlzr.Result) ([]byte, error) {
	var bs []byte
	var err error

	switch *format {
	case "JSON":
		bs, err = json.Marshal(r)
	case "XML":
		bs, err = xml.Marshal(r)
	case "protobuf":
		err = errors.New("protobuf is not yet implemented")
	default:
		err = errors.New("unsupported output format")
	}

	return bs, err
}

func fatal(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

// program flags
var (
	format         = flag.String("f", "JSON", "Output format. Possible values are: JSON, XML, protobuf")
	outputFileName = flag.String("o", "", "Output file name. By default, the output is set to stdout")
	cpuprofile     = flag.String("cpuprofile", "", "write cpu profile to file")
	memprofile     = flag.String("memprofile", "", "write memory profile to this file")
	vflag          = flag.Bool("v", false, "Print version.")
)

func main() {
	flag.Usage = func() {
		fmt.Printf("usage: %s [PROJECT PATH]\n\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}
	flag.Parse()

	if *vflag {
		fmt.Printf("%s - v%s\n", filepath.Base(os.Args[0]), version)
		return
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}

	var reader io.Reader

	if l := len(flag.Args()); l > 1 {
		// more that one file are passed as arguments
		fmt.Fprint(os.Stderr, "too many arguments\n\n")
		flag.Usage()
	} else if l == 0 {
		// no argument, we read from stdin
		reader = os.Stdin
	} else {
		f, err := os.Open(flag.Arg(0))
		if err != nil {
			fatal(err)
		}
		defer f.Close()
		reader = f
	}

	out := os.Stdout
	if len(*outputFileName) > 0 {
		var err error
		out, err = os.Open(*outputFileName)
		if err != nil {
			fatal(err)
		}
		defer out.Close()
	}

	p, err := src.Decode(reader)
	if err != nil {
		fatal(err)
	}

	res, err := anlzr.RunAnalyzers(p, anlzr.LoC{}, anlzr.Complexity{}, anlzr.LocPerLang{}, anlzr.CommentRatios{})
	if err != nil {
		fatal(err)
	}

	bs, err := formatOutput(res)
	if err != nil {
		fatal(err)
	}

	fmt.Fprintln(out, string(bs))
}
<commit_msg>srcanlzr: fix print help<commit_after>// Copyright 2014-2015 The DevMine Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"runtime/pprof"

	"github.com/DevMine/srcanlzr/anlzr"
	"github.com/DevMine/srcanlzr/src"
)

const (
	version = "0.0.0"
)

func formatOutput(r *anlzr.Result) ([]byte, error) {
	var bs []byte
	var err error

	switch *format {
	case "JSON":
		bs, err = json.Marshal(r)
	case "XML":
		bs, err = xml.Marshal(r)
	case "protobuf":
		err = errors.New("protobuf is not yet implemented")
	default:
		err = errors.New("unsupported output format")
	}

	return bs, err
}

func fatal(err error) {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

// program flags
var (
	format         = flag.String("f", "JSON", "Output format. Possible values are: JSON, XML, protobuf")
	outputFileName = flag.String("o", "", "Output file name. By default, the output is set to stdout")
	cpuprofile     = flag.String("cpuprofile", "", "write cpu profile to file")
	memprofile     = flag.String("memprofile", "", "write memory profile to this file")
	vflag          = flag.Bool("v", false, "Print version.")
)

func main() {
	flag.Usage = func() {
		fmt.Printf("usage: %s [JSON PATH]\n\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}
	flag.Parse()

	if *vflag {
		fmt.Printf("%s - v%s\n", filepath.Base(os.Args[0]), version)
		return
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
		return
	}

	var reader io.Reader

	if l := len(flag.Args()); l > 1 {
		// more that one file are passed as arguments
		fmt.Fprint(os.Stderr, "too many arguments\n\n")
		flag.Usage()
	} else if l == 0 {
		// no argument, we read from stdin
		reader = os.Stdin
	} else {
		f, err := os.Open(flag.Arg(0))
		if err != nil {
			fatal(err)
		}
		defer f.Close()
		reader = f
	}

	out := os.Stdout
	if len(*outputFileName) > 0 {
		var err error
		out, err = os.Open(*outputFileName)
		if err != nil {
			fatal(err)
		}
		defer out.Close()
	}

	p, err := src.Decode(reader)
	if err != nil {
		fatal(err)
	}

	res, err := anlzr.RunAnalyzers(p, anlzr.LoC{}, anlzr.Complexity{}, anlzr.LocPerLang{}, anlzr.CommentRatios{})
	if err != nil {
		fatal(err)
	}

	bs, err := formatOutput(res)
	if err != nil {
		fatal(err)
	}

	fmt.Fprintln(out, string(bs))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/atotto/clipboard"
	"github.com/zyedidia/tcell"
	"strconv"
)

// The View struct stores information about a view into a buffer.
// It has a value for the cursor, and the window that the user sees
// the buffer from.
type View struct {
	cursor        Cursor
	topline       int
	height        int
	width         int
	lineNumOffset int

	eh *EventHandler

	buf *Buffer
	sl  Statusline

	mouseReleased bool

	// Syntax highlighting matches
	matches map[int]tcell.Style

	s tcell.Screen
}

// NewView returns a new view with fullscreen width and height
func NewView(buf *Buffer, s tcell.Screen) *View {
	w, h := s.Size()
	return NewViewWidthHeight(buf, s, w, h-1)
}

// NewViewWidthHeight returns a new view with the specified width and height
func NewViewWidthHeight(buf *Buffer, s tcell.Screen, w, h int) *View {
	v := new(View)

	v.buf = buf
	v.s = s

	v.topline = 0
	v.height = h - 1
	v.width = w
	v.cursor = Cursor{
		x:   0,
		y:   0,
		loc: 0,
		v:   v,
	}

	v.eh = NewEventHandler(v)

	v.sl = Statusline{
		v: v,
	}

	return v
}

// ScrollUp scrolls the view up n lines (if possible)
func (v *View) ScrollUp(n int) {
	// Try to scroll by n but if it would overflow, scroll by 1
	if v.topline-n >= 0 {
		v.topline -= n
	} else if v.topline > 0 {
		v.topline--
	}
}

// ScrollDown scrolls the view down n lines (if possible)
func (v *View) ScrollDown(n int) {
	// Try to scroll by n but if it would overflow, scroll by 1
	if v.topline+n <= len(v.buf.lines)-v.height {
		v.topline += n
	} else if v.topline < len(v.buf.lines)-v.height {
		v.topline++
	}
}

// PageUp scrolls the view up a page
func (v *View) PageUp() {
	if v.topline > v.height {
		v.ScrollUp(v.height)
	} else {
		v.topline = 0
	}
}

// PageDown scrolls the view down a page
func (v *View) PageDown() {
	if len(v.buf.lines)-(v.topline+v.height) > v.height {
		v.ScrollDown(v.height)
	} else {
		v.topline = len(v.buf.lines) - v.height
	}
}

// HalfPageUp scrolls the view up half a page
func (v *View) HalfPageUp() {
	if v.topline > v.height/2 {
		v.ScrollUp(v.height / 2)
	} else {
		v.topline = 0
	}
}

// HalfPageDown scrolls the view down half a page
func (v *View) HalfPageDown() {
	if len(v.buf.lines)-(v.topline+v.height) > v.height/2 {
		v.ScrollDown(v.height / 2)
	} else {
		v.topline = len(v.buf.lines) - v.height
	}
}

// HandleEvent handles an event passed by the main loop
// It returns an int describing how the screen needs to be redrawn
// 0: Screen does not need to be redrawn
// 1: Only the cursor/statusline needs to be redrawn
// 2: Everything needs to be redrawn
func (v *View) HandleEvent(event tcell.Event) int {
	var ret int
	switch e := event.(type) {
	case *tcell.EventKey:
		switch e.Key() {
		case tcell.KeyUp:
			v.cursor.Up()
			ret = 1
		case tcell.KeyDown:
			v.cursor.Down()
			ret = 1
		case tcell.KeyLeft:
			v.cursor.Left()
			ret = 1
		case tcell.KeyRight:
			v.cursor.Right()
			ret = 1
		case tcell.KeyEnter:
			v.eh.Insert(v.cursor.loc, "\n")
			v.cursor.Right()
			ret = 2
		case tcell.KeySpace:
			v.eh.Insert(v.cursor.loc, " ")
			v.cursor.Right()
			ret = 2
		case tcell.KeyBackspace2:
			if v.cursor.HasSelection() {
				v.cursor.DeleteSelection()
				v.cursor.ResetSelection()
				ret = 2
			} else if v.cursor.loc > 0 {
				// We have to do something a bit hacky here because we want to
				// delete the line by first moving left and then deleting backwards
				// but the undo redo would place the cursor in the wrong place
				// So instead we move left, save the position, move back, delete
				// and restore the position
				v.cursor.Left()
				cx, cy, cloc := v.cursor.x, v.cursor.y, v.cursor.loc
				v.cursor.Right()
				v.eh.Remove(v.cursor.loc-1, v.cursor.loc)
				v.cursor.x, v.cursor.y, v.cursor.loc = cx, cy, cloc
				ret = 2
			}
		case tcell.KeyTab:
			v.eh.Insert(v.cursor.loc, "\t")
			v.cursor.Right()
			ret = 2
		case tcell.KeyCtrlS:
			err := v.buf.Save()
			if err != nil {
				// Error!
			}
			// Need to redraw the status line
			ret = 1
		case tcell.KeyCtrlZ:
			v.eh.Undo()
			ret = 2
		case tcell.KeyCtrlY:
			v.eh.Redo()
			ret = 2
		case tcell.KeyCtrlC:
			if v.cursor.HasSelection() {
				if !clipboard.Unsupported {
					clipboard.WriteAll(v.cursor.GetSelection())
					ret = 2
				}
			}
		case tcell.KeyCtrlX:
			if v.cursor.HasSelection() {
				if !clipboard.Unsupported {
					clipboard.WriteAll(v.cursor.GetSelection())
					v.cursor.DeleteSelection()
					v.cursor.ResetSelection()
					ret = 2
				}
			}
		case tcell.KeyCtrlV:
			if !clipboard.Unsupported {
				if v.cursor.HasSelection() {
					v.cursor.DeleteSelection()
					v.cursor.ResetSelection()
				}
				clip, _ := clipboard.ReadAll()
				v.eh.Insert(v.cursor.loc, clip)
				// This is a bit weird... Not sure if there's a better way
				for i := 0; i < Count(clip); i++ {
					v.cursor.Right()
				}
				ret = 2
			}
		case tcell.KeyPgUp:
			v.PageUp()
			return 2
		case tcell.KeyPgDn:
			v.PageDown()
			return 2
		case tcell.KeyCtrlU:
			v.HalfPageUp()
			return 2
		case tcell.KeyCtrlD:
			v.HalfPageDown()
			return 2
		case tcell.KeyRune:
			if v.cursor.HasSelection() {
				v.cursor.DeleteSelection()
				v.cursor.ResetSelection()
			}
			v.eh.Insert(v.cursor.loc, string(e.Rune()))
			v.cursor.Right()
			ret = 2
		}
	case *tcell.EventMouse:
		x, y := e.Position()
		x -= v.lineNumOffset
		y += v.topline
		// Position always seems to be off by one
		x--
		y--

		button := e.Buttons()

		switch button {
		case tcell.Button1:
			if y-v.topline > v.height-1 {
				v.ScrollDown(1)
				y = v.height + v.topline - 1
			}
			if y > len(v.buf.lines) {
				y = len(v.buf.lines) - 1
			}
			if x < 0 {
				x = 0
			}

			x = v.cursor.GetCharPosInLine(y, x)
			if x > Count(v.buf.lines[y]) {
				x = Count(v.buf.lines[y])
			}
			d := v.cursor.Distance(x, y)
			v.cursor.loc += d
			v.cursor.x = x
			v.cursor.y = y

			if v.mouseReleased {
				v.cursor.selectionStart = v.cursor.loc
				v.cursor.selectionStartX = v.cursor.x
				v.cursor.selectionStartY = v.cursor.y
			}
			v.cursor.selectionEnd = v.cursor.loc
			v.mouseReleased = false
			return 2
		case tcell.ButtonNone:
			v.mouseReleased = true
			return 0
		case tcell.WheelUp:
			v.ScrollUp(2)
			return 2
		case tcell.WheelDown:
			v.ScrollDown(2)
			return 2
		}
	}

	cy := v.cursor.y
	if cy < v.topline {
		v.topline = cy
		ret = 2
	}
	if cy > v.topline+v.height-1 {
		v.topline = cy - v.height + 1
		ret = 2
	}

	return ret
}

// Display renders the view to the screen
func (v *View) Display() {
	var x int

	charNum := v.cursor.loc + v.cursor.Distance(0, v.topline)

	// Convert the length of buffer to a string, and get the length of the string
	// We are going to have to offset by that amount
	maxLineLength := len(strconv.Itoa(len(v.buf.lines)))
	// + 1 for the little space after the line number
	v.lineNumOffset = maxLineLength + 1

	var highlightStyle tcell.Style

	for lineN := 0; lineN < v.height; lineN++ {
		if lineN+v.topline >= len(v.buf.lines) {
			break
		}
		line := v.buf.lines[lineN+v.topline]

		// Write the line number
		lineNumStyle := tcell.StyleDefault
		// Write the spaces before the line number if necessary
		lineNum := strconv.Itoa(lineN + v.topline + 1)
		for i := 0; i < maxLineLength-len(lineNum); i++ {
			v.s.SetContent(x, lineN, ' ', nil, lineNumStyle)
			x++
		}
		// Write the actual line number
		for _, ch := range lineNum {
			v.s.SetContent(x, lineN, ch, nil, lineNumStyle)
			x++
		}
		// Write the extra space
		v.s.SetContent(x, lineN, ' ', nil, lineNumStyle)
		x++

		// Write the line
		tabchars := 0
		for _, ch := range line {
			var lineStyle tcell.Style
			st, ok := v.matches[charNum]
			if ok {
				highlightStyle = st
			} else {
				highlightStyle = tcell.StyleDefault
			}

			if v.cursor.HasSelection() &&
				(charNum >= v.cursor.selectionStart && charNum <= v.cursor.selectionEnd ||
					charNum <= v.cursor.selectionStart && charNum >= v.cursor.selectionEnd) {
				lineStyle = tcell.StyleDefault
				lineStyle = lineStyle.Reverse(true)
			} else {
				lineStyle = highlightStyle
			}

			if ch == '\t' {
				v.s.SetContent(x+tabchars, lineN, ' ', nil, lineStyle)
				for i := 0; i < tabSize-1; i++ {
					tabchars++
					v.s.SetContent(x+tabchars, lineN, ' ', nil, lineStyle)
				}
			} else {
				v.s.SetContent(x+tabchars, lineN, ch, nil, lineStyle)
			}
			charNum++
			x++
		}
		x = 0
		st, ok := v.matches[charNum]
		if ok {
			highlightStyle = st
		}
		charNum++
	}
}
<commit_msg>Proper window resize handling<commit_after>package main

import (
	"github.com/atotto/clipboard"
	"github.com/zyedidia/tcell"
	"strconv"
)

// The View struct stores information about a view into a buffer.
// It has a value for the cursor, and the window that the user sees
// the buffer from.
type View struct {
	cursor  Cursor
	topline int
	// Leftmost column. Used for horizontal scrolling
	leftCol int

	// Percentage of the terminal window that this view takes up
	heightPercent float32
	widthPercent  float32
	height        int
	width         int

	// How much to offset because of line numbers
	lineNumOffset int

	eh *EventHandler

	buf *Buffer
	sl  Statusline

	mouseReleased bool

	// Syntax highlighting matches
	matches map[int]tcell.Style

	s tcell.Screen
}

// NewView returns a new view with fullscreen width and height
func NewView(buf *Buffer, s tcell.Screen) *View {
	return NewViewWidthHeight(buf, s, 1, 1)
}

// NewViewWidthHeight returns a new view with the specified width and height percentages
func NewViewWidthHeight(buf *Buffer, s tcell.Screen, w, h float32) *View {
	v := new(View)

	v.buf = buf
	v.s = s

	v.widthPercent = w
	v.heightPercent = h
	v.Resize(s.Size())

	v.topline = 0
	v.cursor = Cursor{
		x:   0,
		y:   0,
		loc: 0,
		v:   v,
	}

	v.eh = NewEventHandler(v)

	v.sl = Statusline{
		v: v,
	}

	return v
}

// Resize recalculates the width and height of the view based on the width and height percentages
func (v *View) Resize(w, h int) {
	h--
	v.height = int(float32(h)*v.heightPercent) - 1
	v.width = int(float32(w) * v.widthPercent)
}

// ScrollUp scrolls the view up n lines (if possible)
func (v *View) ScrollUp(n int) {
	// Try to scroll by n but if it would overflow, scroll by 1
	if v.topline-n >= 0 {
		v.topline -= n
	} else if v.topline > 0 {
		v.topline--
	}
}

// ScrollDown scrolls the view down n lines (if possible)
func (v *View) ScrollDown(n int) {
	// Try to scroll by n but if it would overflow, scroll by 1
	if v.topline+n <= len(v.buf.lines)-v.height {
		v.topline += n
	} else if v.topline < len(v.buf.lines)-v.height {
		v.topline++
	}
}

// PageUp scrolls the view up a page
func (v *View) PageUp() {
	if v.topline > v.height {
		v.ScrollUp(v.height)
	} else {
		v.topline = 0
	}
}

// PageDown scrolls the view down a page
func (v *View) PageDown() {
	if len(v.buf.lines)-(v.topline+v.height) > v.height {
		v.ScrollDown(v.height)
	} else {
		v.topline = len(v.buf.lines) - v.height
	}
}

// HalfPageUp scrolls the view up half a page
func (v *View) HalfPageUp() {
	if v.topline > v.height/2 {
		v.ScrollUp(v.height / 2)
	} else {
		v.topline = 0
	}
}

// HalfPageDown scrolls the view down half a page
func (v *View) HalfPageDown() {
	if len(v.buf.lines)-(v.topline+v.height) > v.height/2 {
		v.ScrollDown(v.height / 2)
	} else {
		v.topline = len(v.buf.lines) - v.height
	}
}

// HandleEvent handles an event passed by the main loop
// It returns an int describing how the screen needs to be redrawn
// 0: Screen does not need to be redrawn
// 1: Only the cursor/statusline needs to be redrawn
// 2: Everything needs to be redrawn
func (v *View) HandleEvent(event tcell.Event) int {
	var ret int
	switch e := event.(type) {
	case *tcell.EventResize:
		v.Resize(e.Size())
		ret = 2
	case *tcell.EventKey:
		switch e.Key() {
		case tcell.KeyUp:
			v.cursor.Up()
			ret = 1
		case tcell.KeyDown:
			v.cursor.Down()
			ret = 1
		case tcell.KeyLeft:
			v.cursor.Left()
			ret = 1
		case tcell.KeyRight:
			v.cursor.Right()
			ret = 1
		case tcell.KeyEnter:
			v.eh.Insert(v.cursor.loc, "\n")
			v.cursor.Right()
			ret = 2
		case tcell.KeySpace:
			v.eh.Insert(v.cursor.loc, " ")
			v.cursor.Right()
			ret = 2
		case tcell.KeyBackspace2:
			if v.cursor.HasSelection() {
				v.cursor.DeleteSelection()
				v.cursor.ResetSelection()
				ret = 2
			} else if v.cursor.loc > 0 {
				// We have to do something a bit hacky here because we want to
				// delete the line by first moving left and then deleting backwards
				// but the undo redo would place the cursor in the wrong place
				// So instead we move left, save the position, move back, delete
				// and restore the position
				v.cursor.Left()
				cx, cy, cloc := v.cursor.x, v.cursor.y, v.cursor.loc
				v.cursor.Right()
				v.eh.Remove(v.cursor.loc-1, v.cursor.loc)
				v.cursor.x, v.cursor.y, v.cursor.loc = cx, cy, cloc
				ret = 2
			}
		case tcell.KeyTab:
			v.eh.Insert(v.cursor.loc, "\t")
			v.cursor.Right()
			ret = 2
		case tcell.KeyCtrlS:
			err := v.buf.Save()
			if err != nil {
				// Error!
			}
			// Need to redraw the status line
			ret = 1
		case tcell.KeyCtrlZ:
			v.eh.Undo()
			ret = 2
		case tcell.KeyCtrlY:
			v.eh.Redo()
			ret = 2
		case tcell.KeyCtrlC:
			if v.cursor.HasSelection() {
				if !clipboard.Unsupported {
					clipboard.WriteAll(v.cursor.GetSelection())
					ret = 2
				}
			}
		case tcell.KeyCtrlX:
			if v.cursor.HasSelection() {
				if !clipboard.Unsupported {
					clipboard.WriteAll(v.cursor.GetSelection())
					v.cursor.DeleteSelection()
					v.cursor.ResetSelection()
					ret = 2
				}
			}
		case tcell.KeyCtrlV:
			if !clipboard.Unsupported {
				if v.cursor.HasSelection() {
					v.cursor.DeleteSelection()
					v.cursor.ResetSelection()
				}
				clip, _ := clipboard.ReadAll()
				v.eh.Insert(v.cursor.loc, clip)
				// This is a bit weird... Not sure if there's a better way
				for i := 0; i < Count(clip); i++ {
					v.cursor.Right()
				}
				ret = 2
			}
		case tcell.KeyPgUp:
			v.PageUp()
			return 2
		case tcell.KeyPgDn:
			v.PageDown()
			return 2
		case tcell.KeyCtrlU:
			v.HalfPageUp()
			return 2
		case tcell.KeyCtrlD:
			v.HalfPageDown()
			return 2
		case tcell.KeyRune:
			if v.cursor.HasSelection() {
				v.cursor.DeleteSelection()
				v.cursor.ResetSelection()
			}
			v.eh.Insert(v.cursor.loc, string(e.Rune()))
			v.cursor.Right()
			ret = 2
		}
	case *tcell.EventMouse:
		x, y := e.Position()
		x -= v.lineNumOffset
		y += v.topline
		// Position always seems to be off by one
		x--
		y--

		button := e.Buttons()

		switch button {
		case tcell.Button1:
			if y-v.topline > v.height-1 {
				v.ScrollDown(1)
				y = v.height + v.topline - 1
			}
			if y > len(v.buf.lines) {
				y = len(v.buf.lines) - 1
			}
			if x < 0 {
				x = 0
			}

			x = v.cursor.GetCharPosInLine(y, x)
			if x > Count(v.buf.lines[y]) {
				x = Count(v.buf.lines[y])
			}
			d := v.cursor.Distance(x, y)
			v.cursor.loc += d
			v.cursor.x = x
			v.cursor.y = y

			if v.mouseReleased {
				v.cursor.selectionStart = v.cursor.loc
				v.cursor.selectionStartX = v.cursor.x
				v.cursor.selectionStartY = v.cursor.y
			}
			v.cursor.selectionEnd = v.cursor.loc
			v.mouseReleased = false
			return 2
		case tcell.ButtonNone:
			v.mouseReleased = true
			return 0
		case tcell.WheelUp:
			v.ScrollUp(2)
			return 2
		case tcell.WheelDown:
			v.ScrollDown(2)
			return 2
		}
	}

	cy := v.cursor.y
	if cy < v.topline {
		v.topline = cy
		ret = 2
	}
	if cy > v.topline+v.height-1 {
		v.topline = cy - v.height + 1
		ret = 2
	}

	return ret
}

// Display renders the view to the screen
func (v *View) Display() {
	var x int

	charNum := v.cursor.loc + v.cursor.Distance(0, v.topline)

	// Convert the length of buffer to a string, and get the length of the string
	// We are going to have to offset by that amount
	maxLineLength := len(strconv.Itoa(len(v.buf.lines)))
	// + 1 for the little space after the line number
	v.lineNumOffset = maxLineLength + 1

	var highlightStyle tcell.Style

	for lineN := 0; lineN < v.height; lineN++ {
		if lineN+v.topline >= len(v.buf.lines) {
			break
		}
		line := v.buf.lines[lineN+v.topline]

		// Write the line number
		lineNumStyle := tcell.StyleDefault
		// Write the spaces before the line number if necessary
		lineNum := strconv.Itoa(lineN + v.topline + 1)
		for i := 0; i < maxLineLength-len(lineNum); i++ {
			v.s.SetContent(x, lineN, ' ', nil, lineNumStyle)
			x++
		}
		// Write the actual line number
		for _, ch := range lineNum {
			v.s.SetContent(x, lineN, ch, nil, lineNumStyle)
			x++
		}
		// Write the extra space
		v.s.SetContent(x, lineN, ' ', nil, lineNumStyle)
		x++

		// Write the line
		tabchars := 0
		for _, ch := range line {
			var lineStyle tcell.Style
			st, ok := v.matches[charNum]
			if ok {
				highlightStyle = st
			} else {
				highlightStyle = tcell.StyleDefault
			}

			if v.cursor.HasSelection() &&
				(charNum >= v.cursor.selectionStart && charNum <= v.cursor.selectionEnd ||
					charNum <= v.cursor.selectionStart && charNum >= v.cursor.selectionEnd) {
				lineStyle = tcell.StyleDefault
				lineStyle = lineStyle.Reverse(true)
			} else {
				lineStyle = highlightStyle
			}

			if ch == '\t' {
				v.s.SetContent(x+tabchars, lineN, ' ', nil, lineStyle)
				for i := 0; i < tabSize-1; i++ {
					tabchars++
					v.s.SetContent(x+tabchars, lineN, ' ', nil, lineStyle)
				}
			} else {
				v.s.SetContent(x+tabchars, lineN, ch, nil, lineStyle)
			}
			charNum++
			x++
		}
		x = 0
		st, ok := v.matches[charNum]
		if ok {
			highlightStyle = st
		}
		charNum++
	}
}
<|endoftext|>