<commit_before>package redlot

import (
	"strconv"

	"github.com/syndtr/goleveldb/leveldb/util"
)

func encodeHashKey(name, key []byte) (buf []byte) {
	buf = append(buf, typeHASH)
	buf = append(buf, uint32ToBytes(uint32(len(name)))...)
	buf = append(buf, name...)
	buf = append(buf, key...)
	return
}

func decodeHashKey(b []byte) (name, key []byte) {
	nameLen := bytesToUint32(b[1:5])
	name = b[5 : 5+nameLen]
	key = b[5+nameLen:]
	return
}

func encodeHsizeKey(name []byte) (buf []byte) {
	buf = append(buf, typeHSIZE)
	buf = append(buf, name...)
	return
}

func decodeHsizeKey(b []byte) (key []byte) {
	return b[1:]
}

func hashSizeIncr(name []byte, incr int) {
	hsize := encodeHsizeKey(name)

	var size uint32
	if b, err := db.Get(hsize, nil); err == nil {
		size = bytesToUint32(b)
	}

	if incr > 0 {
		size += uint32(incr)
	}
	if incr < 0 && size > 0 {
		size = size - uint32(0-incr)
	}

	if size == 0 {
		db.Delete(hsize, nil)
	}
	if size > 0 {
		db.Put(hsize, uint32ToBytes(size), nil)
	}
}

// Hset will set a hashmap value by the key.
// Args: name string, key string, value any
func Hset(args [][]byte) (r interface{}, err error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}
	key := encodeHashKey(args[0], args[1])

	if exists, _ := db.Has(key, nil); !exists {
		hashSizeIncr(args[0], 1)
	}

	err = db.Put(key, args[2], nil)
	if err != nil {
		hashSizeIncr(args[0], -1)
		return nil, err
	}

	return
}

// Hset will return a hashmap value by the key.
// Args: name string, key string
func Hget(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}
	var b []byte
	b, err = db.Get(encodeHashKey(args[0], args[1]), nil)
	return string(b), err
}

// Hdel will delete a hashmap value by the key.
// Args: name string, key string
func Hdel(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}
	err = db.Delete(encodeHashKey(args[0], args[1]), nil)
	if err == nil {
		hashSizeIncr(args[0], -1)
	}
	return
}

func hincr(name, key []byte, increment int) (r int64, err error) {
	hash := encodeHashKey(name, key)
	v, _ := db.Get(hash, nil)
	var number int
	var exists bool
	if len(v) != 0 {
		number, err = strconv.Atoi(string(v))
		exists = true
		if err != nil {
			return -1, errNotInt
		}
	}
	number += increment
	r = int64(number)
	err = db.Put(hash, []byte(strconv.Itoa(number)), nil)
	if err == nil && !exists {
		hashSizeIncr(name, 1)
	}
	return
}

// Hincr will incr a hashmap value by the key.
// Args: name string, key string
func Hincr(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	return hincr(args[0], args[1], 1)
}

// Hincrby will incr number a hashmap value by the key.
// Args: name string, key string, value int
func Hincrby(args [][]byte) (r interface{}, err error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}
	i, e := strconv.Atoi(string(args[2]))
	if e != nil {
		return -1, errNotInt
	}

	return hincr(args[0], args[1], i)
}

// Hexists will check the hashmap key is exists.
// Args: name string, key string
func Hexists(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	return
}

// Hsize will return the hashmap size.
// Args: name string
func Hsize(args [][]byte) (r interface{}, err error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}

	var size int64
	if b, e := db.Get(encodeHsizeKey(args[0]), nil); e != nil {
		size = -1
	} else {
		size = int64(bytesToUint32(b))
	}

	return size, nil
}

func hlist(args [][]byte, reverse bool) (r []string, err error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}

	var ks, ke []byte
	if len(args[0]) == 0 {
		ks = []byte{0x48, 0x00}
	} else {
		ks = encodeHsizeKey(args[0])
	}
	if len(args[1]) == 0 {
		ke = []byte{0x48, 0xff}
	} else {
		ke = encodeHsizeKey(args[1])
	}

	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	limit, _ := strconv.Atoi(string(args[2]))

	var iters func() bool
	if reverse {
		iter.Seek([]byte{0x48, 0xff})
		iters = iter.Prev
	} else {
		iters = iter.Next
	}
	for iters() {
		key := decodeHsizeKey(iter.Key())
		r = append(r, string(key))
		limit--
		if limit <= 0 {
			break
		}
	}

	iter.Release()
	err = iter.Error()

	return
}

// Hlist will list all hashmap in the range.
// Args: start string, end string, limit int
func Hlist(args [][]byte) (r []string, err error) {
	r, err = hlist(args, false)
	return
}

// Hrlist will reverse list all hashmap in the range.
// Args: start string, end string, limit int
func Hrlist(args [][]byte) (r []string, err error) {
	r, err = hlist(args, true)

	return
}

func hscan(args [][]byte, kv, reverse bool) (r []string, err error) {
	if _, err = db.Get(encodeHsizeKey(args[0]), nil); err != nil {
		return
	}

	if len(args[1]) != 0 && string(args[1]) >= string(args[2]) {
		return []string{""}, nil
	}

	var ks, ke []byte
	if len(args[1]) == 0 {
		ks = append(ks, typeHASH)
		ks = append(ks, uint32ToBytes(uint32(len(args[0])))...)
		ks = append(ks, args[0]...)
	} else {
		ks = encodeHashKey(args[0], args[1])
	}

	if len(args[2]) == 0 {
		ke = append(ks, []byte{0xff}...)
	} else {
		ke = encodeHashKey(args[0], args[2])
	}

	limit, _ := strconv.Atoi(string(args[3]))

	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	var iters func() bool
	if reverse {
		iter.Seek(ke)
		iters = iter.Prev
	} else {
		iters = iter.Next
	}
	for iters() {
		_, key := decodeHashKey(iter.Key())
		r = append(r, string(key))
		if kv {
			r = append(r, string(iter.Value()))
		}
		limit--
		if limit <= 0 {
			break
		}
	}

	iter.Release()
	err = iter.Error()

	return
}

// Hkeys will list the hashmap keys in the range.
// Args: name string, start string, end string, limit int
func Hkeys(args [][]byte) (r []string, err error) {
	if len(args) < 4 {
		return nil, errNosArgs
	}

	r, err = hscan(args, false, false)

	return
}

// Hrkeys will reverse list the hashmap keys in the range.
// Args: name string, start string, end string, limit int
func Hrkeys(args [][]byte) (r []string, err error) {
	if len(args) < 4 {
		return nil, errNosArgs
	}

	r, err = hscan(args, false, true)

	return
}

// Hgetall will list all keys/value in the hashmap.
// Args: name string
func Hgetall(args [][]byte) (r []string, err error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}

	if _, err = db.Get(encodeHsizeKey(args[0]), nil); err != nil {
		return
	}

	var buf []byte
	buf = append(buf, typeHASH)
	buf = append(buf, uint32ToBytes(uint32(len(args[0])))...)
	buf = append(buf, args[0]...)
	ke := append(buf, []byte{0xff}...)

	iter := db.NewIterator(&util.Range{Start: buf, Limit: ke}, nil)
	for iter.Next() {
		_, key := decodeHashKey(iter.Key())
		r = append(r, string(key))
		r = append(r, string(iter.Value()))
	}
	iter.Release()
	err = iter.Error()
	return
}

// Hscan will list keys/value of the hashmap in the range.
// Args: name string, start string, end string, limit int
func Hscan(args [][]byte) (r []string, err error) {
	if len(args) < 4 {
		return nil, errNosArgs
	}

	r, err = hscan(args, true, false)

	return
}

// Hrscan will reverse list keys/value of the hashmap in the range.
// Args: name string, start string, end string, limit int
func Hrscan(args [][]byte) (r []string, err error) {
	if len(args) < 4 {
		return nil, errNosArgs
	}

	r, err = hscan(args, true, true)

	return
}

// Hclear will remove all value in the hashmap.
// Args: name string
func Hclear(args [][]byte) (r interface{}, err error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}

	return
}

// MultiHget will return multi hashmap value by keys.
func MultiHget(args [][]byte) (r []string, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	return
}

// MultiHset will set multi hashmap value by keys.
func MultiHset(args [][]byte) (r interface{}, err error) {
	if len(args) < 3 && len(args)%2 == 0 {
		return nil, errNosArgs
	}

	return
}

// MultiHdel will delete multi hashmap value by keys.
func MultiHdel(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	return
}
<commit_msg>Implement Hexists method.<commit_after>package redlot

import (
	"strconv"

	"github.com/syndtr/goleveldb/leveldb/util"
)

func encodeHashKey(name, key []byte) (buf []byte) {
	buf = append(buf, typeHASH)
	buf = append(buf, uint32ToBytes(uint32(len(name)))...)
	buf = append(buf, name...)
	buf = append(buf, key...)
	return
}

func decodeHashKey(b []byte) (name, key []byte) {
	nameLen := bytesToUint32(b[1:5])
	name = b[5 : 5+nameLen]
	key = b[5+nameLen:]
	return
}

func encodeHsizeKey(name []byte) (buf []byte) {
	buf = append(buf, typeHSIZE)
	buf = append(buf, name...)
	return
}

func decodeHsizeKey(b []byte) (key []byte) {
	return b[1:]
}

func hashSizeIncr(name []byte, incr int) {
	hsize := encodeHsizeKey(name)

	var size uint32
	if b, err := db.Get(hsize, nil); err == nil {
		size = bytesToUint32(b)
	}

	if incr > 0 {
		size += uint32(incr)
	}
	if incr < 0 && size > 0 {
		size = size - uint32(0-incr)
	}

	if size == 0 {
		db.Delete(hsize, nil)
	}
	if size > 0 {
		db.Put(hsize, uint32ToBytes(size), nil)
	}
}

// Hset will set a hashmap value by the key.
// Args: name string, key string, value any
func Hset(args [][]byte) (r interface{}, err error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}
	key := encodeHashKey(args[0], args[1])

	if exists, _ := db.Has(key, nil); !exists {
		hashSizeIncr(args[0], 1)
	}

	err = db.Put(key, args[2], nil)
	if err != nil {
		hashSizeIncr(args[0], -1)
		return nil, err
	}

	return
}

// Hset will return a hashmap value by the key.
// Args: name string, key string
func Hget(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}
	var b []byte
	b, err = db.Get(encodeHashKey(args[0], args[1]), nil)
	return string(b), err
}

// Hdel will delete a hashmap value by the key.
// Args: name string, key string
func Hdel(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}
	err = db.Delete(encodeHashKey(args[0], args[1]), nil)
	if err == nil {
		hashSizeIncr(args[0], -1)
	}
	return
}

func hincr(name, key []byte, increment int) (r int64, err error) {
	hash := encodeHashKey(name, key)
	v, _ := db.Get(hash, nil)
	var number int
	var exists bool
	if len(v) != 0 {
		number, err = strconv.Atoi(string(v))
		exists = true
		if err != nil {
			return -1, errNotInt
		}
	}
	number += increment
	r = int64(number)
	err = db.Put(hash, []byte(strconv.Itoa(number)), nil)
	if err == nil && !exists {
		hashSizeIncr(name, 1)
	}
	return
}

// Hincr will incr a hashmap value by the key.
// Args: name string, key string
func Hincr(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	return hincr(args[0], args[1], 1)
}

// Hincrby will incr number a hashmap value by the key.
// Args: name string, key string, value int
func Hincrby(args [][]byte) (r interface{}, err error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}
	i, e := strconv.Atoi(string(args[2]))
	if e != nil {
		return -1, errNotInt
	}

	return hincr(args[0], args[1], i)
}

// Hexists will check the hashmap key is exists.
// Args: name string, key string
func Hexists(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	var exists bool
	exists, err = db.Has(encodeHashKey(args[0], args[1]), nil)
	if exists {
		r = int64(1)
	} else {
		r = int64(0)
	}

	return
}

// Hsize will return the hashmap size.
// Args: name string
func Hsize(args [][]byte) (r interface{}, err error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}

	var size int64
	if b, e := db.Get(encodeHsizeKey(args[0]), nil); e != nil {
		size = -1
	} else {
		size = int64(bytesToUint32(b))
	}

	return size, nil
}

func hlist(args [][]byte, reverse bool) (r []string, err error) {
	if len(args) < 3 {
		return nil, errNosArgs
	}

	var ks, ke []byte
	if len(args[0]) == 0 {
		ks = []byte{0x48, 0x00}
	} else {
		ks = encodeHsizeKey(args[0])
	}
	if len(args[1]) == 0 {
		ke = []byte{0x48, 0xff}
	} else {
		ke = encodeHsizeKey(args[1])
	}

	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	limit, _ := strconv.Atoi(string(args[2]))

	var iters func() bool
	if reverse {
		iter.Seek([]byte{0x48, 0xff})
		iters = iter.Prev
	} else {
		iters = iter.Next
	}
	for iters() {
		key := decodeHsizeKey(iter.Key())
		r = append(r, string(key))
		limit--
		if limit <= 0 {
			break
		}
	}

	iter.Release()
	err = iter.Error()

	return
}

// Hlist will list all hashmap in the range.
// Args: start string, end string, limit int
func Hlist(args [][]byte) (r []string, err error) {
	r, err = hlist(args, false)
	return
}

// Hrlist will reverse list all hashmap in the range.
// Args: start string, end string, limit int
func Hrlist(args [][]byte) (r []string, err error) {
	r, err = hlist(args, true)

	return
}

func hscan(args [][]byte, kv, reverse bool) (r []string, err error) {
	if _, err = db.Get(encodeHsizeKey(args[0]), nil); err != nil {
		return
	}

	if len(args[1]) != 0 && string(args[1]) >= string(args[2]) {
		return []string{""}, nil
	}

	var ks, ke []byte
	if len(args[1]) == 0 {
		ks = append(ks, typeHASH)
		ks = append(ks, uint32ToBytes(uint32(len(args[0])))...)
		ks = append(ks, args[0]...)
	} else {
		ks = encodeHashKey(args[0], args[1])
	}

	if len(args[2]) == 0 {
		ke = append(ks, []byte{0xff}...)
	} else {
		ke = encodeHashKey(args[0], args[2])
	}

	limit, _ := strconv.Atoi(string(args[3]))

	iter := db.NewIterator(&util.Range{Start: ks, Limit: ke}, nil)
	var iters func() bool
	if reverse {
		iter.Seek(ke)
		iters = iter.Prev
	} else {
		iters = iter.Next
	}
	for iters() {
		_, key := decodeHashKey(iter.Key())
		r = append(r, string(key))
		if kv {
			r = append(r, string(iter.Value()))
		}
		limit--
		if limit <= 0 {
			break
		}
	}

	iter.Release()
	err = iter.Error()

	return
}

// Hkeys will list the hashmap keys in the range.
// Args: name string, start string, end string, limit int
func Hkeys(args [][]byte) (r []string, err error) {
	if len(args) < 4 {
		return nil, errNosArgs
	}

	r, err = hscan(args, false, false)

	return
}

// Hrkeys will reverse list the hashmap keys in the range.
// Args: name string, start string, end string, limit int
func Hrkeys(args [][]byte) (r []string, err error) {
	if len(args) < 4 {
		return nil, errNosArgs
	}

	r, err = hscan(args, false, true)

	return
}

// Hgetall will list all keys/value in the hashmap.
// Args: name string
func Hgetall(args [][]byte) (r []string, err error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}

	if _, err = db.Get(encodeHsizeKey(args[0]), nil); err != nil {
		return
	}

	var buf []byte
	buf = append(buf, typeHASH)
	buf = append(buf, uint32ToBytes(uint32(len(args[0])))...)
	buf = append(buf, args[0]...)
	ke := append(buf, []byte{0xff}...)

	iter := db.NewIterator(&util.Range{Start: buf, Limit: ke}, nil)
	for iter.Next() {
		_, key := decodeHashKey(iter.Key())
		r = append(r, string(key))
		r = append(r, string(iter.Value()))
	}
	iter.Release()
	err = iter.Error()
	return
}

// Hscan will list keys/value of the hashmap in the range.
// Args: name string, start string, end string, limit int
func Hscan(args [][]byte) (r []string, err error) {
	if len(args) < 4 {
		return nil, errNosArgs
	}

	r, err = hscan(args, true, false)

	return
}

// Hrscan will reverse list keys/value of the hashmap in the range.
// Args: name string, start string, end string, limit int
func Hrscan(args [][]byte) (r []string, err error) {
	if len(args) < 4 {
		return nil, errNosArgs
	}

	r, err = hscan(args, true, true)

	return
}

// Hclear will remove all value in the hashmap.
// Args: name string
func Hclear(args [][]byte) (r interface{}, err error) {
	if len(args) < 1 {
		return nil, errNosArgs
	}

	return
}

// MultiHget will return multi hashmap value by keys.
func MultiHget(args [][]byte) (r []string, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	return
}

// MultiHset will set multi hashmap value by keys.
func MultiHset(args [][]byte) (r interface{}, err error) {
	if len(args) < 3 && len(args)%2 == 0 {
		return nil, errNosArgs
	}

	return
}

// MultiHdel will delete multi hashmap value by keys.
func MultiHdel(args [][]byte) (r interface{}, err error) {
	if len(args) < 2 {
		return nil, errNosArgs
	}

	return
}
<|endoftext|>


<commit_before>package copro

import (
	"strings"

	runewidth "github.com/mattn/go-runewidth"
	termbox "github.com/nsf/termbox-go"
)

var lastVerticalPosition int

func (app *App) Renderer(buffer func()) {
	defer termbox.Close()

	termbox.SetOutputMode(termbox.OutputNormal)
	termbox.SetInputMode(termbox.InputEsc)
	draw(buffer)
mainloop:
	for {
		switch ev := termbox.PollEvent(); ev.Type {

		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc:
				break mainloop
			case termbox.KeyCtrlC:
				break mainloop

			case termbox.KeySpace:
				app.selectCurrentPointer()

			case termbox.KeyEnter:
				break mainloop

			case termbox.KeyArrowDown:
				app.moveCurrentPointerDown()
			case termbox.KeyArrowUp:
				app.moveCurrentPointerUp()
			}
			switch ev.Ch {
			case 'k':
				app.moveCurrentPointerUp()
			case 'j':
				app.moveCurrentPointerDown()
			case 'o':
				app.selectCurrentPointer()
			}
		case termbox.EventError:
			panic(ev.Err)
		}

		draw(buffer)
	}
}

func (app *App) moveCurrentPointerUp() {

	maxIndex := app.EntryCount
	if app.Pointer-1 < 0 {
		app.Pointer = maxIndex
	} else {
		app.Pointer -= 1
	}
}

func (app *App) moveCurrentPointerDown() {
	maxIndex := app.EntryCount
	if app.Pointer+1 > maxIndex {
		app.Pointer = 0
	} else {
		app.Pointer += 1
	}
}

func (app *App) selectCurrentPointer() {
	exist := false
	for i, pointer := range app.SavedPointers {
		if app.Pointer == pointer {
			exist = true
			app.SavedPointers = append(app.SavedPointers[:i], app.SavedPointers[i+1:]...)
		}
	}
	if !exist {
		app.SavedPointers = append(app.SavedPointers, app.Pointer)
	}

}
func draw(buffer func()) {
	lastVerticalPosition = 0
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	buffer()
	termbox.Sync()
}

func Display(msg string) {
	printLine(msg, termbox.ColorDefault)
}

func DisplayCyan(msg string) {
	printLine(msg, termbox.ColorCyan)
}

func DisplayYellow(msg string) {
	printLine(msg, termbox.ColorYellow)
}

func DisplayBlack(msg string) {
	printLine(msg, termbox.ColorBlack)
}

func DisplayBlue(msg string) {
	printLine(msg, termbox.ColorBlue)
}

func DisplayRed(msg string) {
	printLine(msg, termbox.ColorRed)
}

func DisplayGreen(msg string) {
	printLine(msg, termbox.ColorGreen)
}

func DisplayWhite(msg string) {
	printLine(msg, termbox.ColorWhite)
}

func DisplayMajenta(msg string) {
	printLine(msg, termbox.ColorMagenta)
}

func DisplayGrey(msg string) {
	printLine(msg, termbox.ColorBlack)
}

func printLine(msg string, foreground termbox.Attribute) {
	row := strings.Split(msg, "\n")
	for _, line := range row {
		x := 0
		for _, c := range line {
			termbox.SetCell(x, lastVerticalPosition, c, foreground, termbox.ColorDefault)
			w := runewidth.RuneWidth(c)
			if w == 0 || (w == 2 && runewidth.IsAmbiguousWidth(c)) {
				w = 1
			}
			x += w
		}
		lastVerticalPosition++
	}
}
<commit_msg>Ctrl+c should stop the process and not only the loop<commit_after>package copro

import (
	"os"
	"strings"

	runewidth "github.com/mattn/go-runewidth"
	termbox "github.com/nsf/termbox-go"
)

var lastVerticalPosition int

func (app *App) Renderer(buffer func()) {
	defer termbox.Close()

	termbox.SetOutputMode(termbox.OutputNormal)
	termbox.SetInputMode(termbox.InputEsc)
	draw(buffer)
mainloop:
	for {
		switch ev := termbox.PollEvent(); ev.Type {

		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc:
				break mainloop
			case termbox.KeyCtrlC:
				termbox.Close()
				os.Exit(1)
				break mainloop

			case termbox.KeySpace:
				app.selectCurrentPointer()

			case termbox.KeyEnter:
				break mainloop

			case termbox.KeyArrowDown:
				app.moveCurrentPointerDown()
			case termbox.KeyArrowUp:
				app.moveCurrentPointerUp()
			}
			switch ev.Ch {
			case 'k':
				app.moveCurrentPointerUp()
			case 'j':
				app.moveCurrentPointerDown()
			case 'o':
				app.selectCurrentPointer()
			}
		case termbox.EventError:
			panic(ev.Err)
		}

		draw(buffer)
	}
}

func (app *App) moveCurrentPointerUp() {

	maxIndex := app.EntryCount
	if app.Pointer-1 < 0 {
		app.Pointer = maxIndex
	} else {
		app.Pointer -= 1
	}
}

func (app *App) moveCurrentPointerDown() {
	maxIndex := app.EntryCount
	if app.Pointer+1 > maxIndex {
		app.Pointer = 0
	} else {
		app.Pointer += 1
	}
}

func (app *App) selectCurrentPointer() {
	exist := false
	for i, pointer := range app.SavedPointers {
		if app.Pointer == pointer {
			exist = true
			app.SavedPointers = append(app.SavedPointers[:i], app.SavedPointers[i+1:]...)
		}
	}
	if !exist {
		app.SavedPointers = append(app.SavedPointers, app.Pointer)
	}

}
func draw(buffer func()) {
	lastVerticalPosition = 0
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	buffer()
	termbox.Sync()
}

func Display(msg string) {
	printLine(msg, termbox.ColorDefault)
}

func DisplayCyan(msg string) {
	printLine(msg, termbox.ColorCyan)
}

func DisplayYellow(msg string) {
	printLine(msg, termbox.ColorYellow)
}

func DisplayBlack(msg string) {
	printLine(msg, termbox.ColorBlack)
}

func DisplayBlue(msg string) {
	printLine(msg, termbox.ColorBlue)
}

func DisplayRed(msg string) {
	printLine(msg, termbox.ColorRed)
}

func DisplayGreen(msg string) {
	printLine(msg, termbox.ColorGreen)
}

func DisplayWhite(msg string) {
	printLine(msg, termbox.ColorWhite)
}

func DisplayMajenta(msg string) {
	printLine(msg, termbox.ColorMagenta)
}

func DisplayGrey(msg string) {
	printLine(msg, termbox.ColorBlack)
}

func printLine(msg string, foreground termbox.Attribute) {
	row := strings.Split(msg, "\n")
	for _, line := range row {
		x := 0
		for _, c := range line {
			termbox.SetCell(x, lastVerticalPosition, c, foreground, termbox.ColorDefault)
			w := runewidth.RuneWidth(c)
			if w == 0 || (w == 2 && runewidth.IsAmbiguousWidth(c)) {
				w = 1
			}
			x += w
		}
		lastVerticalPosition++
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"gopkg.in/BlueDragonX/go-hash.v1"
	"gopkg.in/BlueDragonX/simplelog.v1"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

type Template struct {
	Src    string
	Dest   string
	logger *simplelog.Logger
}

func NewTemplate(src, dest string, logger *simplelog.Logger) Template {
	return Template{src, dest, logger}
}

// Return true if one file differs from another.
func (t *Template) differs(fileA, fileB string) bool {
	var err error
	var hashA, hashB string
	if hashA, err = hash.File(fileA); err != nil {
		t.logger.Warn("unable to hash %s", fileA)
		return true
	}
	if hashB, err = hash.File(fileB); err != nil {
		t.logger.Warn("unable to hash %s", fileB)
		return true
	}
	return hashA != hashB
}

// Render the template to a temporary and return true if the original was changed.
func (t *Template) Render(context map[string]interface{}) (changed bool, err error) {
	// create the destination directory
	dir := filepath.Dir(t.Dest)
	if err = os.MkdirAll(dir, 0777); err != nil {
		return
	}

	// create a temp file to write
	var tmp *os.File
	prefix := fmt.Sprintf(".%s-", filepath.Base(t.Dest))
	if tmp, err = ioutil.TempFile(dir, prefix); err != nil {
		return
	}
	defer func() {
		tmp.Close()
		os.Remove(tmp.Name())
	}()

	// add functions to the templates
	funcs := template.FuncMap{
		"replace": strings.Replace,
	}

	// render the template to the temp file
	var tpl *template.Template
	name := filepath.Base(t.Src)
	if tpl, err = template.New(name).Funcs(funcs).ParseFiles(t.Src); err != nil {
		return
	}
	if err = tpl.Execute(tmp, context); err != nil {
		return
	}
	tmp.Close()

	// return if the old and new files are the same
	changed = t.differs(t.Dest, tmp.Name())
	if !changed {
		return
	}

	// replace the old file with the new one
	err = os.Rename(tmp.Name(), t.Dest)
	return
}

// A renderer generates files from a collection of templates.
type Renderer struct {
	templates []Template
	logger    *simplelog.Logger
}

func NewRenderer(templates []Template, logger *simplelog.Logger) *Renderer {
	item := &Renderer{
		templates,
		logger,
	}
	return item
}

func (renderer *Renderer) Render(context map[string]interface{}) (changed bool, err error) {
	var oneChanged bool
	for _, template := range renderer.templates {
		if oneChanged, err = template.Render(context); err != nil {
			return
		}
		if oneChanged {
			renderer.logger.Debug("template '%s' rendered to '%s'", template.Src, template.Dest)
		} else {
			renderer.logger.Debug("template '%s' did not change", template.Dest)
		}
		changed = changed || oneChanged
	}
	return changed, nil
}
<commit_msg>Only remove tmp file if it's not already moved.<commit_after>package main

import (
	"fmt"
	"gopkg.in/BlueDragonX/go-hash.v1"
	"gopkg.in/BlueDragonX/simplelog.v1"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

type Template struct {
	Src    string
	Dest   string
	logger *simplelog.Logger
}

func NewTemplate(src, dest string, logger *simplelog.Logger) Template {
	return Template{src, dest, logger}
}

// Return true if one file differs from another.
func (t *Template) differs(fileA, fileB string) bool {
	var err error
	var hashA, hashB string
	if hashA, err = hash.File(fileA); err != nil {
		t.logger.Warn("unable to hash %s", fileA)
		return true
	}
	if hashB, err = hash.File(fileB); err != nil {
		t.logger.Warn("unable to hash %s", fileB)
		return true
	}
	return hashA != hashB
}

// Render the template to a temporary and return true if the original was changed.
func (t *Template) Render(context map[string]interface{}) (changed bool, err error) {
	// create the destination directory
	dir := filepath.Dir(t.Dest)
	if err = os.MkdirAll(dir, 0777); err != nil {
		return
	}

	// create a temp file to write
	var tmp *os.File
	prefix := fmt.Sprintf(".%s-", filepath.Base(t.Dest))
	if tmp, err = ioutil.TempFile(dir, prefix); err != nil {
		return
	}
	defer func() {
		tmp.Close()
		if !changed || err != nil {
			os.Remove(tmp.Name())
		}
	}()

	// add functions to the templates
	funcs := template.FuncMap{
		"replace": strings.Replace,
	}

	// render the template to the temp file
	var tpl *template.Template
	name := filepath.Base(t.Src)
	if tpl, err = template.New(name).Funcs(funcs).ParseFiles(t.Src); err != nil {
		return
	}
	if err = tpl.Execute(tmp, context); err != nil {
		return
	}
	tmp.Close()

	// return if the old and new files are the same
	changed = t.differs(t.Dest, tmp.Name())
	if !changed {
		return
	}

	// replace the old file with the new one
	err = os.Rename(tmp.Name(), t.Dest)
	return
}

// A renderer generates files from a collection of templates.
type Renderer struct {
	templates []Template
	logger    *simplelog.Logger
}

func NewRenderer(templates []Template, logger *simplelog.Logger) *Renderer {
	item := &Renderer{
		templates,
		logger,
	}
	return item
}

func (renderer *Renderer) Render(context map[string]interface{}) (changed bool, err error) {
	var oneChanged bool
	for _, template := range renderer.templates {
		if oneChanged, err = template.Render(context); err != nil {
			return
		}
		if oneChanged {
			renderer.logger.Debug("template '%s' rendered to '%s'", template.Src, template.Dest)
		} else {
			renderer.logger.Debug("template '%s' did not change", template.Dest)
		}
		changed = changed || oneChanged
	}
	return changed, nil
}
<|endoftext|>


<commit_before>package txdb

import (
	"bytes"
	"database/sql"
	"sort"
	"time"

	"golang.org/x/net/context"

	"chain/database/pg"
	"chain/errors"
	"chain/fedchain/bc"
	"chain/fedchain/state"
	"chain/metrics"
	"chain/net/trace/span"
	"chain/strings"
)

func poolTxs(ctx context.Context) ([]*bc.Tx, error) {
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	const q = `SELECT tx_hash, data FROM pool_txs ORDER BY sort_id`
	rows, err := pg.FromContext(ctx).Query(ctx, q)
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	defer rows.Close()

	var txs []*bc.Tx
	for rows.Next() {
		var hash bc.Hash
		var data bc.TxData
		err := rows.Scan(&hash, &data)
		if err != nil {
			return nil, errors.Wrap(err, "row scan")
		}
		txs = append(txs, &bc.Tx{TxData: data, Hash: hash, Stored: true})
	}

	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "end row scan loop")
	}

	txs = topSort(ctx, txs)
	return txs, nil
}

// GetTxs looks up transactions by their hashes
// in the block chain and in the pool.
func GetTxs(ctx context.Context, hashes ...bc.Hash) (map[bc.Hash]*bc.Tx, error) {
	hashStrings := make([]string, 0, len(hashes))
	for _, h := range hashes {
		hashStrings = append(hashStrings, h.String())
	}
	sort.Strings(hashStrings)
	hashStrings = strings.Uniq(hashStrings)
	const q = `SELECT tx_hash, data FROM txs WHERE tx_hash=ANY($1)`
	rows, err := pg.FromContext(ctx).Query(ctx, q, pg.Strings(hashStrings))
	if err != nil {
		return nil, errors.Wrap(err, "get txs query")
	}
	defer rows.Close()

	txs := make(map[bc.Hash]*bc.Tx, len(hashes))
	for rows.Next() {
		var hash bc.Hash
		var data bc.TxData
		err = rows.Scan(&hash, &data)
		if err != nil {
			return nil, errors.Wrap(err, "rows scan")
		}
		txs[hash] = &bc.Tx{TxData: data, Hash: hash, Stored: true}
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows end")
	}
	if len(txs) < len(hashStrings) {
		return nil, errors.Wrap(pg.ErrUserInputNotFound, "missing tx")
	}
	return txs, nil
}

func GetTxBlockHeader(ctx context.Context, hash string) (*bc.BlockHeader, error) {
	const q = `
		SELECT header
		FROM blocks b
		JOIN blocks_txs bt ON b.block_hash = bt.block_hash
		WHERE bt.tx_hash=$1
	`
	b := new(bc.BlockHeader)
	err := pg.FromContext(ctx).QueryRow(ctx, q, hash).Scan(b)
	if err == sql.ErrNoRows {
		return nil, nil // tx "not being in a block" is not an error
	}
	return b, errors.Wrap(err, "select query")
}

// insertTx inserts tx into txs. It returns true if the insert query inserted the
// transaction. It returns false if the transaction already existed and the query
// had no effect.
func insertTx(ctx context.Context, tx *bc.Tx) (bool, error) {
	const q = `INSERT INTO txs (tx_hash, data) VALUES($1, $2) ON CONFLICT DO NOTHING`
	res, err := pg.FromContext(ctx).Exec(ctx, q, tx.Hash, tx)
	if err != nil {
		return false, errors.Wrap(err, "insert query")
	}

	affected, err := res.RowsAffected()
	if err != nil {
		return false, errors.Wrap(err, "insert query rows affected")
	}
	return affected > 0, nil
}

func insertBlock(ctx context.Context, block *bc.Block) ([]bc.Hash, error) {
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	const q = `
		INSERT INTO blocks (block_hash, height, data, header)
		VALUES ($1, $2, $3, $4)
	`
	_, err := pg.FromContext(ctx).Exec(ctx, q, block.Hash(), block.Height, block, &block.BlockHeader)
	if err != nil {
		return nil, errors.Wrap(err, "insert query")
	}

	newHashes, err := insertBlockTxs(ctx, block)
	return newHashes, errors.Wrap(err, "inserting txs")
}

func insertBlockTxs(ctx context.Context, block *bc.Block) ([]bc.Hash, error) {
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	var (
		hashInBlock []string // all txs in block
		blockPos    []int32  // position of txs in block
		hashHist    []string // historical txs not already stored
		data        [][]byte // parallel with hashHist
	)
	for i, tx := range block.Transactions {
		blockPos = append(blockPos, int32(i))
		hashInBlock = append(hashInBlock, tx.Hash.String())
		if !tx.Stored {
			var buf bytes.Buffer
			_, err := tx.WriteTo(&buf)
			if err != nil {
				return nil, errors.Wrap(err, "serializing tx")
			}
			data = append(data, buf.Bytes())
			hashHist = append(hashHist, tx.Hash.String())
		}
	}

	const txQ = `
		WITH t AS (SELECT unnest($1::text[]) tx_hash, unnest($2::bytea[]) dat)
		INSERT INTO txs (tx_hash, data)
		SELECT tx_hash, dat FROM t
		WHERE t.tx_hash NOT IN (SELECT tx_hash FROM txs)
		RETURNING tx_hash;
	`
	var newHashes []bc.Hash
	rows, err := pg.FromContext(ctx).Query(ctx, txQ, pg.Strings(hashHist), pg.Byteas(data))
	if err != nil {
		return nil, errors.Wrap(err, "insert txs")
	}
	for rows.Next() {
		var hash bc.Hash
		err := rows.Scan(&hash)
		if err != nil {
			return nil, errors.Wrap(err, "rows scan")
		}
		newHashes = append(newHashes, hash)
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows err check")
	}

	const blockTxQ = `
		INSERT INTO blocks_txs (tx_hash, block_pos, block_hash, block_height)
		SELECT unnest($1::text[]), unnest($2::int[]), $3, $4;
	`
	_, err = pg.FromContext(ctx).Exec(
		ctx,
		blockTxQ,
		pg.Strings(hashInBlock),
		pg.Int32s(blockPos),
		block.Hash(),
		block.Height,
	)
	return nil, errors.Wrap(err, "insert block txs")
}

// ListBlocks returns a list of the most recent blocks,
// potentially offset by a previous query's results.
func ListBlocks(ctx context.Context, prev string, limit int) ([]*bc.Block, error) {
	const q = `
		SELECT data FROM blocks WHERE ($1='' OR height<$1::bigint)
		ORDER BY height DESC LIMIT $2
	`
	rows, err := pg.FromContext(ctx).Query(ctx, q, prev, limit)
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	defer rows.Close()
	var blocks []*bc.Block
	for rows.Next() {
		var block bc.Block
		err := rows.Scan(&block)
		if err != nil {
			return nil, errors.Wrap(err, "row scan")
		}
		blocks = append(blocks, &block)
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows loop")
	}
	return blocks, nil
}

// GetBlock fetches a block by its hash
func GetBlock(ctx context.Context, hash string) (*bc.Block, error) {
	const q = `SELECT data FROM blocks WHERE block_hash=$1`
	block := new(bc.Block)
	err := pg.FromContext(ctx).QueryRow(ctx, q, hash).Scan(block)
	if err == sql.ErrNoRows {
		err = pg.ErrUserInputNotFound
	}
	return block, errors.WithDetailf(err, "block hash=%v", hash)
}

func removeBlockSpentOutputs(ctx context.Context, delta []*state.Output) error {
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	var (
		txHashes []string
		ids      []uint32
	)
	for _, out := range delta {
		if !out.Spent {
			continue
		}
		txHashes = append(txHashes, out.Outpoint.Hash.String())
		ids = append(ids, out.Outpoint.Index)
	}

	dbtx, ctx, err := pg.Begin(ctx)
	if err != nil {
		return errors.Wrap(err, "begin db transaction for deleting utxos")
	}
	defer dbtx.Rollback(ctx)

	db := pg.FromContext(ctx)

	// account_utxos are deleted by a foreign key constraint
	_, err = db.Exec(ctx, `LOCK TABLE account_utxos IN EXCLUSIVE MODE`)
	if err != nil {
		return errors.Wrap(err, "acquire lock for deleting utxos")
	}

	const q = `
		DELETE FROM utxos
		WHERE (tx_hash, index) IN (SELECT unnest($1::text[]), unnest($2::integer[]))
	`
	_, err = db.Exec(ctx, q, pg.Strings(txHashes), pg.Uint32s(ids))
	if err != nil {
		return errors.Wrap(err, "delete query")
	}

	return errors.Wrap(dbtx.Commit(ctx), "commit transaction for deleting utxos")
}

// insertBlockOutputs updates utxos to mark
// unconfirmed records as confirmed and to insert new
// records as necessary, one for each unspent item
// in delta.
//
// It returns a new list containing all spent items
// from delta, plus all newly-inserted unspent outputs
// from delta, omitting the updated items.
func insertBlockOutputs(ctx context.Context, delta []*state.Output) error {
	defer metrics.RecordElapsed(time.Now())
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	db := pg.FromContext(ctx)

	var outs utxoSet
	for _, out := range delta {
		if out.Spent {
			continue
		}
		addToUTXOSet(&outs, &Output{Output: *out})
	}

	// Insert the ones not upgraded above.
	const insertQ1 = `
		WITH new_utxos AS (
			SELECT
				unnest($1::text[]) AS tx_hash,
				unnest($2::bigint[]) AS index,
				unnest($3::text[]),
				unnest($4::bigint[]),
				unnest($5::bytea[]),
				unnest($6::bytea[]),
				unnest($7::bytea[])
		)
		INSERT INTO utxos (
			tx_hash, index, asset_id, amount,
			script, contract_hash, metadata
		)
		SELECT * FROM new_utxos n WHERE NOT EXISTS
			(SELECT 1 FROM utxos u WHERE (n.tx_hash, n.index) = (u.tx_hash, u.index))
	`

	_, err := db.Exec(ctx, insertQ1,
		outs.txHash,
		outs.index,
		outs.assetID,
		outs.amount,
		outs.script,
		outs.contractHash,
		outs.metadata,
	)
	if err != nil {
		return errors.Wrap(err, "insert into utxos")
	}

	const insertQ2 = `
		INSERT INTO blocks_utxos (tx_hash, index)
		    SELECT unnest($1::text[]), unnest($2::bigint[])
	`
	_, err = db.Exec(ctx, insertQ2, outs.txHash, outs.index)
	return errors.Wrap(err, "insert into blocks_utxos")
}

// CountBlockTxs returns the total number of confirmed transactions.
// TODO: Instead running a count query, we should increment a value each time a
// new block lands.
func CountBlockTxs(ctx context.Context) (uint64, error) {
	const q = `SELECT count(tx_hash) FROM blocks_txs`
	var res uint64
	err := pg.FromContext(ctx).QueryRow(ctx, q).Scan(&res)
	return res, errors.Wrap(err)
}
<commit_msg>api/txdb: fix insertBlockTxs to return newHashes<commit_after>package txdb

import (
	"bytes"
	"database/sql"
	"sort"
	"time"

	"golang.org/x/net/context"

	"chain/database/pg"
	"chain/errors"
	"chain/fedchain/bc"
	"chain/fedchain/state"
	"chain/metrics"
	"chain/net/trace/span"
	"chain/strings"
)

func poolTxs(ctx context.Context) ([]*bc.Tx, error) {
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	const q = `SELECT tx_hash, data FROM pool_txs ORDER BY sort_id`
	rows, err := pg.FromContext(ctx).Query(ctx, q)
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	defer rows.Close()

	var txs []*bc.Tx
	for rows.Next() {
		var hash bc.Hash
		var data bc.TxData
		err := rows.Scan(&hash, &data)
		if err != nil {
			return nil, errors.Wrap(err, "row scan")
		}
		txs = append(txs, &bc.Tx{TxData: data, Hash: hash, Stored: true})
	}

	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "end row scan loop")
	}

	txs = topSort(ctx, txs)
	return txs, nil
}

// GetTxs looks up transactions by their hashes
// in the block chain and in the pool.
func GetTxs(ctx context.Context, hashes ...bc.Hash) (map[bc.Hash]*bc.Tx, error) {
	hashStrings := make([]string, 0, len(hashes))
	for _, h := range hashes {
		hashStrings = append(hashStrings, h.String())
	}
	sort.Strings(hashStrings)
	hashStrings = strings.Uniq(hashStrings)
	const q = `SELECT tx_hash, data FROM txs WHERE tx_hash=ANY($1)`
	rows, err := pg.FromContext(ctx).Query(ctx, q, pg.Strings(hashStrings))
	if err != nil {
		return nil, errors.Wrap(err, "get txs query")
	}
	defer rows.Close()

	txs := make(map[bc.Hash]*bc.Tx, len(hashes))
	for rows.Next() {
		var hash bc.Hash
		var data bc.TxData
		err = rows.Scan(&hash, &data)
		if err != nil {
			return nil, errors.Wrap(err, "rows scan")
		}
		txs[hash] = &bc.Tx{TxData: data, Hash: hash, Stored: true}
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows end")
	}
	if len(txs) < len(hashStrings) {
		return nil, errors.Wrap(pg.ErrUserInputNotFound, "missing tx")
	}
	return txs, nil
}

func GetTxBlockHeader(ctx context.Context, hash string) (*bc.BlockHeader, error) {
	const q = `
		SELECT header
		FROM blocks b
		JOIN blocks_txs bt ON b.block_hash = bt.block_hash
		WHERE bt.tx_hash=$1
	`
	b := new(bc.BlockHeader)
	err := pg.FromContext(ctx).QueryRow(ctx, q, hash).Scan(b)
	if err == sql.ErrNoRows {
		return nil, nil // tx "not being in a block" is not an error
	}
	return b, errors.Wrap(err, "select query")
}

// insertTx inserts tx into txs. It returns true if the insert query inserted the
// transaction. It returns false if the transaction already existed and the query
// had no effect.
func insertTx(ctx context.Context, tx *bc.Tx) (bool, error) {
	const q = `INSERT INTO txs (tx_hash, data) VALUES($1, $2) ON CONFLICT DO NOTHING`
	res, err := pg.FromContext(ctx).Exec(ctx, q, tx.Hash, tx)
	if err != nil {
		return false, errors.Wrap(err, "insert query")
	}

	affected, err := res.RowsAffected()
	if err != nil {
		return false, errors.Wrap(err, "insert query rows affected")
	}
	return affected > 0, nil
}

func insertBlock(ctx context.Context, block *bc.Block) ([]bc.Hash, error) {
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	const q = `
		INSERT INTO blocks (block_hash, height, data, header)
		VALUES ($1, $2, $3, $4)
	`
	_, err := pg.FromContext(ctx).Exec(ctx, q, block.Hash(), block.Height, block, &block.BlockHeader)
	if err != nil {
		return nil, errors.Wrap(err, "insert query")
	}

	newHashes, err := insertBlockTxs(ctx, block)
	return newHashes, errors.Wrap(err, "inserting txs")
}

func insertBlockTxs(ctx context.Context, block *bc.Block) ([]bc.Hash, error) {
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	var (
		hashInBlock []string // all txs in block
		blockPos    []int32  // position of txs in block
		hashHist    []string // historical txs not already stored
		data        [][]byte // parallel with hashHist
	)
	for i, tx := range block.Transactions {
		blockPos = append(blockPos, int32(i))
		hashInBlock = append(hashInBlock, tx.Hash.String())
		if !tx.Stored {
			var buf bytes.Buffer
			_, err := tx.WriteTo(&buf)
			if err != nil {
				return nil, errors.Wrap(err, "serializing tx")
			}
			data = append(data, buf.Bytes())
			hashHist = append(hashHist, tx.Hash.String())
		}
	}

	const txQ = `
		WITH t AS (SELECT unnest($1::text[]) tx_hash, unnest($2::bytea[]) dat)
		INSERT INTO txs (tx_hash, data)
		SELECT tx_hash, dat FROM t
		WHERE t.tx_hash NOT IN (SELECT tx_hash FROM txs)
		RETURNING tx_hash;
	`
	var newHashes []bc.Hash
	rows, err := pg.FromContext(ctx).Query(ctx, txQ, pg.Strings(hashHist), pg.Byteas(data))
	if err != nil {
		return nil, errors.Wrap(err, "insert txs")
	}
	for rows.Next() {
		var hash bc.Hash
		err := rows.Scan(&hash)
		if err != nil {
			return nil, errors.Wrap(err, "rows scan")
		}
		newHashes = append(newHashes, hash)
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows err check")
	}

	const blockTxQ = `
		INSERT INTO blocks_txs (tx_hash, block_pos, block_hash, block_height)
		SELECT unnest($1::text[]), unnest($2::int[]), $3, $4;
	`
	_, err = pg.FromContext(ctx).Exec(
		ctx,
		blockTxQ,
		pg.Strings(hashInBlock),
		pg.Int32s(blockPos),
		block.Hash(),
		block.Height,
	)
	if err != nil {
		return nil, errors.Wrap(err, "insert block txs")
	}
	return newHashes, nil
}

// ListBlocks returns a list of the most recent blocks,
// potentially offset by a previous query's results.
func ListBlocks(ctx context.Context, prev string, limit int) ([]*bc.Block, error) {
	const q = `
		SELECT data FROM blocks WHERE ($1='' OR height<$1::bigint)
		ORDER BY height DESC LIMIT $2
	`
	rows, err := pg.FromContext(ctx).Query(ctx, q, prev, limit)
	if err != nil {
		return nil, errors.Wrap(err, "select query")
	}
	defer rows.Close()
	var blocks []*bc.Block
	for rows.Next() {
		var block bc.Block
		err := rows.Scan(&block)
		if err != nil {
			return nil, errors.Wrap(err, "row scan")
		}
		blocks = append(blocks, &block)
	}
	if err := rows.Err(); err != nil {
		return nil, errors.Wrap(err, "rows loop")
	}
	return blocks, nil
}

// GetBlock fetches a block by its hash
func GetBlock(ctx context.Context, hash string) (*bc.Block, error) {
	const q = `SELECT data FROM blocks WHERE block_hash=$1`
	block := new(bc.Block)
	err := pg.FromContext(ctx).QueryRow(ctx, q, hash).Scan(block)
	if err == sql.ErrNoRows {
		err = pg.ErrUserInputNotFound
	}
	return block, errors.WithDetailf(err, "block hash=%v", hash)
}

func removeBlockSpentOutputs(ctx context.Context, delta []*state.Output) error {
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	var (
		txHashes []string
		ids      []uint32
	)
	for _, out := range delta {
		if !out.Spent {
			continue
		}
		txHashes = append(txHashes, out.Outpoint.Hash.String())
		ids = append(ids, out.Outpoint.Index)
	}

	dbtx, ctx, err := pg.Begin(ctx)
	if err != nil {
		return errors.Wrap(err, "begin db transaction for deleting utxos")
	}
	defer dbtx.Rollback(ctx)

	db := pg.FromContext(ctx)

	// account_utxos are deleted by a foreign key constraint
	_, err = db.Exec(ctx, `LOCK TABLE account_utxos IN EXCLUSIVE MODE`)
	if err != nil {
		return errors.Wrap(err, "acquire lock for deleting utxos")
	}

	const q = `
		DELETE FROM utxos
		WHERE (tx_hash, index) IN (SELECT unnest($1::text[]), unnest($2::integer[]))
	`
	_, err = db.Exec(ctx, q, pg.Strings(txHashes), pg.Uint32s(ids))
	if err != nil {
		return errors.Wrap(err, "delete query")
	}

	return errors.Wrap(dbtx.Commit(ctx), "commit transaction for deleting utxos")
}

// insertBlockOutputs updates utxos to mark
// unconfirmed records as confirmed and to insert new
// records as necessary, one for each unspent item
// in delta.
//
// It returns a new list containing all spent items
// from delta, plus all newly-inserted unspent outputs
// from delta, omitting the updated items.
func insertBlockOutputs(ctx context.Context, delta []*state.Output) error {
	defer metrics.RecordElapsed(time.Now())
	ctx = span.NewContext(ctx)
	defer span.Finish(ctx)

	db := pg.FromContext(ctx)

	var outs utxoSet
	for _, out := range delta {
		if out.Spent {
			continue
		}
		addToUTXOSet(&outs, &Output{Output: *out})
	}

	// Insert the ones not upgraded above.
	const insertQ1 = `
		WITH new_utxos AS (
			SELECT
				unnest($1::text[]) AS tx_hash,
				unnest($2::bigint[]) AS index,
				unnest($3::text[]),
				unnest($4::bigint[]),
				unnest($5::bytea[]),
				unnest($6::bytea[]),
				unnest($7::bytea[])
		)
		INSERT INTO utxos (
			tx_hash, index, asset_id, amount,
			script, contract_hash, metadata
		)
		SELECT * FROM new_utxos n WHERE NOT EXISTS
			(SELECT 1 FROM utxos u WHERE (n.tx_hash, n.index) = (u.tx_hash, u.index))
	`

	_, err := db.Exec(ctx, insertQ1,
		outs.txHash,
		outs.index,
		outs.assetID,
		outs.amount,
		outs.script,
		outs.contractHash,
		outs.metadata,
	)
	if err != nil {
		return errors.Wrap(err, "insert into utxos")
	}

	const insertQ2 = `
		INSERT INTO blocks_utxos (tx_hash, index)
		    SELECT unnest($1::text[]), unnest($2::bigint[])
	`
	_, err = db.Exec(ctx, insertQ2, outs.txHash, outs.index)
	return errors.Wrap(err, "insert into blocks_utxos")
}

// CountBlockTxs returns the total number of confirmed transactions.
// TODO: Instead running a count query, we should increment a value each time a
// new block lands.
func CountBlockTxs(ctx context.Context) (uint64, error) {
	const q = `SELECT count(tx_hash) FROM blocks_txs`
	var res uint64
	err := pg.FromContext(ctx).QueryRow(ctx, q).Scan(&res)
	return res, errors.Wrap(err)
}
<|endoftext|>


<commit_before>package somaproto

type PropertyRequest struct {
	PropertyType string               `json:"propertytype,omitempty"`
	Custom       *TreePropertyCustom  `json:"custom,omitempty"`
	System       *TreePropertySystem  `json:"system,omitempty"`
	Service      *TreePropertyService `json:"service,omitempty"`
	Native       *TreePropertyNative  `json:"native,omitempty"`
	Filter       *PropertyFilter      `json:"filter,omitempty"`
}

type PropertyResult struct {
	Code    uint16                `json:"code,omitempty"`
	Status  string                `json:"status,omitempty"`
	Text    []string              `json:"text,omitempty"`
	Custom  []TreePropertyCustom  `json:"custom,omitempty"`
	System  []TreePropertySystem  `json:"system,omitempty"`
	Service []TreePropertyService `json:"service,omitempty"`
	Native  []TreePropertyNative  `json:"native,omitempty"`
	JobId   string                `json:"jobid,omitempty"`
}

type PropertyFilter struct {
	Property   string `json:"property,omitempty"`
	Type       string `json:"type,omitempty"`
	Repository string `json:"repository,omitempty"`
}

//
func (p *PropertyResult) ErrorMark(err error, imp bool, found bool,
	length int, jobid string) bool {
	if p.markError(err) {
		return true
	}
	if p.markImplemented(imp) {
		return true
	}
	if p.markFound(found, length) {
		return true
	}
	if p.hasJobId(jobid) {
		return p.markAccepted()
	}
	return p.markOk()
}

func (p *PropertyResult) markError(err error) bool {
	if err != nil {
		p.Code = 500
		p.Status = "ERROR"
		p.Text = []string{err.Error()}
		return true
	}
	return false
}

func (p *PropertyResult) markImplemented(f bool) bool {
	if f {
		p.Code = 501
		p.Status = "NOT IMPLEMENTED"
		return true
	}
	return false
}

func (p *PropertyResult) markFound(f bool, i int) bool {
	if f || i == 0 {
		p.Code = 404
		p.Status = "NOT FOUND"
		return true
	}
	return false
}

func (p *PropertyResult) markOk() bool {
	p.Code = 200
	p.Status = "OK"
	return false
}

func (p *PropertyResult) hasJobId(s string) bool {
	if s != "" {
		p.JobId = s
		return true
	}
	return false
}

func (p *PropertyResult) markAccepted() bool {
	p.Code = 202
	p.Status = "ACCEPTED"
	return false
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Update PropertyFilter<commit_after>package somaproto

type PropertyRequest struct {
	PropertyType string               `json:"propertytype,omitempty"`
	Custom       *TreePropertyCustom  `json:"custom,omitempty"`
	System       *TreePropertySystem  `json:"system,omitempty"`
	Service      *TreePropertyService `json:"service,omitempty"`
	Native       *TreePropertyNative  `json:"native,omitempty"`
	Filter       *PropertyFilter      `json:"filter,omitempty"`
}

type PropertyResult struct {
	Code    uint16                `json:"code,omitempty"`
	Status  string                `json:"status,omitempty"`
	Text    []string              `json:"text,omitempty"`
	Custom  []TreePropertyCustom  `json:"custom,omitempty"`
	System  []TreePropertySystem  `json:"system,omitempty"`
	Service []TreePropertyService `json:"service,omitempty"`
	Native  []TreePropertyNative  `json:"native,omitempty"`
	JobId   string                `json:"jobid,omitempty"`
}

type PropertyFilter struct {
	Name       string `json:"name,omitempty"`
	Type       string `json:"type,omitempty"`
	Repository string `json:"repository,omitempty"`
}

//
func (p *PropertyResult) ErrorMark(err error, imp bool, found bool,
	length int, jobid string) bool {
	if p.markError(err) {
		return true
	}
	if p.markImplemented(imp) {
		return true
	}
	if p.markFound(found, length) {
		return true
	}
	if p.hasJobId(jobid) {
		return p.markAccepted()
	}
	return p.markOk()
}

func (p *PropertyResult) markError(err error) bool {
	if err != nil {
		p.Code = 500
		p.Status = "ERROR"
		p.Text = []string{err.Error()}
		return true
	}
	return false
}

func (p *PropertyResult) markImplemented(f bool) bool {
	if f {
		p.Code = 501
		p.Status = "NOT IMPLEMENTED"
		return true
	}
	return false
}

func (p *PropertyResult) markFound(f bool, i int) bool {
	if f || i == 0 {
		p.Code = 404
		p.Status = "NOT FOUND"
		return true
	}
	return false
}

func (p *PropertyResult) markOk() bool {
	p.Code = 200
	p.Status = "OK"
	return false
}

func (p *PropertyResult) hasJobId(s string) bool {
	if s != "" {
		p.JobId = s
		return true
	}
	return false
}

func (p *PropertyResult) markAccepted() bool {
	p.Code = 202
	p.Status = "ACCEPTED"
	return false
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>//
package main

/*
Packages must be imported:
    "core/common/page"
    "core/spider"
Pckages may be imported:
    "core/pipeline": scawler result persistent;
    "github.com/PuerkitoBio/goquery": html dom parser.
*/
import (
	"fmt"

	"github.com/PuerkitoBio/goquery"
	"github.com/hu17889/go_spider/core/common/page"
	"github.com/hu17889/go_spider/core/pipeline"
	"github.com/hu17889/go_spider/core/spider"
)

type MyPageProcesser struct {
}

func NewMyPageProcesser() *MyPageProcesser {
	return &MyPageProcesser{}
}

// Parse html dom here and record the parse result that we want to Page.
// Package goquery (http://godoc.org/github.com/PuerkitoBio/goquery) is used to parse html.
func (this *MyPageProcesser) Process(p *page.Page) {
	if !p.IsSucc() {
		println(p.Errormsg())
		return
	}

	query := p.GetHtmlParser()

	query.Find(`div[class="wx-rb bg-blue wx-rb_v1 _item"]`).Each(func(i int, s *goquery.Selection) {
		name := s.Find("div.txt-box > h3").Text()
		href, _ := s.Attr("href")

		fmt.Printf("WeName:%v link:http://http://weixin.sogou.com%v \r\n", name, href)
		// the entity we want to save by Pipeline
		p.AddField("name", name)
		p.AddField("href", href)
	})

	next_page_href, _ := query.Find("#sogou_next").Attr("href")
	if next_page_href == "" {
		p.SetSkip(true)
	} else {
		p.AddTargetRequestWithHeaderFile("http://weixin.sogou.com/weixin"+next_page_href, "html", "weixin.sogou.com.json")
	}

}

func (this *MyPageProcesser) Finish() {
    fmt.Printf("TODO:before end spider \r\n")
}

func main() {
	// Spider input:
	//  PageProcesser ;
	//  Task name used in Pipeline for record;
	req_url := "http://weixin.sogou.com/weixin?query=%E4%BA%91%E6%B5%AE&type=1&page=1&ie=utf8"
	spider.NewSpider(NewMyPageProcesser(), "TaskName").
		AddUrlWithHeaderFile(req_url, "html", "weixin.sogou.com.json"). // Start url, html is the responce type ("html" or "json" or "jsonp" or "text")
		AddPipeline(pipeline.NewPipelineConsole()).                     // Print result on screen
		SetThreadnum(3).                                                // Crawl request by three Coroutines
		Run()
}
<commit_msg>corrected<commit_after>//
package main

/*
Packages must be imported:
    "core/common/page"
    "core/spider"
Pckages may be imported:
    "core/pipeline": scawler result persistent;
    "github.com/PuerkitoBio/goquery": html dom parser.
*/
import (
	"fmt"

	"github.com/PuerkitoBio/goquery"
	"github.com/hu17889/go_spider/core/common/page"
	"github.com/hu17889/go_spider/core/pipeline"
	"github.com/hu17889/go_spider/core/spider"
)

type MyPageProcesser struct {
}

func NewMyPageProcesser() *MyPageProcesser {
	return &MyPageProcesser{}
}

// Parse html dom here and record the parse result that we want to Page.
// Package goquery (http://godoc.org/github.com/PuerkitoBio/goquery) is used to parse html.
func (this *MyPageProcesser) Process(p *page.Page) {
	if !p.IsSucc() {
		println(p.Errormsg())
		return
	}

	query := p.GetHtmlParser()

	query.Find(`div[class="wx-rb bg-blue wx-rb_v1 _item"]`).Each(func(i int, s *goquery.Selection) {
		name := s.Find("div.txt-box > h3").Text()
		href, _ := s.Attr("href")

		fmt.Printf("WeName:%v link:http://http://weixin.sogou.com%v \r\n", name, href)
		// the entity we want to save by Pipeline
		p.AddField("name", name)
		p.AddField("href", href)
	})

	next_page_href, _ := query.Find("#sogou_next").Attr("href")
	if next_page_href == "" {
		p.SetSkip(true)
	} else {
		p.AddTargetRequestWithHeaderFile("http://weixin.sogou.com/weixin"+next_page_href, "html", "weixin.sogou.com.json")
	}

}

func (this *NewMyPageProcesser) Finish() {
    fmt.Printf("TODO:before end spider \r\n")
}

func main() {
	// Spider input:
	//  PageProcesser ;
	//  Task name used in Pipeline for record;
	req_url := "http://weixin.sogou.com/weixin?query=%E4%BA%91%E6%B5%AE&type=1&page=1&ie=utf8"
	spider.NewSpider(NewMyPageProcesser(), "TaskName").
		AddUrlWithHeaderFile(req_url, "html", "weixin.sogou.com.json"). // Start url, html is the responce type ("html" or "json" or "jsonp" or "text")
		AddPipeline(pipeline.NewPipelineConsole()).                     // Print result on screen
		SetThreadnum(3).                                                // Crawl request by three Coroutines
		Run()
}
<|endoftext|>


<commit_before>package apig

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"text/template"

	"github.com/gedex/inflector"
	"github.com/serenize/snaker"
	"github.com/wantedly/apig/util"
)

const templateDir = "_templates"

var funcMap = template.FuncMap{
	"apibDefaultValue": apibDefaultValue,
	"apibType":         apibType,
	"pluralize":        inflector.Pluralize,
	"requestParams":    requestParams,
	"tolower":          strings.ToLower,
	"toSnakeCase":      snaker.CamelToSnake,
	"title":            strings.Title,
}

var managedFields = []string{
	"ID",
	"CreatedAt",
	"UpdatedAt",
}

func apibDefaultValue(field *Field) string {
	switch field.Type {
	case "bool":
		return "false"
	case "string":
		return strings.ToUpper(field.Name)
	case "time.Time":
		return "`2000-01-01 00:00:00`"
	case "*time.Time":
		return "`2000-01-01 00:00:00`"
	case "uint":
		return "1"
	}

	return ""
}

func apibType(field *Field) string {
	switch field.Type {
	case "bool":
		return "boolean"
	case "string":
		return "string"
	case "time.Time":
		return "string"
	case "*time.Time":
		return "string"
	case "uint":
		return "number"
	}

	switch field.Association.Type {
	case AssociationBelongsTo:
		return inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "*", "", -1)))
	case AssociationHasMany:
		return fmt.Sprintf("array[%s]", inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "[]", "", -1))))
	case AssociationHasOne:
		return inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "*", "", -1)))
	}

	return ""
}

func requestParams(fields []*Field) []*Field {
	var managed bool

	params := []*Field{}

	for _, field := range fields {
		managed = false

		for _, name := range managedFields {
			if field.Name == name {
				managed = true
			}
		}

		if !managed {
			params = append(params, field)
		}
	}

	return params
}

func generateApibIndex(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "index.apib.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("apib").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "docs", "index.apib")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {

		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateApibModel(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "model.apib.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("apib").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "docs", snaker.CamelToSnake(detail.Model.Name)+".apib")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateController(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "controller.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("controller").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "controllers", snaker.CamelToSnake(detail.Model.Name)+".go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Printf("\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateREADME(models []*Model, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "README.md.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("readme").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, models); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "README.md")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func generateRouter(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "router.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("router").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "router", "router.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func generateDB(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "db.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("db").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "db", "db.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func Generate(outDir, modelDir, targetFile string, all bool) int {
	outModelDir := filepath.Join(outDir, modelDir)
	files, err := ioutil.ReadDir(outModelDir)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	var models Models
	var wg sync.WaitGroup
	modelMap := make(map[string]*Model)
	errCh := make(chan error)
	modelsCh := make(chan []*Model)
	doneCh := make(chan struct{})
	go func() {
		defer close(doneCh)
		for _, file := range files {
			wg.Add(1)
			go func(f os.FileInfo) {
				defer wg.Done()
				if f.IsDir() {
					return
				}
				if !strings.HasSuffix(f.Name(), ".go") {
					return
				}

				modelPath := filepath.Join(outModelDir, f.Name())
				ms, err := parseModel(modelPath)
				if err != nil {
					errCh <- err
				}
				modelsCh <- ms
			}(file)
		}
		wg.Wait()
	}()

	go func() {
		defer close(errCh)
	loop:
		for {
			select {
			case ms := <-modelsCh:
				for _, model := range ms {
					models = append(models, model)
					modelMap[model.Name] = model
				}
			case <-doneCh:
				errCh <- nil
				break loop
			}
		}
	}()

	err = <-errCh
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	sort.Sort(models)

	importPaths, err := parseImport(filepath.Join(outDir, targetFile))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	importDir := formatImportDir(importPaths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	switch {
	case len(importDir) > 1:
		fmt.Fprintln(os.Stderr, "Conflict import path. Please check 'main.go'.")
		return 1
	case len(importDir) == 0:
		fmt.Fprintln(os.Stderr, "Can't refer import path. Please check 'main.go'.")
		return 1
	}

	dirs := strings.SplitN(importDir[0], "/", 3)
	vcs := dirs[0]
	user := dirs[1]
	project := dirs[2]
	errCh = make(chan error)
	go func() {
		defer close(errCh)
		for _, model := range models {
			wg.Add(1)
			go func(m *Model) {
				defer wg.Done()
				// Check association, stdout "model.Fields[0].Association.Type"
				resolveAssociate(m, modelMap, make(map[string]bool))
				d := &Detail{
					Model:     m,
					ImportDir: importDir[0],
					VCS:       vcs,
					User:      user,
					Project:   project,
				}
				if err := generateApibModel(d, outDir); err != nil {
					fmt.Fprintln(os.Stderr, err)
					errCh <- err
				}
				if err := generateController(d, outDir); err != nil {
					fmt.Fprintln(os.Stderr, err)
					errCh <- err
				}
			}(model)
		}
		wg.Wait()
	}()

	err = <-errCh
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	namespace, err := parseNamespace(filepath.Join(outDir, "router", "router.go"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	detail := &Detail{
		Models:    models,
		ImportDir: importDir[0],
		VCS:       vcs,
		User:      user,
		Project:   project,
		Namespace: namespace,
	}
	if all {
		if err := generateSkeleton(detail, outDir); err != nil {
			fmt.Fprintln(os.Stderr, err)
			return 1
		}
	}
	if err := generateApibIndex(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateRouter(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateDB(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateREADME(models, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	fmt.Println("===> Generated...")
	return 0
}
<commit_msg>Resolve associates in series<commit_after>package apig

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"text/template"

	"github.com/gedex/inflector"
	"github.com/serenize/snaker"
	"github.com/wantedly/apig/util"
)

const templateDir = "_templates"

var funcMap = template.FuncMap{
	"apibDefaultValue": apibDefaultValue,
	"apibType":         apibType,
	"pluralize":        inflector.Pluralize,
	"requestParams":    requestParams,
	"tolower":          strings.ToLower,
	"toSnakeCase":      snaker.CamelToSnake,
	"title":            strings.Title,
}

var managedFields = []string{
	"ID",
	"CreatedAt",
	"UpdatedAt",
}

func apibDefaultValue(field *Field) string {
	switch field.Type {
	case "bool":
		return "false"
	case "string":
		return strings.ToUpper(field.Name)
	case "time.Time":
		return "`2000-01-01 00:00:00`"
	case "*time.Time":
		return "`2000-01-01 00:00:00`"
	case "uint":
		return "1"
	}

	return ""
}

func apibType(field *Field) string {
	switch field.Type {
	case "bool":
		return "boolean"
	case "string":
		return "string"
	case "time.Time":
		return "string"
	case "*time.Time":
		return "string"
	case "uint":
		return "number"
	}

	switch field.Association.Type {
	case AssociationBelongsTo:
		return inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "*", "", -1)))
	case AssociationHasMany:
		return fmt.Sprintf("array[%s]", inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "[]", "", -1))))
	case AssociationHasOne:
		return inflector.Pluralize(strings.ToLower(strings.Replace(field.Type, "*", "", -1)))
	}

	return ""
}

func requestParams(fields []*Field) []*Field {
	var managed bool

	params := []*Field{}

	for _, field := range fields {
		managed = false

		for _, name := range managedFields {
			if field.Name == name {
				managed = true
			}
		}

		if !managed {
			params = append(params, field)
		}
	}

	return params
}

func generateApibIndex(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "index.apib.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("apib").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "docs", "index.apib")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {

		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateApibModel(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "model.apib.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("apib").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "docs", snaker.CamelToSnake(detail.Model.Name)+".apib")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateController(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "controller.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("controller").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "controllers", snaker.CamelToSnake(detail.Model.Name)+".go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Printf("\t\x1b[32m%s\x1b[0m %s\n", "create", dstPath)

	return nil
}

func generateREADME(models []*Model, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "README.md.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("readme").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, models); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "README.md")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func generateRouter(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "router.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("router").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "router", "router.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func generateDB(detail *Detail, outDir string) error {
	body, err := Asset(filepath.Join(templateDir, "db.go.tmpl"))

	if err != nil {
		return err
	}

	tmpl, err := template.New("db").Funcs(funcMap).Parse(string(body))

	if err != nil {
		return err
	}

	var buf bytes.Buffer

	if err := tmpl.Execute(&buf, detail); err != nil {
		return err
	}

	dstPath := filepath.Join(outDir, "db", "db.go")

	if !util.FileExists(filepath.Dir(dstPath)) {
		if err := util.Mkdir(filepath.Dir(dstPath)); err != nil {
			return err
		}
	}

	if err := ioutil.WriteFile(dstPath, buf.Bytes(), 0644); err != nil {
		return err
	}

	fmt.Fprintf(os.Stdout, "\t\x1b[32m%s\x1b[0m %s\n", "update", dstPath)

	return nil
}

func Generate(outDir, modelDir, targetFile string, all bool) int {
	outModelDir := filepath.Join(outDir, modelDir)
	files, err := ioutil.ReadDir(outModelDir)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	var models Models
	var wg sync.WaitGroup
	modelMap := make(map[string]*Model)
	errCh := make(chan error)
	modelsCh := make(chan []*Model)
	doneCh := make(chan struct{})
	go func() {
		defer close(doneCh)
		for _, file := range files {
			wg.Add(1)
			go func(f os.FileInfo) {
				defer wg.Done()
				if f.IsDir() {
					return
				}
				if !strings.HasSuffix(f.Name(), ".go") {
					return
				}

				modelPath := filepath.Join(outModelDir, f.Name())
				ms, err := parseModel(modelPath)
				if err != nil {
					errCh <- err
				}
				modelsCh <- ms
			}(file)
		}
		wg.Wait()
	}()

	go func() {
		defer close(errCh)
	loop:
		for {
			select {
			case ms := <-modelsCh:
				for _, model := range ms {
					models = append(models, model)
					modelMap[model.Name] = model
				}
			case <-doneCh:
				errCh <- nil
				break loop
			}
		}
	}()

	err = <-errCh
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	sort.Sort(models)

	importPaths, err := parseImport(filepath.Join(outDir, targetFile))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	importDir := formatImportDir(importPaths)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	switch {
	case len(importDir) > 1:
		fmt.Fprintln(os.Stderr, "Conflict import path. Please check 'main.go'.")
		return 1
	case len(importDir) == 0:
		fmt.Fprintln(os.Stderr, "Can't refer import path. Please check 'main.go'.")
		return 1
	}

	dirs := strings.SplitN(importDir[0], "/", 3)
	vcs := dirs[0]
	user := dirs[1]
	project := dirs[2]
	errCh = make(chan error)

	for _, model := range models {
		// Check association, stdout "model.Fields[0].Association.Type"
		resolveAssociate(model, modelMap, make(map[string]bool))
	}

	go func() {
		defer close(errCh)
		for _, model := range models {
			wg.Add(1)
			go func(m *Model) {
				defer wg.Done()
				d := &Detail{
					Model:     m,
					ImportDir: importDir[0],
					VCS:       vcs,
					User:      user,
					Project:   project,
				}
				if err := generateApibModel(d, outDir); err != nil {
					fmt.Fprintln(os.Stderr, err)
					errCh <- err
				}
				if err := generateController(d, outDir); err != nil {
					fmt.Fprintln(os.Stderr, err)
					errCh <- err
				}
			}(model)
		}
		wg.Wait()
	}()

	err = <-errCh
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	namespace, err := parseNamespace(filepath.Join(outDir, "router", "router.go"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	detail := &Detail{
		Models:    models,
		ImportDir: importDir[0],
		VCS:       vcs,
		User:      user,
		Project:   project,
		Namespace: namespace,
	}
	if all {
		if err := generateSkeleton(detail, outDir); err != nil {
			fmt.Fprintln(os.Stderr, err)
			return 1
		}
	}
	if err := generateApibIndex(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateRouter(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateDB(detail, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	if err := generateREADME(models, outDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	fmt.Println("===> Generated...")
	return 0
}
<|endoftext|>


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

// Package skiplist implements a skip list. Compared with the classical
// version, there are two changes:
//
//	this implementation allows for repeated elements.
//	there is a back pointer, so it's a doubly linked list.
//
// List will be sorted by score:
//
//	in ascending order.
//	with rank(0-based), also in ascending order.
//	"what is the score, how to compare" is defined by the user.
package skiplist

import (
	"fmt"
	"math/rand"
	"time"
)

const (
	// PROPABILITY is the fixed probability.
	PROPABILITY float32 = 0.25

	DefaultLevel = 16
	MaximumLevel = 32
)

// Scorable object can be passed to CompareFunc.
type Scorable interface{}

// CompareFunc can compare two scorable objects, returns
//
//	<0 if l <  r
//	 0 if l == r
//	>0 if l >  r
type CompareFunc func(l, r Scorable) int

// Element is an element of a skip list.
type Element struct {
	// The value stored with this element.
	Value Scorable

	lev  []level
	list *List
}

type level struct {
	next *Element
	prev *Element
	span int
}

// Next returns the next list element or nil.
func (e *Element) Next() *Element {
	if p := e.next(); e.list != nil && p != e.list.root {
		return p
	}
	return nil
}

// Prev returns the previous list element or nil.
func (e *Element) Prev() *Element {
	if p := e.prev(); e.list != nil && p != e.list.root {
		return p
	}
	return nil
}

func (e *Element) next() *Element {
	return e.lev[0].next
}

func (e *Element) prev() *Element {
	return e.lev[0].prev
}

// List represents a skip list.
type List struct {
	maxL int
	rndS rand.Source
	comp CompareFunc
	root *Element
	len  int
}

// NewList creates a new skip list, with DefaultLevel\compare.
func NewList(compare CompareFunc) *List {
	return NewListEx(DefaultLevel, compare)
}

// NewListEx creates a new skip list, with maxLevel\compare.
func NewListEx(maxLevel int, compare CompareFunc) *List {
	if maxLevel < 1 || maxLevel > MaximumLevel {
		panic("maxLevel < 1 or maxLevel > MaximumLevel")
	}
	if compare == nil {
		panic("compare is nil")
	}

	l := &List{
		maxL: maxLevel,
		rndS: rand.NewSource(time.Now().Unix()),
		comp: compare,
		root: &Element{
			lev:  make([]level, maxLevel),
			list: nil,
		},
	}

	for i := 0; i < l.maxL; i++ {
		l.root.lev[i].next = l.root
		l.root.lev[i].prev = l.root
		l.root.lev[i].span = 0
	}

	return l
}

// Len returns the number of elements of list l. The complexity is O(1).
func (l *List) Len() int { return l.len }

// Front returns the first element of list l or nil.
func (l *List) Front() *Element {
	if l.len == 0 {
		return nil
	}
	return l.root.next()
}

// Back returns the last element of list l or nil.
func (l *List) Back() *Element {
	if l.len == 0 {
		return nil
	}
	return l.root.prev()
}

// Get the element at rank, return nil if rank is invalid.
//
//	0 <= valid rank < list.Len()
func (l *List) Get(rank int) *Element {
	if rank < 0 || rank >= l.len {
		return nil
	}

	e, found := l.searchToRank(rank, nil)
	if !found || e == l.root {
		panic("impossible")
	}

	return e
}

// Find the first element equal to score, return nil if not found.
// If there are multiple elements equal to score, you can use the
// "Element" to traverse them.
func (l *List) Find(score Scorable) *Element {
	if score == nil {
		return nil
	}

	e, found := l.searchToScore(score, nil)
	if found && e == l.root {
		panic("impossible")
	}

	if !found {
		return nil
	}
	return e
}

// Rank will calculate current rank of the element, return -1 if not in the list.
func (l *List) Rank(e *Element) int {
	if e.list != l {
		return -1
	}

	path := &searchPath{}
	l.searchPathOf(e, path)

	span := 0
	for _, v := range path.levSpan {
		span += v
	}

	return span - 1
}

// Add an element to the list.
func (l *List) Add(v Scorable) *Element {
	e := &Element{Value: v}
	l.add(e)
	return e
}

func (l *List) add(e *Element) {
	path := &searchPath{}

	ee, found := l.searchToScore(e.Value, path)
	if found && ee == l.root {
		panic("impossible")
	}

	randON := true

	// repeated element
	if found {
		if len(ee.lev) == 1 {
			// only 1 level, insert before.
			path.prev[0] = path.prev[0].prev()
			path.levSpan[0]--
		} else {
			// more than 1 level, force 1 level on newer.
			randON = false
		}
	}

	nlev := 1
	if randON {
		nlev = l.randLevel()
	}

	//fmt.Println(nlev, randON)

	e.lev = make([]level, nlev)

	revspan := 0
	for i := 0; i < nlev; i++ {
		p := path.prev[i]
		n := p.lev[i].next
		p.lev[i].next = e
		e.lev[i].prev = p
		e.lev[i].next = n
		n.lev[i].prev = e

		e.lev[i].span = p.lev[i].span - revspan
		p.lev[i].span = revspan + 1
		revspan += path.levSpan[i]
	}

	for i := nlev; i < l.maxL; i++ {
		path.prev[i].lev[i].span++
	}

	e.list = l
	l.len++
}

func (l *List) randLevel() int {
	const RANDMAX int64 = 65536
	const RANDTHRESHOLD int64 = int64(float32(RANDMAX) * PROPABILITY)
	nlev := 1
	for l.rndS.Int63()%RANDMAX < RANDTHRESHOLD && nlev <= l.maxL {
		nlev++
	}
	return nlev
}

// Remove an element from the list.
func (l *List) Remove(e *Element) {
	if e.list != l {
		return
	}
	l.remove(e)
}

func (l *List) remove(e *Element) {
	path := &searchPath{}
	l.searchPathOf(e, path)

	for i := 0; i < len(e.lev); i++ {
		n := e.lev[i].next
		p := e.lev[i].prev
		p.lev[i].next = n
		n.lev[i].prev = p
		p.lev[i].span += e.lev[i].span - 1
	}

	for i := len(e.lev); i < l.maxL; i++ {
		path.prev[i].lev[i].span--
	}

	e.lev = nil
	e.list = nil
	l.len--
}

// searchPath represents search path of skip list.
type searchPath struct {
	prev    [MaximumLevel]*Element
	levSpan [MaximumLevel]int
}

func (l *List) searchPathOf(e *Element, path *searchPath) {
	path.prev[0] = e
	path.levSpan[0] = 0

	ilev := 0
	for {
		idle, levSpan := true, 0

		for i := ilev + 1; i < len(e.lev); i++ {
			idle = false
			path.prev[i] = e
			path.levSpan[i] = 0
			ilev++
		}

		for e != l.root && (ilev+1) >= len(e.lev) {
			idle = false
			e = e.lev[ilev].prev
			levSpan += e.lev[ilev].span
		}

		if idle {
			break
		}

		path.levSpan[ilev] = levSpan
	}
}

// return
//
//	<0 goto down
//	 0 found
//	>0 goto next
type poscompFunc func(ilev int, p, n *Element) int

func (l *List) searchToPos(poscomp poscompFunc, path *searchPath) (*Element, bool) {
	found := false

	p := l.root

	for i := l.maxL - 1; i >= 0; i-- {
		levSpan := 0

		equal := false
		n := p.lev[i].next
		for n != l.root {
			ret := poscomp(i, p, n)
			if ret < 0 {
				break
			}
			levSpan += p.lev[i].span
			p = n
			n = n.lev[i].next
			if ret == 0 {
				equal = true
				break
			}
		}

		if path != nil {
			path.prev[i] = p
			path.levSpan[i] = levSpan
		}

		if equal {
			found = true
			for i--; path != nil && i >= 0; i-- {
				path.prev[i] = p
				path.levSpan[i] = 0
			}
			break
		}
	}

	return p, found
}

// searchToXXX will find the element that is closest to XXX.
// If the "path" is not nil, it will be filled.

func (l *List) searchToScore(score Scorable, path *searchPath) (*Element, bool) {
	poscomp := func(ilev int, p, n *Element) int {
		return l.comp(score, n.Value)
	}

	return l.searchToPos(poscomp, path)
}

func (l *List) searchToRank(rank int, path *searchPath) (*Element, bool) {
	span := rank + 1
	poscomp := func(ilev int, p, n *Element) int {
		ret := span - p.lev[ilev].span
		if ret >= 0 {
			span = ret
		}
		return ret
	}
	return l.searchToPos(poscomp, path)
}

func (l *List) dump() {
	fmt.Println("TotalLevel:", l.maxL, " ", "Length:", l.len)
	fmt.Println()
	for i := l.maxL - 1; i >= 0; i-- {
		fmt.Println("Level:", i)
		e := l.root

		fmt.Print("  ")
		for {
			fmt.Println("\t", e.lev[i].span)

			e = e.lev[i].next
			if e == l.root {
				break
			}
			fmt.Print(e, " ")
		}
		fmt.Println()
	}
}
<commit_msg>Update skiplist.go<commit_after>// Copyright 2015 someonegg. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package skiplist implements a skip list. Compared with the classical
// version, there are two changes:
//
//	this implementation allows for repeated elements.
//	there is a back pointer, so it's a doubly linked list.
//
// List will be sorted by score:
//
//	in ascending order.
//	with rank(0-based), also in ascending order.
//	"what is the score, how to compare" is defined by the user.
package skiplist

import (
	"fmt"
	"math/rand"
	"time"
)

const (
	// PROPABILITY is the fixed probability.
	PROPABILITY float32 = 0.25

	DefaultLevel = 16
	MaximumLevel = 32
)

// Scorable object can be passed to CompareFunc.
type Scorable interface{}

// CompareFunc can compare two scorable objects, returns
//
//	<0 if l <  r
//	 0 if l == r
//	>0 if l >  r
type CompareFunc func(l, r Scorable) int

// Element is an element of a skip list.
type Element struct {
	// The value stored with this element.
	Value Scorable

	lev  []level
	list *List
}

type level struct {
	next *Element
	prev *Element
	span int
}

// Next returns the next list element or nil.
func (e *Element) Next() *Element {
	if p := e.next(); e.list != nil && p != e.list.root {
		return p
	}
	return nil
}

// Prev returns the previous list element or nil.
func (e *Element) Prev() *Element {
	if p := e.prev(); e.list != nil && p != e.list.root {
		return p
	}
	return nil
}

func (e *Element) next() *Element {
	return e.lev[0].next
}

func (e *Element) prev() *Element {
	return e.lev[0].prev
}

// List represents a skip list.
type List struct {
	maxL int
	rndS rand.Source
	comp CompareFunc
	root *Element
	len  int
}

// NewList creates a new skip list, with DefaultLevel\compare.
func NewList(compare CompareFunc) *List {
	return NewListEx(DefaultLevel, compare)
}

// NewListEx creates a new skip list, with maxLevel\compare.
func NewListEx(maxLevel int, compare CompareFunc) *List {
	if maxLevel < 1 || maxLevel > MaximumLevel {
		panic("maxLevel < 1 or maxLevel > MaximumLevel")
	}
	if compare == nil {
		panic("compare is nil")
	}

	l := &List{
		maxL: maxLevel,
		rndS: rand.NewSource(time.Now().Unix()),
		comp: compare,
		root: &Element{
			lev:  make([]level, maxLevel),
			list: nil,
		},
	}

	for i := 0; i < l.maxL; i++ {
		l.root.lev[i].next = l.root
		l.root.lev[i].prev = l.root
		l.root.lev[i].span = 0
	}

	return l
}

// Len returns the number of elements of list l. The complexity is O(1).
func (l *List) Len() int { return l.len }

// Front returns the first element of list l or nil.
func (l *List) Front() *Element {
	if l.len == 0 {
		return nil
	}
	return l.root.next()
}

// Back returns the last element of list l or nil.
func (l *List) Back() *Element {
	if l.len == 0 {
		return nil
	}
	return l.root.prev()
}

// Get the element at rank, return nil if rank is invalid.
//
//	0 <= valid rank < list.Len()
func (l *List) Get(rank int) *Element {
	if rank < 0 || rank >= l.len {
		return nil
	}

	e, found := l.searchToRank(rank, nil)
	if !found || e == l.root {
		panic("impossible")
	}

	return e
}

// Find the first element equal to score, return nil if not found.
// If there are multiple elements equal to score, you can use the
// "Element" to traverse them.
func (l *List) Find(score Scorable) *Element {
	if score == nil {
		return nil
	}

	e, found := l.searchToScore(score, nil)
	if found && e == l.root {
		panic("impossible")
	}

	if !found {
		return nil
	}
	return e
}

// Rank will calculate current rank of the element, return -1 if not in the list.
func (l *List) Rank(e *Element) int {
	if e.list != l {
		return -1
	}

	path := &searchPath{}
	l.searchPathOf(e, path)

	span := 0
	for _, v := range path.levSpan {
		span += v
	}

	return span - 1
}

// Add an element to the list.
func (l *List) Add(v Scorable) *Element {
	e := &Element{Value: v}
	l.add(e)
	return e
}

func (l *List) add(e *Element) {
	path := &searchPath{}

	ee, found := l.searchToScore(e.Value, path)
	if found && ee == l.root {
		panic("impossible")
	}

	randON := true

	// repeated element
	if found {
		if len(ee.lev) == 1 {
			// only 1 level, insert before.
			path.prev[0] = path.prev[0].prev()
			path.levSpan[0]--
		} else {
			// more than 1 level, force 1 level on newer.
			randON = false
		}
	}

	nlev := 1
	if randON {
		nlev = l.randLevel()
	}

	//fmt.Println(nlev, randON)

	e.lev = make([]level, nlev)

	revspan := 0
	for i := 0; i < nlev; i++ {
		p := path.prev[i]
		n := p.lev[i].next
		p.lev[i].next = e
		e.lev[i].prev = p
		e.lev[i].next = n
		n.lev[i].prev = e

		e.lev[i].span = p.lev[i].span - revspan
		p.lev[i].span = revspan + 1
		revspan += path.levSpan[i]
	}

	for i := nlev; i < l.maxL; i++ {
		path.prev[i].lev[i].span++
	}

	e.list = l
	l.len++
}

func (l *List) randLevel() int {
	const RANDMAX int64 = 65536
	const RANDTHRESHOLD int64 = int64(float32(RANDMAX) * PROPABILITY)
	nlev := 1
	for l.rndS.Int63()%RANDMAX < RANDTHRESHOLD && nlev < l.maxL {
		nlev++
	}
	return nlev
}

// Remove an element from the list.
func (l *List) Remove(e *Element) {
	if e.list != l {
		return
	}
	l.remove(e)
}

func (l *List) remove(e *Element) {
	path := &searchPath{}
	l.searchPathOf(e, path)

	for i := 0; i < len(e.lev); i++ {
		n := e.lev[i].next
		p := e.lev[i].prev
		p.lev[i].next = n
		n.lev[i].prev = p
		p.lev[i].span += e.lev[i].span - 1
	}

	for i := len(e.lev); i < l.maxL; i++ {
		path.prev[i].lev[i].span--
	}

	e.lev = nil
	e.list = nil
	l.len--
}

// searchPath represents search path of skip list.
type searchPath struct {
	prev    [MaximumLevel]*Element
	levSpan [MaximumLevel]int
}

func (l *List) searchPathOf(e *Element, path *searchPath) {
	path.prev[0] = e
	path.levSpan[0] = 0

	ilev := 0
	for {
		idle, levSpan := true, 0

		for i := ilev + 1; i < len(e.lev); i++ {
			idle = false
			path.prev[i] = e
			path.levSpan[i] = 0
			ilev++
		}

		for e != l.root && (ilev+1) >= len(e.lev) {
			idle = false
			e = e.lev[ilev].prev
			levSpan += e.lev[ilev].span
		}

		if idle {
			break
		}

		path.levSpan[ilev] = levSpan
	}
}

// return
//
//	<0 goto down
//	 0 found
//	>0 goto next
type poscompFunc func(ilev int, p, n *Element) int

func (l *List) searchToPos(poscomp poscompFunc, path *searchPath) (*Element, bool) {
	found := false

	p := l.root

	for i := l.maxL - 1; i >= 0; i-- {
		levSpan := 0

		equal := false
		n := p.lev[i].next
		for n != l.root {
			ret := poscomp(i, p, n)
			if ret < 0 {
				break
			}
			levSpan += p.lev[i].span
			p = n
			n = n.lev[i].next
			if ret == 0 {
				equal = true
				break
			}
		}

		if path != nil {
			path.prev[i] = p
			path.levSpan[i] = levSpan
		}

		if equal {
			found = true
			for i--; path != nil && i >= 0; i-- {
				path.prev[i] = p
				path.levSpan[i] = 0
			}
			break
		}
	}

	return p, found
}

// searchToXXX will find the element that is closest to XXX.
// If the "path" is not nil, it will be filled.

func (l *List) searchToScore(score Scorable, path *searchPath) (*Element, bool) {
	poscomp := func(ilev int, p, n *Element) int {
		return l.comp(score, n.Value)
	}

	return l.searchToPos(poscomp, path)
}

func (l *List) searchToRank(rank int, path *searchPath) (*Element, bool) {
	span := rank + 1
	poscomp := func(ilev int, p, n *Element) int {
		ret := span - p.lev[ilev].span
		if ret >= 0 {
			span = ret
		}
		return ret
	}
	return l.searchToPos(poscomp, path)
}

func (l *List) dump() {
	fmt.Println("TotalLevel:", l.maxL, " ", "Length:", l.len)
	fmt.Println()
	for i := l.maxL - 1; i >= 0; i-- {
		fmt.Println("Level:", i)
		e := l.root

		fmt.Print("  ")
		for {
			fmt.Println("\t", e.lev[i].span)

			e = e.lev[i].next
			if e == l.root {
				break
			}
			fmt.Print(e, " ")
		}
		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package main

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

	moocfetcher "github.com/moocfetcher/moocfetcher-appliance/backend/lib"
	"github.com/satori/go.uuid"
)

var copyStatusPath = regexp.MustCompile("^/api/copy-status/([a-zA-Z0-9\\-]+)$")

type CopyHandler struct {
	Jobs map[string]*CopyJob
}

type CopyJob struct {
	ID         string
	courseData moocfetcher.CourseData
	finished   []string
	current    string
}

type CopyJobProgress struct {
	Current string `json:"current,omitempty"`
	Done    int    `json:"done"`
	Total   int    `json:"total"`
}

func (c *CopyJob) Run() {
	// FIXME totally stubbed out implementation
	for len(c.finished) < len(c.courseData.Courses) {
		c.finished = append(c.finished, c.courseData.Courses[len(c.finished)].Slug)
		c.current = c.finished[len(c.finished)-1]

		time.Sleep(5 * time.Second)
	}
}

func (c *CopyJob) Progress() CopyJobProgress {
	return CopyJobProgress{
		Current: c.current,
		Done:    len(c.finished),
		Total:   len(c.courseData.Courses),
	}
}

func NewCopyHandler() *CopyHandler {
	return &CopyHandler{
		Jobs: map[string]*CopyJob{},
	}
}

func (ch *CopyHandler) NewCopyJob(cd moocfetcher.CourseData) *CopyJob {
	id := uuid.NewV4().String()
	job := &CopyJob{
		ID:         id,
		courseData: cd,
	}

	ch.Jobs[id] = job

	return job
}

func (ch *CopyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Get request JSON and parse
	var courseData moocfetcher.CourseData

	defer r.Body.Close()
	err := json.NewDecoder(r.Body).Decode(&courseData)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	job := ch.NewCopyJob(courseData)
	resp := fmt.Sprintf("{ \"id\": \"%s\"}", job.ID)
	w.Write([]byte(resp))
	w.Header().Set("Content-Type", "application/json")
	go job.Run()
}

type CopyStatusHandler struct {
	Jobs map[string]*CopyJob
}

func NewCopyStatusHandler(jobs map[string]*CopyJob) *CopyStatusHandler {
	return &CopyStatusHandler{
		Jobs: jobs,
	}
}

func (csh *CopyStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Get the job ID
	m := copyStatusPath.FindStringSubmatch(r.URL.Path)
	if m == nil {
		fmt.Println("Match not found")
		http.NotFound(w, r)
		return
	}

	id := m[1]
	if job, ok := csh.Jobs[id]; ok {
		progress := job.Progress()
		js, err := json.Marshal(progress)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
		return
	}
	fmt.Printf("Job not found: %s\n", id)
	http.NotFound(w, r)
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "Under Construction", http.StatusNotImplemented)
}

func addCorsHeaders(h http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if origin := r.Header.Get("Origin"); origin != "" {
			w.Header().Set("Access-Control-Allow-Origin", origin)
		}
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		if r.Method == "OPTIONS" {
			return
		}
		h.ServeHTTP(w, r)
	}
}

func main() {
	// TODO Init application
	ch := NewCopyHandler()
	http.Handle("/api/copy", ch)
	http.Handle("/api/copy-status/", NewCopyStatusHandler(ch.Jobs))
	http.Handle("/api/stats", http.HandlerFunc(statsHandler))

	http.ListenAndServe(":8080", addCorsHeaders(http.DefaultServeMux))
}
<commit_msg>Fixing order of operations in copy operation<commit_after>package main

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

	moocfetcher "github.com/moocfetcher/moocfetcher-appliance/backend/lib"
	"github.com/satori/go.uuid"
)

var copyStatusPath = regexp.MustCompile("^/api/copy-status/([a-zA-Z0-9\\-]+)$")

type CopyHandler struct {
	Jobs map[string]*CopyJob
}

type CopyJob struct {
	ID         string
	courseData moocfetcher.CourseData
	finished   []string
	current    string
}

type CopyJobProgress struct {
	Current string `json:"current,omitempty"`
	Done    int    `json:"done"`
	Total   int    `json:"total"`
}

func (c *CopyJob) Run() {
	// FIXME totally stubbed out implementation
	for len(c.finished) < len(c.courseData.Courses) {
		c.current = c.courseData.Courses[len(c.finished)].Slug
		time.Sleep(5 * time.Second)
		c.finished = append(c.finished, c.current)
	}
	c.current = ""

}

func (c *CopyJob) Progress() CopyJobProgress {
	return CopyJobProgress{
		Current: c.current,
		Done:    len(c.finished),
		Total:   len(c.courseData.Courses),
	}
}

func NewCopyHandler() *CopyHandler {
	return &CopyHandler{
		Jobs: map[string]*CopyJob{},
	}
}

func (ch *CopyHandler) NewCopyJob(cd moocfetcher.CourseData) *CopyJob {
	id := uuid.NewV4().String()
	job := &CopyJob{
		ID:         id,
		courseData: cd,
	}

	ch.Jobs[id] = job

	return job
}

func (ch *CopyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Get request JSON and parse
	var courseData moocfetcher.CourseData

	defer r.Body.Close()
	err := json.NewDecoder(r.Body).Decode(&courseData)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	job := ch.NewCopyJob(courseData)
	resp := fmt.Sprintf("{ \"id\": \"%s\"}", job.ID)
	w.Write([]byte(resp))
	w.Header().Set("Content-Type", "application/json")
	go job.Run()
}

type CopyStatusHandler struct {
	Jobs map[string]*CopyJob
}

func NewCopyStatusHandler(jobs map[string]*CopyJob) *CopyStatusHandler {
	return &CopyStatusHandler{
		Jobs: jobs,
	}
}

func (csh *CopyStatusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Get the job ID
	m := copyStatusPath.FindStringSubmatch(r.URL.Path)
	if m == nil {
		fmt.Println("Match not found")
		http.NotFound(w, r)
		return
	}

	id := m[1]
	if job, ok := csh.Jobs[id]; ok {
		progress := job.Progress()
		js, err := json.Marshal(progress)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
		return
	}
	fmt.Printf("Job not found: %s\n", id)
	http.NotFound(w, r)
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "Under Construction", http.StatusNotImplemented)
}

func addCorsHeaders(h http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if origin := r.Header.Get("Origin"); origin != "" {
			w.Header().Set("Access-Control-Allow-Origin", origin)
		}
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		if r.Method == "OPTIONS" {
			return
		}
		h.ServeHTTP(w, r)
	}
}

func main() {
	// TODO Init application
	ch := NewCopyHandler()
	http.Handle("/api/copy", ch)
	http.Handle("/api/copy-status/", NewCopyStatusHandler(ch.Jobs))
	http.Handle("/api/stats", http.HandlerFunc(statsHandler))

	http.ListenAndServe(":8080", addCorsHeaders(http.DefaultServeMux))
}
<|endoftext|>