<commit_before>package baa

import (
	"fmt"
	"sync"
)

const (
	leafKindStatic uint = iota
	leafKindParam
	leafKindWide
)

// Tree provlider router for baa with radix tree
type Tree struct {
	autoHead          bool
	autoTrailingSlash bool
	mu                sync.RWMutex
	groups            []*group
	nodes             [RouteLength]*leaf
	baa               *Baa
	namedNodes        map[string]*Node
}

// Node is struct for named route
type Node struct {
	paramNum int
	pattern  string
	format   string
	root     *Tree
}

// Leaf is a tree node
type leaf struct {
	kind        uint
	pattern     string
	param       string
	handlers    []HandlerFunc
	children    []*leaf
	childrenNum uint
	paramChild  *leaf
	wideChild   *leaf
	parent      *leaf
	root        *Tree
}

// group route
type group struct {
	pattern  string
	handlers []HandlerFunc
}

// NewTree create a router instance
func NewTree(b *Baa) Router {
	t := new(Tree)
	for i := 0; i < len(t.nodes); i++ {
		t.nodes[i] = newLeaf("/", nil, t)
	}
	t.namedNodes = make(map[string]*Node)
	t.groups = make([]*group, 0)
	t.baa = b
	return t
}

// NewNode create a route node
func NewNode(pattern string, root *Tree) *Node {
	return &Node{
		pattern: pattern,
		root:    root,
	}
}

// newLeaf create a tree leaf
func newLeaf(pattern string, handlers []HandlerFunc, root *Tree) *leaf {
	l := new(leaf)
	l.pattern = pattern
	l.handlers = handlers
	l.root = root
	l.kind = leafKindStatic
	l.children = make([]*leaf, 128)
	return l
}

// newGroup create a group router
func newGroup() *group {
	g := new(group)
	g.handlers = make([]HandlerFunc, 0)
	return g
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added. Combo router will not be affected by this value.
func (t *Tree) SetAutoHead(v bool) {
	t.autoHead = v
}

// SetAutoTrailingSlash optional trailing slash.
func (t *Tree) SetAutoTrailingSlash(v bool) {
	t.autoTrailingSlash = v
}

// Match find matched route and returns handlerss
func (t *Tree) Match(method, pattern string, c *Context) []HandlerFunc {
	var i, l int
	var root, nl *leaf
	root = t.nodes[RouterMethods[method]]

	for {
		switch root.kind {
		case leafKindStatic:
			// static route
			l = len(root.pattern)
			if l > len(pattern) {
				return nil
			}
			for i := l - 1; i >= 0; i-- {
				if root.pattern[i] != pattern[i] {
					return nil
				}
			}
			pattern = pattern[l:]
		case leafKindParam:
			// params route
			l = len(pattern)
			if root.childrenNum == 0 {
				i = l
			} else {
				for i = 0; i < l && pattern[i] != '/'; i++ {
				}
			}
			c.SetParam(root.param, pattern[:i])
			pattern = pattern[i:]
		case leafKindWide:
			// wide route
			c.SetParam(root.param, pattern)
			pattern = pattern[:0]
		default:
		}

		if len(pattern) == 0 {
			if root.handlers == nil {
				return nil
			}
			return root.handlers
		}

		// children static route
		if nl = root.children[pattern[0]]; nl != nil {
			root = nl
			continue
		}

		// param route
		if root.paramChild != nil {
			root = root.paramChild
			continue
		}

		// wide route
		if root.wideChild != nil {
			root = root.wideChild
			continue
		}

		break
	}

	return nil
}

// URLFor use named route return format url
func (t *Tree) URLFor(name string, args ...interface{}) string {
	if name == "" {
		return ""
	}
	node := t.namedNodes[name]
	if node == nil || len(node.format) == 0 {
		return ""
	}
	format := make([]byte, len(node.format))
	copy(format, node.format)
	for i := node.paramNum + 1; i <= len(args); i++ {
		format = append(format, "%v"...)
	}
	return fmt.Sprintf(string(format), args...)
}

// Add registers a new handle with the given method, pattern and handlers.
// add check training slash option.
func (t *Tree) Add(method, pattern string, handlers []HandlerFunc) RouteNode {
	if method == "GET" && t.autoHead {
		t.add("HEAD", pattern, handlers)
	}
	if t.autoTrailingSlash && (len(pattern) > 1 || len(t.groups) > 0) {
		if pattern[len(pattern)-1] == '/' {
			t.add(method, pattern[:len(pattern)-1], handlers)
		} else {
			t.add(method, pattern+"/", handlers)
		}
	}
	return t.add(method, pattern, handlers)
}

// GroupAdd add a group route has same prefix and handle chain
func (t *Tree) GroupAdd(pattern string, f func(), handlers []HandlerFunc) {
	g := newGroup()
	g.pattern = pattern
	g.handlers = handlers
	t.groups = append(t.groups, g)

	f()

	t.groups = t.groups[:len(t.groups)-1]
}

// add registers a new request handle with the given method, pattern and handlers.
func (t *Tree) add(method, pattern string, handlers []HandlerFunc) RouteNode {
	if _, ok := RouterMethods[method]; !ok {
		panic("unsupport http method [" + method + "]")
	}

	t.mu.Lock()
	defer t.mu.Unlock()

	// check group set
	if len(t.groups) > 0 {
		var gpattern string
		var ghandlers []HandlerFunc
		for i := range t.groups {
			gpattern += t.groups[i].pattern
			if len(t.groups[i].handlers) > 0 {
				ghandlers = append(ghandlers, t.groups[i].handlers...)
			}
		}
		pattern = gpattern + pattern
		ghandlers = append(ghandlers, handlers...)
		handlers = ghandlers
	}

	// check pattern (for training slash move behind group check)
	if pattern == "" {
		panic("route pattern can not be emtpy!")
	}
	if pattern[0] != '/' {
		panic("route pattern must begin /")
	}

	for i := 0; i < len(handlers); i++ {
		handlers[i] = WrapHandlerFunc(handlers[i])
	}

	root := t.nodes[RouterMethods[method]]
	origPattern := pattern

	// specialy route = /
	if len(pattern) == 1 {
		root.handlers = handlers
		return NewNode(origPattern, t)
	}

	// left trim slash, because root is slash /
	pattern = pattern[1:]

	var radix []byte
	var param []byte
	var i, k int
	var tl *leaf
	for i = 0; i < len(pattern); i++ {
		// wide route
		if pattern[i] == '*' {
			// clear static route
			if len(radix) > 0 {
				root = root.insertChild(newLeaf(string(radix), nil, t))
				radix = radix[:0]
			}
			tl = newLeaf("*", handlers, t)
			tl.kind = leafKindWide
			root.insertChild(tl)
			break
		}

		// param route
		if pattern[i] == ':' {
			// clear static route
			if len(radix) > 0 {
				root = root.insertChild(newLeaf(string(radix), nil, t))
				radix = radix[:0]
			}
			// set param route
			param = param[:0]
			k = 0
			for i = i + 1; i < len(pattern); i++ {
				if pattern[i] == '/' {
					i--
					break
				}
				param = append(param, pattern[i])
				k++
			}
			if k == 0 {
				panic("route pattern param is empty")
			}
			// check last character
			if i == len(pattern) {
				tl = newLeaf(":", handlers, t)
			} else {
				tl = newLeaf(":", nil, t)
			}
			tl.param = string(param[:k])
			tl.kind = leafKindParam
			root = root.insertChild(tl)
			continue
		}
		radix = append(radix, pattern[i])
	}

	// static route
	if len(radix) > 0 {
		tl = newLeaf(string(radix), handlers, t)
		root.insertChild(tl)
	}

	return NewNode(origPattern, t)
}

// insertChild insert child into root route, and returns the child route
func (l *leaf) insertChild(node *leaf) *leaf {
	// wide route
	if node.kind == leafKindWide {
		if l.wideChild != nil {
			panic("Router Tree.insert error: cannot set two wide route with same prefix!")
		}
		l.wideChild = node
		return node
	}

	// param route
	if node.kind == leafKindParam {
		if l.paramChild == nil {
			l.paramChild = node
			return l.paramChild
		}
		if l.paramChild.param != node.param {
			panic("Router Tree.insert error cannot use two param [:" + l.paramChild.param + ", :" + node.param + "] with same prefix!")
		}
		if node.handlers != nil {
			if l.paramChild.handlers != nil {
				panic("Router Tree.insert error: cannot twice set handler for same route")
			}
			l.paramChild.handlers = node.handlers
		}
		return l.paramChild
	}

	// static route
	child := l.children[node.pattern[0]]
	if child == nil {
		// new child
		l.children[node.pattern[0]] = node
		l.childrenNum++
		return node
	}

	pos := child.hasPrefixString(node.pattern)
	pre := node.pattern[:pos]
	if pos == len(child.pattern) {
		// same route
		if pos == len(node.pattern) {
			if node.handlers != nil {
				if child.handlers != nil {
					panic("Router Tree.insert error: cannot twice set handler for same route")
				}
				child.handlers = node.handlers
			}
			return child
		}

		// child is prefix or node
		node.pattern = node.pattern[pos:]
		return child.insertChild(node)
	}

	newChild := newLeaf(child.pattern[pos:], child.handlers, child.root)
	newChild.children = child.children
	newChild.childrenNum = child.childrenNum
	newChild.paramChild = child.paramChild
	newChild.wideChild = child.wideChild

	// node is prefix of child
	if pos == len(node.pattern) {
		child.reset(node.pattern, node.handlers)
		child.children[newChild.pattern[0]] = newChild
		child.childrenNum++
		return child
	}

	// child and node has same prefix
	child.reset(pre, nil)
	child.children[newChild.pattern[0]] = newChild
	child.childrenNum++
	node.pattern = node.pattern[pos:]
	child.children[node.pattern[0]] = node
	child.childrenNum++
	return node
}

// resetPattern reset route pattern and alpha
func (l *leaf) reset(pattern string, handlers []HandlerFunc) {
	l.pattern = pattern
	l.children = make([]*leaf, 128)
	l.childrenNum = 0
	l.paramChild = nil
	l.wideChild = nil
	l.param = ""
	l.handlers = handlers
}

// hasPrefixString returns the same prefix position, if none return 0
func (l *leaf) hasPrefixString(s string) int {
	var i, j int
	j = len(l.pattern)
	if len(s) < j {
		j = len(s)
	}
	for i = 0; i < j && s[i] == l.pattern[i]; i++ {
	}
	return i
}

// String returns full pattern of leaf
func (l *leaf) String() string {
	s := l.pattern
	if l.kind == leafKindParam {
		s += l.param
	}
	if l.parent != nil {
		s = l.parent.String() + s
	}
	return s
}

// Name set name of route
func (n *Node) Name(name string) {
	if name == "" {
		return
	}
	p := 0
	f := make([]byte, 0, len(n.pattern))
	for i := 0; i < len(n.pattern); i++ {
		if n.pattern[i] != ':' {
			f = append(f, n.pattern[i])
			continue
		}
		f = append(f, '%')
		f = append(f, 'v')
		p++
		for i = i + 1; i < len(n.pattern); i++ {
			if n.pattern[i] == '/' {
				i--
				break
			}
		}
	}
	n.format = string(f)
	n.paramNum = p
	n.root.namedNodes[name] = n
}
<commit_msg>fix staitc route not found with same prefix in param route<commit_after>package baa

import (
	"fmt"
	"sync"
)

const (
	leafKindStatic uint = iota
	leafKindParam
	leafKindWide
)

// Tree provlider router for baa with radix tree
type Tree struct {
	autoHead          bool
	autoTrailingSlash bool
	mu                sync.RWMutex
	groups            []*group
	nodes             [RouteLength]*leaf
	baa               *Baa
	namedNodes        map[string]*Node
}

// Node is struct for named route
type Node struct {
	paramNum int
	pattern  string
	format   string
	root     *Tree
}

// Leaf is a tree node
type leaf struct {
	kind        uint
	pattern     string
	param       string
	handlers    []HandlerFunc
	children    []*leaf
	childrenNum uint
	paramChild  *leaf
	wideChild   *leaf
	parent      *leaf
	root        *Tree
}

// group route
type group struct {
	pattern  string
	handlers []HandlerFunc
}

// NewTree create a router instance
func NewTree(b *Baa) Router {
	t := new(Tree)
	for i := 0; i < len(t.nodes); i++ {
		t.nodes[i] = newLeaf("/", nil, t)
	}
	t.namedNodes = make(map[string]*Node)
	t.groups = make([]*group, 0)
	t.baa = b
	return t
}

// NewNode create a route node
func NewNode(pattern string, root *Tree) *Node {
	return &Node{
		pattern: pattern,
		root:    root,
	}
}

// newLeaf create a tree leaf
func newLeaf(pattern string, handlers []HandlerFunc, root *Tree) *leaf {
	l := new(leaf)
	l.pattern = pattern
	l.handlers = handlers
	l.root = root
	l.kind = leafKindStatic
	l.children = make([]*leaf, 128)
	return l
}

// newGroup create a group router
func newGroup() *group {
	g := new(group)
	g.handlers = make([]HandlerFunc, 0)
	return g
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added. Combo router will not be affected by this value.
func (t *Tree) SetAutoHead(v bool) {
	t.autoHead = v
}

// SetAutoTrailingSlash optional trailing slash.
func (t *Tree) SetAutoTrailingSlash(v bool) {
	t.autoTrailingSlash = v
}

// Match find matched route and returns handlerss
func (t *Tree) Match(method, pattern string, c *Context) []HandlerFunc {
	var i, l int
	var root, nl *leaf
	root = t.nodes[RouterMethods[method]]
	current := root

	for {
		switch current.kind {
		case leafKindStatic:
			// static route
			l = len(current.pattern)
			if l > len(pattern) {
				break
			}
			i := l - 1
			for ; i >= 0; i-- {
				if current.pattern[i] != pattern[i] {
					break
				}
			}
			if i >= 0 {
				break
			}
			if len(pattern) == l || current.children[pattern[l]] != nil {
				pattern = pattern[l:]
				root = current
			}
		case leafKindParam:
			// params route
			l = len(pattern)
			if current.childrenNum == 0 {
				i = l
			} else {
				for i = 0; i < l && pattern[i] != '/'; i++ {
				}
			}
			c.SetParam(current.param, pattern[:i])
			pattern = pattern[i:]
			root = current
		case leafKindWide:
			// wide route
			c.SetParam(current.param, pattern)
			pattern = pattern[:0]
		default:
		}

		if len(pattern) == 0 {
			if current.handlers == nil {
				return nil
			}
			return current.handlers
		}

		// children static route
		if current == root {
			if nl = root.children[pattern[0]]; nl != nil {
				current = nl
				continue
			}
		}

		// param route
		if root.paramChild != nil {
			current = root.paramChild
			continue
		}

		// wide route
		if root.wideChild != nil {
			current = root.wideChild
			continue
		}

		break
	}

	return nil
}

// URLFor use named route return format url
func (t *Tree) URLFor(name string, args ...interface{}) string {
	if name == "" {
		return ""
	}
	node := t.namedNodes[name]
	if node == nil || len(node.format) == 0 {
		return ""
	}
	format := make([]byte, len(node.format))
	copy(format, node.format)
	for i := node.paramNum + 1; i <= len(args); i++ {
		format = append(format, "%v"...)
	}
	return fmt.Sprintf(string(format), args...)
}

// Add registers a new handle with the given method, pattern and handlers.
// add check training slash option.
func (t *Tree) Add(method, pattern string, handlers []HandlerFunc) RouteNode {
	if method == "GET" && t.autoHead {
		t.add("HEAD", pattern, handlers)
	}
	if t.autoTrailingSlash && (len(pattern) > 1 || len(t.groups) > 0) {
		if pattern[len(pattern)-1] == '/' {
			t.add(method, pattern[:len(pattern)-1], handlers)
		} else {
			t.add(method, pattern+"/", handlers)
		}
	}
	return t.add(method, pattern, handlers)
}

// GroupAdd add a group route has same prefix and handle chain
func (t *Tree) GroupAdd(pattern string, f func(), handlers []HandlerFunc) {
	g := newGroup()
	g.pattern = pattern
	g.handlers = handlers
	t.groups = append(t.groups, g)

	f()

	t.groups = t.groups[:len(t.groups)-1]
}

// add registers a new request handle with the given method, pattern and handlers.
func (t *Tree) add(method, pattern string, handlers []HandlerFunc) RouteNode {
	if _, ok := RouterMethods[method]; !ok {
		panic("unsupport http method [" + method + "]")
	}

	t.mu.Lock()
	defer t.mu.Unlock()

	// check group set
	if len(t.groups) > 0 {
		var gpattern string
		var ghandlers []HandlerFunc
		for i := range t.groups {
			gpattern += t.groups[i].pattern
			if len(t.groups[i].handlers) > 0 {
				ghandlers = append(ghandlers, t.groups[i].handlers...)
			}
		}
		pattern = gpattern + pattern
		ghandlers = append(ghandlers, handlers...)
		handlers = ghandlers
	}

	// check pattern (for training slash move behind group check)
	if pattern == "" {
		panic("route pattern can not be emtpy!")
	}
	if pattern[0] != '/' {
		panic("route pattern must begin /")
	}

	for i := 0; i < len(handlers); i++ {
		handlers[i] = WrapHandlerFunc(handlers[i])
	}

	root := t.nodes[RouterMethods[method]]
	origPattern := pattern

	// specialy route = /
	if len(pattern) == 1 {
		root.handlers = handlers
		return NewNode(origPattern, t)
	}

	// left trim slash, because root is slash /
	pattern = pattern[1:]

	var radix []byte
	var param []byte
	var i, k int
	var tl *leaf
	for i = 0; i < len(pattern); i++ {
		// wide route
		if pattern[i] == '*' {
			// clear static route
			if len(radix) > 0 {
				root = root.insertChild(newLeaf(string(radix), nil, t))
				radix = radix[:0]
			}
			tl = newLeaf("*", handlers, t)
			tl.kind = leafKindWide
			root.insertChild(tl)
			break
		}

		// param route
		if pattern[i] == ':' {
			// clear static route
			if len(radix) > 0 {
				root = root.insertChild(newLeaf(string(radix), nil, t))
				radix = radix[:0]
			}
			// set param route
			param = param[:0]
			k = 0
			for i = i + 1; i < len(pattern); i++ {
				if pattern[i] == '/' {
					i--
					break
				}
				param = append(param, pattern[i])
				k++
			}
			if k == 0 {
				panic("route pattern param is empty")
			}
			// check last character
			if i == len(pattern) {
				tl = newLeaf(":", handlers, t)
			} else {
				tl = newLeaf(":", nil, t)
			}
			tl.param = string(param[:k])
			tl.kind = leafKindParam
			root = root.insertChild(tl)
			continue
		}
		radix = append(radix, pattern[i])
	}

	// static route
	if len(radix) > 0 {
		tl = newLeaf(string(radix), handlers, t)
		root.insertChild(tl)
	}

	return NewNode(origPattern, t)
}

// insertChild insert child into root route, and returns the child route
func (l *leaf) insertChild(node *leaf) *leaf {
	// wide route
	if node.kind == leafKindWide {
		if l.wideChild != nil {
			panic("Router Tree.insert error: cannot set two wide route with same prefix!")
		}
		l.wideChild = node
		return node
	}

	// param route
	if node.kind == leafKindParam {
		if l.paramChild == nil {
			l.paramChild = node
			return l.paramChild
		}
		if l.paramChild.param != node.param {
			panic("Router Tree.insert error cannot use two param [:" + l.paramChild.param + ", :" + node.param + "] with same prefix!")
		}
		if node.handlers != nil {
			if l.paramChild.handlers != nil {
				panic("Router Tree.insert error: cannot twice set handler for same route")
			}
			l.paramChild.handlers = node.handlers
		}
		return l.paramChild
	}

	// static route
	child := l.children[node.pattern[0]]
	if child == nil {
		// new child
		l.children[node.pattern[0]] = node
		l.childrenNum++
		return node
	}

	pos := child.hasPrefixString(node.pattern)
	pre := node.pattern[:pos]
	if pos == len(child.pattern) {
		// same route
		if pos == len(node.pattern) {
			if node.handlers != nil {
				if child.handlers != nil {
					panic("Router Tree.insert error: cannot twice set handler for same route")
				}
				child.handlers = node.handlers
			}
			return child
		}

		// child is prefix or node
		node.pattern = node.pattern[pos:]
		return child.insertChild(node)
	}

	newChild := newLeaf(child.pattern[pos:], child.handlers, child.root)
	newChild.children = child.children
	newChild.childrenNum = child.childrenNum
	newChild.paramChild = child.paramChild
	newChild.wideChild = child.wideChild

	// node is prefix of child
	if pos == len(node.pattern) {
		child.reset(node.pattern, node.handlers)
		child.children[newChild.pattern[0]] = newChild
		child.childrenNum++
		return child
	}

	// child and node has same prefix
	child.reset(pre, nil)
	child.children[newChild.pattern[0]] = newChild
	child.childrenNum++
	node.pattern = node.pattern[pos:]
	child.children[node.pattern[0]] = node
	child.childrenNum++
	return node
}

// resetPattern reset route pattern and alpha
func (l *leaf) reset(pattern string, handlers []HandlerFunc) {
	l.pattern = pattern
	l.children = make([]*leaf, 128)
	l.childrenNum = 0
	l.paramChild = nil
	l.wideChild = nil
	l.param = ""
	l.handlers = handlers
}

// hasPrefixString returns the same prefix position, if none return 0
func (l *leaf) hasPrefixString(s string) int {
	var i, j int
	j = len(l.pattern)
	if len(s) < j {
		j = len(s)
	}
	for i = 0; i < j && s[i] == l.pattern[i]; i++ {
	}
	return i
}

// String returns full pattern of leaf
func (l *leaf) String() string {
	s := l.pattern
	if l.kind == leafKindParam {
		s += l.param
	}
	if l.parent != nil {
		s = l.parent.String() + s
	}
	return s
}

// Name set name of route
func (n *Node) Name(name string) {
	if name == "" {
		return
	}
	p := 0
	f := make([]byte, 0, len(n.pattern))
	for i := 0; i < len(n.pattern); i++ {
		if n.pattern[i] != ':' {
			f = append(f, n.pattern[i])
			continue
		}
		f = append(f, '%')
		f = append(f, 'v')
		p++
		for i = i + 1; i < len(n.pattern); i++ {
			if n.pattern[i] == '/' {
				i--
				break
			}
		}
	}
	n.format = string(f)
	n.paramNum = p
	n.root.namedNodes[name] = n
}
<|endoftext|>


<commit_before>package hush

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/pkg/errors"

	yaml "gopkg.in/yaml.v2"
)

type Tree struct {
	tree map[Path]*Value

	encryptionKey []byte
}

const safePerm = 0600 // rw- --- ---

func LoadTree() (*Tree, error) {
	hushPath, err := hushPath()
	if err != nil {
		return nil, err
	}

	stat, err := os.Stat(hushPath)
	if os.IsNotExist(err) {
		warn("hush file does not exist. assuming an empty one")
		return &Tree{}, nil
	}
	if err != nil {
		return nil, errors.Wrap(err, "can't stat hush file")
	}
	if (stat.Mode() & os.ModePerm) != safePerm {
		warn("hush file has loose permissions. fixing.")
		err := os.Chmod(hushPath, safePerm)
		if err != nil {
			die("couldn't fix permissions on hush file")
		}
	}

	file, err := os.Open(hushPath)
	if err != nil {
		return nil, errors.Wrap(err, "opening hush file")
	}
	hushData, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, errors.Wrap(err, "can't read hush file")
	}

	keys := make(yaml.MapSlice, 0)
	err = yaml.Unmarshal(hushData, &keys)
	if err != nil {
		return nil, errors.Wrap(err, "can't parse hush file")
	}
	tree := newT(keys)
	return tree, nil
}

func newT(items yaml.MapSlice) *Tree {
	t := &Tree{
		tree: make(map[Path]*Value, 3*len(items)),
	}
	newT_(items, []string{}, t)
	return t
}

func newT_(items yaml.MapSlice, crumbs []string, t *Tree) {
	n := len(crumbs)
	for _, item := range items {
		key := item.Key.(string)
		crumbs = append(crumbs, key)

		switch val := item.Value.(type) {
		case string:
			p := NewPath(strings.Join(crumbs, "/"))
			privacy := Private
			if p.IsPublic() {
				privacy = Public
			}
			t.tree[p] = NewEncoded(val, privacy)
		case yaml.MapSlice:
			newT_(val, crumbs, t)
		default:
			panic(fmt.Sprintf("unexpected type: %#v", val))
		}
		crumbs = crumbs[:n] // remove final crumb
	}
}

func (t *Tree) mapSlice() yaml.MapSlice {
	// sort by key
	kvs := make([][]string, 0, len(t.tree))
	for p, val := range t.tree {
		kvs = append(kvs, []string{string(p), val.String()})
	}
	sort.SliceStable(kvs, func(i, j int) bool {
		return kvs[i][0] < kvs[j][0]
	})

	var slice yaml.MapSlice
	for _, kv := range kvs {
		path := strings.Split(kv[0], "\t")
		slice = mapSlice_(slice, path, kv[1])
	}
	return slice
}

func mapSlice_(slice yaml.MapSlice, path []string, value string) yaml.MapSlice {
	if len(path) == 0 {
		panic("path should never have 0 length")
	}
	if len(path) == 1 {
		return append(slice, yaml.MapItem{
			Key:   path[0],
			Value: value,
		})
	}

	var inner yaml.MapSlice
	if len(slice) == 0 {
		slice = append(slice, yaml.MapItem{Key: path[0]})
	} else {
		final := slice[len(slice)-1]
		if final.Key.(string) == path[0] {
			inner = final.Value.(yaml.MapSlice)
		} else {
			slice = append(slice, yaml.MapItem{Key: path[0]})
		}
	}
	slice[len(slice)-1].Value = mapSlice_(inner, path[1:], value)
	return slice
}

func (t *Tree) filter(pattern string) *Tree {
	keep := t.Empty()
	for p, val := range t.tree {
		if matches(p, pattern) {
			keep.tree[p] = val
		}
	}
	return keep
}

func isLowercase(s string) bool {
	return s == strings.ToLower(s)
}

func matches(p Path, pattern string) bool {
	ps := strings.Split(string(p), "\t")
	patterns := strings.Split(pattern, "/")
	if len(patterns) > len(ps) {
		return false
	}

	ignoreCase := isLowercase(pattern)
	for i, pattern := range patterns {
		haystack := ps[i]
		if ignoreCase {
			haystack = strings.ToLower(haystack)
		}
		if !strings.Contains(haystack, pattern) {
			return false
		}
	}
	return true
}

func (t *Tree) get(p Path) (*Value, bool) {
	val, ok := t.tree[p]
	return val, ok
}

func (t *Tree) set(p Path, val *Value) {
	t.tree[p] = val
}

// Encrypt returns a copy of this tree with all leaves encrypted.
func (tree *Tree) Encrypt() *Tree {
	t := tree.Empty()
	for p, v := range tree.tree {
		if p.IsPublic() { // don't encrypt public data
			t.tree[p] = v
			continue
		}
		if p.IsEncryptionKey() { // value uses different encryption key
			t.tree[p] = v
			continue
		}
		t.tree[p] = v.Ciphertext(t.encryptionKey)
	}
	return t
}

// Encode returns a copy of this tree with all leaves encoded into base64.
func (tree *Tree) Encode() *Tree {
	t := tree.Empty()
	for p, v := range tree.tree {
		t.tree[p] = v.Encode()
	}
	return t
}

// Empty returns a copy of this tree with all the keys and values
// removed.  It retains any other data associated with this tree.
func (t *Tree) Empty() *Tree {
	tree := &Tree{
		tree:          make(map[Path]*Value, len(t.tree)),
		encryptionKey: t.encryptionKey,
	}
	return tree
}

// SetPassphrase sets the password that's used for performing
// encryption and decryption.
func (t *Tree) SetPassphrase(password []byte) {
	t.encryptionKey = []byte(`0123456789abcdef`)
}

// Decrypt returns a copy of this tree with all leaves decrypted.
func (tree *Tree) Decrypt() *Tree {
	t := tree.Empty()
	for p, v := range tree.tree {
		if p.IsPublic() { // don't decrypt public data
			t.tree[p] = v
			continue
		}
		if p.IsEncryptionKey() { // value uses different encryption key
			t.tree[p] = v
			continue
		}
		t.tree[p] = v.Plaintext(tree.encryptionKey)
	}
	return t
}

// Print displays a tree for human consumption.
func (tree *Tree) Print(w io.Writer) error {
	tree = tree.Decrypt()
	slice := tree.mapSlice()
	data, err := yaml.Marshal(slice)
	if err != nil {
		return errors.Wrap(err, "printing tree")
	}

	_, err = w.Write(data)
	return err
}

// Save stores a tree to disk for permanent, private archival.
func (tree *Tree) Save() error {
	tree = tree.Encrypt().Encode()
	slice := tree.mapSlice()

	data, err := yaml.Marshal(slice)
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}

	// save to temporary file
	file, err := ioutil.TempFile("", "hush-")
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	err = os.Chmod(file.Name(), safePerm)
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	_, err = file.Write(data)
	file.Close()
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}

	// move temporary file over top of permanent file
	hushPath, err := hushPath()
	if os.IsNotExist(err) {
		err = nil // we can create the file
	}
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	err = os.Rename(file.Name(), hushPath)
	return errors.Wrap(err, "saving tree")
}
<commit_msg>Use password for encryption<commit_after>package hush

import (
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"golang.org/x/crypto/pbkdf2"

	"github.com/pkg/errors"

	yaml "gopkg.in/yaml.v2"
)

type Tree struct {
	tree map[Path]*Value

	encryptionKey []byte
}

const safePerm = 0600 // rw- --- ---

func LoadTree() (*Tree, error) {
	hushPath, err := hushPath()
	if err != nil {
		return nil, err
	}

	stat, err := os.Stat(hushPath)
	if os.IsNotExist(err) {
		warn("hush file does not exist. assuming an empty one")
		return &Tree{}, nil
	}
	if err != nil {
		return nil, errors.Wrap(err, "can't stat hush file")
	}
	if (stat.Mode() & os.ModePerm) != safePerm {
		warn("hush file has loose permissions. fixing.")
		err := os.Chmod(hushPath, safePerm)
		if err != nil {
			die("couldn't fix permissions on hush file")
		}
	}

	file, err := os.Open(hushPath)
	if err != nil {
		return nil, errors.Wrap(err, "opening hush file")
	}
	hushData, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, errors.Wrap(err, "can't read hush file")
	}

	keys := make(yaml.MapSlice, 0)
	err = yaml.Unmarshal(hushData, &keys)
	if err != nil {
		return nil, errors.Wrap(err, "can't parse hush file")
	}
	tree := newT(keys)
	return tree, nil
}

func newT(items yaml.MapSlice) *Tree {
	t := &Tree{
		tree: make(map[Path]*Value, 3*len(items)),
	}
	newT_(items, []string{}, t)
	return t
}

func newT_(items yaml.MapSlice, crumbs []string, t *Tree) {
	n := len(crumbs)
	for _, item := range items {
		key := item.Key.(string)
		crumbs = append(crumbs, key)

		switch val := item.Value.(type) {
		case string:
			p := NewPath(strings.Join(crumbs, "/"))
			privacy := Private
			if p.IsPublic() {
				privacy = Public
			}
			t.tree[p] = NewEncoded(val, privacy)
		case yaml.MapSlice:
			newT_(val, crumbs, t)
		default:
			panic(fmt.Sprintf("unexpected type: %#v", val))
		}
		crumbs = crumbs[:n] // remove final crumb
	}
}

func (t *Tree) mapSlice() yaml.MapSlice {
	// sort by key
	kvs := make([][]string, 0, len(t.tree))
	for p, val := range t.tree {
		kvs = append(kvs, []string{string(p), val.String()})
	}
	sort.SliceStable(kvs, func(i, j int) bool {
		return kvs[i][0] < kvs[j][0]
	})

	var slice yaml.MapSlice
	for _, kv := range kvs {
		path := strings.Split(kv[0], "\t")
		slice = mapSlice_(slice, path, kv[1])
	}
	return slice
}

func mapSlice_(slice yaml.MapSlice, path []string, value string) yaml.MapSlice {
	if len(path) == 0 {
		panic("path should never have 0 length")
	}
	if len(path) == 1 {
		return append(slice, yaml.MapItem{
			Key:   path[0],
			Value: value,
		})
	}

	var inner yaml.MapSlice
	if len(slice) == 0 {
		slice = append(slice, yaml.MapItem{Key: path[0]})
	} else {
		final := slice[len(slice)-1]
		if final.Key.(string) == path[0] {
			inner = final.Value.(yaml.MapSlice)
		} else {
			slice = append(slice, yaml.MapItem{Key: path[0]})
		}
	}
	slice[len(slice)-1].Value = mapSlice_(inner, path[1:], value)
	return slice
}

func (t *Tree) filter(pattern string) *Tree {
	keep := t.Empty()
	for p, val := range t.tree {
		if matches(p, pattern) {
			keep.tree[p] = val
		}
	}
	return keep
}

func isLowercase(s string) bool {
	return s == strings.ToLower(s)
}

func matches(p Path, pattern string) bool {
	ps := strings.Split(string(p), "\t")
	patterns := strings.Split(pattern, "/")
	if len(patterns) > len(ps) {
		return false
	}

	ignoreCase := isLowercase(pattern)
	for i, pattern := range patterns {
		haystack := ps[i]
		if ignoreCase {
			haystack = strings.ToLower(haystack)
		}
		if !strings.Contains(haystack, pattern) {
			return false
		}
	}
	return true
}

func (t *Tree) get(p Path) (*Value, bool) {
	val, ok := t.tree[p]
	return val, ok
}

func (t *Tree) set(p Path, val *Value) {
	t.tree[p] = val
}

// Encrypt returns a copy of this tree with all leaves encrypted.
func (tree *Tree) Encrypt() *Tree {
	t := tree.Empty()
	for p, v := range tree.tree {
		if p.IsPublic() { // don't encrypt public data
			t.tree[p] = v
			continue
		}
		if p.IsEncryptionKey() { // value uses different encryption key
			t.tree[p] = v
			continue
		}
		t.tree[p] = v.Ciphertext(t.encryptionKey)
	}
	return t
}

// Encode returns a copy of this tree with all leaves encoded into base64.
func (tree *Tree) Encode() *Tree {
	t := tree.Empty()
	for p, v := range tree.tree {
		t.tree[p] = v.Encode()
	}
	return t
}

// Empty returns a copy of this tree with all the keys and values
// removed.  It retains any other data associated with this tree.
func (t *Tree) Empty() *Tree {
	tree := &Tree{
		tree:          make(map[Path]*Value, len(t.tree)),
		encryptionKey: t.encryptionKey,
	}
	return tree
}

// SetPassphrase sets the password that's used for performing
// encryption and decryption.
func (t *Tree) SetPassphrase(password []byte) error {
	p := NewPath("hush-configuration/salt")
	v, ok := t.get(p)
	if !ok {
		return errors.New("hush file missing salt")
	}
	v, err := v.Decode()
	if err != nil {
		return err
	}
	salt := v.plaintext
	pwKey := pbkdf2.Key(
		password, salt,
		2<<15, // iteration count (about 80ms on modern server)
		32,    // desired key size in bytes
		sha256.New,
	)

	p = NewPath("hush-configuration/encryption-key")
	v, ok = t.get(p)
	if !ok {
		return errors.New("hush file missing encryption key")
	}
	v = v.Plaintext(pwKey)

	t.encryptionKey = v.plaintext
	return nil
}

// Decrypt returns a copy of this tree with all leaves decrypted.
func (tree *Tree) Decrypt() *Tree {
	t := tree.Empty()
	for p, v := range tree.tree {
		if p.IsPublic() { // don't decrypt public data
			t.tree[p] = v
			continue
		}
		if p.IsEncryptionKey() { // value uses different encryption key
			t.tree[p] = v
			continue
		}
		t.tree[p] = v.Plaintext(tree.encryptionKey)
	}
	return t
}

// Print displays a tree for human consumption.
func (tree *Tree) Print(w io.Writer) error {
	tree = tree.Decrypt()
	slice := tree.mapSlice()
	data, err := yaml.Marshal(slice)
	if err != nil {
		return errors.Wrap(err, "printing tree")
	}

	_, err = w.Write(data)
	return err
}

// Save stores a tree to disk for permanent, private archival.
func (tree *Tree) Save() error {
	tree = tree.Encrypt().Encode()
	slice := tree.mapSlice()

	data, err := yaml.Marshal(slice)
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}

	// save to temporary file
	file, err := ioutil.TempFile("", "hush-")
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	err = os.Chmod(file.Name(), safePerm)
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	_, err = file.Write(data)
	file.Close()
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}

	// move temporary file over top of permanent file
	hushPath, err := hushPath()
	if os.IsNotExist(err) {
		err = nil // we can create the file
	}
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	err = os.Rename(file.Name(), hushPath)
	return errors.Wrap(err, "saving tree")
}
<|endoftext|>


<commit_before>package kace

type node struct {
	val   rune
	end   bool
	links []*node
}

func newNode() *node {
	return &node{links: make([]*node, 0)}
}

func (n *node) add(rs []rune) {
	cur := n
	for _, v := range rs {
		link := cur.linkByVal(v)
		if link == nil {
			link = newNode()
			cur.links = append(cur.links, link)
		}
		cur = link
	}
}

func (n *node) find(rs []rune) bool {
	cur := n
	for _, v := range rs {
		cur = cur.linkByVal(v)
		if cur == nil {
			return false
		}
	}

	return cur.end
}

func (n *node) linkByVal(val rune) *node {
	for _, v := range n.links {
		if v.val == val {
			return v
		}
	}

	return nil
}
<commit_msg>Fix newNode assignments and find logic.<commit_after>package kace

type node struct {
	val   rune
	end   bool
	links []*node
}

func newNode(val rune, isEnd bool) *node {
	return &node{
		val:   val,
		end:   isEnd,
		links: make([]*node, 0),
	}
}

func (n *node) add(rs []rune) {
	cur := n
	for k, v := range rs {
		isEnd := k == len(rs)-1

		link := cur.linkByVal(v)
		if link == nil {
			link = newNode(v, isEnd)
			cur.links = append(cur.links, link)
		}

		cur = link
	}
}

func (n *node) find(rs []rune) bool {
	cur := n
	for _, v := range rs {
		cur = cur.linkByVal(v)
		if cur == nil {
			return false
		}
	}

	return cur.end
}

func (n *node) linkByVal(val rune) *node {
	for _, v := range n.links {
		if v.val == val {
			return v
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	fs "gopkg.in/fsnotify.v1"
)

//
// Event
//
type Event struct {
	E fs.Event
	T time.Time
	I os.FileInfo
}

//
// chans
//
type ChanEvent chan *Event
type ChanExit chan bool

//
// Piper
//
type Piper interface {
	Pipe(next Piper) Piper
	Handle(e *Event)
	Close() error
}

//
// Watcher watch file changes
//
type Watcher struct {
	w    *fs.Watcher
	next Piper
	exit ChanExit
}

// NewWatcher create watcher
func NewWatcher(dirs []string) (*Watcher, error) {
	// w
	w, err := fs.NewWatcher()
	if err != nil {
		return nil, err
	}

	// listen
	log.Println("[umon]", "Watcher: watch dirs", dirs)
	for _, dir := range dirs {
		filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
			if info == nil {
				return err
			}
			if !info.IsDir() {
				return nil
			}
			w.Add(path)
			return nil
		})
	}

	// ok
	return &Watcher{
		w:    w,
		exit: make(ChanExit, 1),
	}, nil
}

// @impl Piper
func (w *Watcher) Pipe(next Piper) Piper {
	w.next = next
	go w.runWatch()
	return next
}

// runWatch run watch
func (w *Watcher) runWatch() {
	for {
		select {
		case <-w.exit:
			return

		case e := <-w.w.Events:
			info, _ := os.Stat(e.Name)
			if info != nil && info.IsDir() {
				switch e.Op {
				case fs.Create:
					w.w.Add(e.Name)
				case fs.Remove:
					w.w.Remove(e.Name)
				}
			}
			w.next.Handle(&Event{
				E: e,
				T: time.Now(),
				I: info,
			})
		}
	}
}

// @impl Piper.Handle
func (w *Watcher) Handle(e *Event) {
	// empty
}

// Close watch
func (w *Watcher) Close() error {
	w.exit <- true
	return nil
}

//
// Filter filter unwanted event
//
type Filter struct {
	next Piper

	events ChanEvent
	exit   ChanExit
}

func NewFilter() (*Filter, error) {
	return &Filter{
		exit:   make(ChanExit, 1),
		events: make(ChanEvent, 16),
	}, nil
}

// @impl Piper.Handle
func (f *Filter) Handle(e *Event) {
	f.events <- e
}

// @impl Piper.Pipe
func (f *Filter) Pipe(next Piper) Piper {
	f.next = next
	go f.runFilt()
	return next
}

// runFilter run filter
func (f *Filter) runFilt() {
	// last time when receive event
	var (
		lastTime time.Time
		lastEvt  *Event
	)

	// check event ticker
	ticker := time.NewTicker(time.Second)

	for {
		select {
		case <-f.exit:
			return

		case e := <-f.events:
			name := filepath.Base(e.E.Name)
			if strings.HasPrefix(name, ".") {
				continue
			}
			ext := filepath.Ext(name)
			if ext != ".go" {
				continue
			}
			lastTime = time.Now()
			lastEvt = e

		case <-ticker.C:
			if lastEvt == nil {
				continue
			}
			if time.Now().Sub(lastTime) < time.Second {
				continue
			}
			f.next.Handle(lastEvt)
			lastEvt = nil
		}
	}
}

// @impl Close
func (f *Filter) Close() error {
	f.exit <- true
	return nil
}

//
// Builder builder unwanted event
//
type Builder struct {
	next   Piper
	events ChanEvent
	exit   ChanExit
}

func NewBuilder() (*Builder, error) {
	return &Builder{
		exit:   make(ChanExit, 1),
		events: make(ChanEvent, 16),
	}, nil
}

// @impl Piper.Handle
func (b *Builder) Handle(e *Event) {
	b.events <- e
}

// @impl Piper.Pipe
func (b *Builder) Pipe(next Piper) Piper {
	b.next = next
	go b.runBuild()
	return next
}

// runBuild run builder
func (b *Builder) runBuild() {
	var (
		lastTime time.Time
		lastEvt  *Event
	)
	ticker := time.NewTicker(time.Second)

	for {
		select {
		case <-b.exit:
			return

		case e := <-b.events:
			cmd := exec.Command("go", "build")
			cmd.Stderr, cmd.Stdout = os.Stderr, os.Stdout
			if err := cmd.Start(); err != nil {
				log.Fatal(err)
			}
			if err := cmd.Wait(); err != nil {
				log.Println("[umon]", "Builder: build err", err)
			} else {
				lastTime = time.Now()
				lastEvt = e
				log.Println("[umon]", "Builder: build ok")
			}

		case <-ticker.C:
			if lastEvt == nil {
				continue
			}
			if time.Now().Sub(lastTime) < time.Second {
				continue
			}
			b.next.Handle(lastEvt)
			lastEvt = nil
		}
	}
}

// @impl Close
func (b *Builder) Close() error {
	b.exit <- true
	return nil
}

//
// Runner runner unwanted event
//
type Runner struct {
	next   Piper
	events ChanEvent
	exit   ChanExit
}

func NewRunner() (*Runner, error) {
	return &Runner{
		exit:   make(ChanExit, 1),
		events: make(ChanEvent, 16),
	}, nil
}

// @impl Piper.Handle
func (b *Runner) Handle(e *Event) {
	b.events <- e
}

// @impl Piper.Pipe
func (b *Runner) Pipe(next Piper) Piper {
	b.next = next
	go b.runRun()
	return next
}

// runRun run runner
func (b *Runner) runRun() {
	// app name
	runDir := os.Getenv("PWD")
	if len(runDir) == 0 {
		panic("no PWD env")
	}
	appName := filepath.Join(runDir, filepath.Base(runDir))
	log.Println("[umon]", "Runner: app", appName)

	// notify run
	runC := make(chan bool, 1)
	runC <- true

	// cmd
	var cmd *exec.Cmd
	for {
		select {
		case <-b.exit:
			return

		case <-b.events:
			runC <- true

		case <-runC:
			// kill
			if cmd != nil {
				log.Println("[umon]", "Runner: kill", cmd.Process)
				if cmd.Process != nil {
					cmd.Process.Kill()
				}
				cmd = nil
				time.Sleep(200*time.Microsecond)
			}

			// exist
			if _, err := os.Stat(appName); err != nil {
				if os.IsNotExist(err) {
					log.Println("[umon]", "Runner: app not exist, run go build first")
				}
				continue
			}

			// start
			cmd = exec.Command(appName)
			cmd.Stderr, cmd.Stdout = os.Stderr, os.Stdout
			if err := cmd.Start(); err != nil {
				log.Println("[umon]", "Runner: start err", err)
			} else {
				log.Println("[umon]", "Runner: start ok")
			}
		}
	}
}

// @impl Close
func (b *Runner) Close() error {
	b.exit <- true
	return nil
}

//
// Ender
//
type Ender struct {
	// empty
}

// NewEnder create ender instance
func NewEnder() (*Ender, error) {
	return &Ender{
	// empty
	}, nil
}

// @impl Piper.Pipe
func (ed *Ender) Pipe(next Piper) Piper {
	// no next
	return nil
}

// @impl Piper.Handle
func (ed *Ender) Handle(e *Event) {
	log.Println("[umon]", "Ender: handle", e)
}

// @impl Close
func (ed *Ender) Close() error {
	return nil
}

//
// umon ../app ../ctrl
//
func main() {
	// watcher
	watchDir := []string{"."}
	if len(os.Args) > 1 {
		watchDir = os.Args[1:]
	}
	watch, err := NewWatcher(watchDir)
	if err != nil {
		log.Fatal(err)
	}
	defer watch.Close()

	// filter
	filter, err := NewFilter()
	if err != nil {
		log.Fatal(err)
	}
	defer filter.Close()

	// builder
	builder, err := NewBuilder()
	if err != nil {
		log.Fatal(err)
	}
	defer builder.Close()

	// runner
	runner, err := NewRunner()
	if err != nil {
		log.Fatal(err)
	}
	defer runner.Close()

	// end
	end, err := NewEnder()
	if err != nil {
		log.Fatal(err)
	}
	defer end.Close()

	// pipe
	watch.Pipe(filter).Pipe(builder).Pipe(runner).Pipe(end)

	// wait
	exit := make(ChanExit)
	<-exit
}
<commit_msg>fix hint<commit_after>package main

import (
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	fs "gopkg.in/fsnotify.v1"
)

//
// Event
//
type Event struct {
	E fs.Event
	T time.Time
	I os.FileInfo
}

//
// chans
//
type ChanEvent chan *Event
type ChanExit chan bool

//
// Piper
//
type Piper interface {
	Pipe(next Piper) Piper
	Handle(e *Event)
	Close() error
}

//
// Watcher watch file changes
//
type Watcher struct {
	w    *fs.Watcher
	next Piper
	exit ChanExit
}

// NewWatcher create watcher
func NewWatcher(dirs []string) (*Watcher, error) {
	// w
	w, err := fs.NewWatcher()
	if err != nil {
		return nil, err
	}

	// listen
	log.Println("[umon]", "Watcher: watch dirs", dirs)
	for _, dir := range dirs {
		filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
			if info == nil {
				return err
			}
			if !info.IsDir() {
				return nil
			}
			w.Add(path)
			return nil
		})
	}

	// ok
	return &Watcher{
		w:    w,
		exit: make(ChanExit, 1),
	}, nil
}

// @impl Piper
func (w *Watcher) Pipe(next Piper) Piper {
	w.next = next
	go w.runWatch()
	return next
}

// runWatch run watch
func (w *Watcher) runWatch() {
	for {
		select {
		case <-w.exit:
			return

		case e := <-w.w.Events:
			info, _ := os.Stat(e.Name)
			if info != nil && info.IsDir() {
				switch e.Op {
				case fs.Create:
					w.w.Add(e.Name)
				case fs.Remove:
					w.w.Remove(e.Name)
				}
			}
			w.next.Handle(&Event{
				E: e,
				T: time.Now(),
				I: info,
			})
		}
	}
}

// @impl Piper.Handle
func (w *Watcher) Handle(e *Event) {
	// empty
}

// Close watch
func (w *Watcher) Close() error {
	w.exit <- true
	return nil
}

//
// Filter filter unwanted event
//
type Filter struct {
	next Piper

	events ChanEvent
	exit   ChanExit
}

func NewFilter() (*Filter, error) {
	return &Filter{
		exit:   make(ChanExit, 1),
		events: make(ChanEvent, 16),
	}, nil
}

// @impl Piper.Handle
func (f *Filter) Handle(e *Event) {
	f.events <- e
}

// @impl Piper.Pipe
func (f *Filter) Pipe(next Piper) Piper {
	f.next = next
	go f.runFilt()
	return next
}

// runFilter run filter
func (f *Filter) runFilt() {
	// last time when receive event
	var (
		lastTime time.Time
		lastEvt  *Event
	)

	// check event ticker
	ticker := time.NewTicker(time.Second)

	for {
		select {
		case <-f.exit:
			return

		case e := <-f.events:
			name := filepath.Base(e.E.Name)
			if strings.HasPrefix(name, ".") {
				continue
			}
			ext := filepath.Ext(name)
			if ext != ".go" {
				continue
			}
			lastTime = time.Now()
			lastEvt = e

		case <-ticker.C:
			if lastEvt == nil {
				continue
			}
			if time.Now().Sub(lastTime) < time.Second {
				continue
			}
			f.next.Handle(lastEvt)
			lastEvt = nil
		}
	}
}

// @impl Close
func (f *Filter) Close() error {
	f.exit <- true
	return nil
}

//
// Builder builder unwanted event
//
type Builder struct {
	next   Piper
	events ChanEvent
	exit   ChanExit
}

func NewBuilder() (*Builder, error) {
	return &Builder{
		exit:   make(ChanExit, 1),
		events: make(ChanEvent, 16),
	}, nil
}

// @impl Piper.Handle
func (b *Builder) Handle(e *Event) {
	b.events <- e
}

// @impl Piper.Pipe
func (b *Builder) Pipe(next Piper) Piper {
	b.next = next
	go b.runBuild()
	return next
}

// runBuild run builder
func (b *Builder) runBuild() {
	var (
		lastTime time.Time
		lastEvt  *Event
	)
	ticker := time.NewTicker(time.Second)

	for {
		select {
		case <-b.exit:
			return

		case e := <-b.events:
			cmd := exec.Command("go", "build")
			cmd.Stderr, cmd.Stdout = os.Stderr, os.Stdout
			if err := cmd.Start(); err != nil {
				log.Fatal(err)
			}
			if err := cmd.Wait(); err != nil {
				log.Println("[umon]", "Builder: build err", err)
			} else {
				lastTime = time.Now()
				lastEvt = e
				log.Println("[umon]", "Builder: build ok")
			}

		case <-ticker.C:
			if lastEvt == nil {
				continue
			}
			if time.Now().Sub(lastTime) < time.Second {
				continue
			}
			b.next.Handle(lastEvt)
			lastEvt = nil
		}
	}
}

// @impl Close
func (b *Builder) Close() error {
	b.exit <- true
	return nil
}

//
// Runner runner unwanted event
//
type Runner struct {
	next   Piper
	events ChanEvent
	exit   ChanExit
}

func NewRunner() (*Runner, error) {
	return &Runner{
		exit:   make(ChanExit, 1),
		events: make(ChanEvent, 16),
	}, nil
}

// @impl Piper.Handle
func (b *Runner) Handle(e *Event) {
	b.events <- e
}

// @impl Piper.Pipe
func (b *Runner) Pipe(next Piper) Piper {
	b.next = next
	go b.runRun()
	return next
}

// runRun run runner
func (b *Runner) runRun() {
	// app name
	runDir := os.Getenv("PWD")
	if len(runDir) == 0 {
		panic("no PWD env")
	}
	appName := filepath.Join(runDir, filepath.Base(runDir))
	log.Println("[umon]", "Runner: app", appName)

	// notify run
	runC := make(chan bool, 1)
	runC <- true

	// cmd
	var cmd *exec.Cmd
	for {
		select {
		case <-b.exit:
			return

		case <-b.events:
			runC <- true

		case <-runC:
			// kill
			if cmd != nil {
				log.Println("[umon]", "Runner: kill", cmd.Process)
				if cmd.Process != nil {
					cmd.Process.Kill()
				}
				cmd = nil
				time.Sleep(200*time.Microsecond)
			}

			// exist
			if _, err := os.Stat(appName); err != nil {
				if os.IsNotExist(err) {
					log.Println("[umon]", "Runner: app not exist, run go build, then restart umon")
				}
				continue
			}

			// start
			cmd = exec.Command(appName)
			cmd.Stderr, cmd.Stdout = os.Stderr, os.Stdout
			if err := cmd.Start(); err != nil {
				log.Println("[umon]", "Runner: start err", err)
			} else {
				log.Println("[umon]", "Runner: start ok")
			}
		}
	}
}

// @impl Close
func (b *Runner) Close() error {
	b.exit <- true
	return nil
}

//
// Ender
//
type Ender struct {
	// empty
}

// NewEnder create ender instance
func NewEnder() (*Ender, error) {
	return &Ender{
	// empty
	}, nil
}

// @impl Piper.Pipe
func (ed *Ender) Pipe(next Piper) Piper {
	// no next
	return nil
}

// @impl Piper.Handle
func (ed *Ender) Handle(e *Event) {
	log.Println("[umon]", "Ender: handle", e)
}

// @impl Close
func (ed *Ender) Close() error {
	return nil
}

//
// umon ../app ../ctrl
//
func main() {
	// watcher
	watchDir := []string{"."}
	if len(os.Args) > 1 {
		watchDir = os.Args[1:]
	}
	watch, err := NewWatcher(watchDir)
	if err != nil {
		log.Fatal(err)
	}
	defer watch.Close()

	// filter
	filter, err := NewFilter()
	if err != nil {
		log.Fatal(err)
	}
	defer filter.Close()

	// builder
	builder, err := NewBuilder()
	if err != nil {
		log.Fatal(err)
	}
	defer builder.Close()

	// runner
	runner, err := NewRunner()
	if err != nil {
		log.Fatal(err)
	}
	defer runner.Close()

	// end
	end, err := NewEnder()
	if err != nil {
		log.Fatal(err)
	}
	defer end.Close()

	// pipe
	watch.Pipe(filter).Pipe(builder).Pipe(runner).Pipe(end)

	// wait
	exit := make(ChanExit)
	<-exit
}
<|endoftext|>


<commit_before>package discordgo

import (
	"fmt"
	"strings"
)

// A User stores all data for an individual Discord user.
type User struct {
	ID            string `json:"id"`
	Email         string `json:"email"`
	Username      string `json:"username"`
	Avatar        string `json:"avatar"`
	Discriminator string `json:"discriminator"`
	Token         string `json:"token"`
	Verified      bool   `json:"verified"`
	MFAEnabled    bool   `json:"mfa_enabled"`
	Bot           bool   `json:"bot"`
}

// String returns a unique identifier of the form username#discriminator
func (u *User) String() string {
	return fmt.Sprintf("%s#%s", u.Username, u.Discriminator)
}

// Mention return a string which mentions the user
func (u *User) Mention() string {
	return fmt.Sprintf("<@%s>", u.ID)
}

// AvatarURL returns a URL to the user's avatar.
//		size:     The size of the user's avatar as a power of two
func (u *User) AvatarURL(size string) string {
	var URL string
	if strings.HasPrefix(u.Avatar, "a_") {
		URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
	} else {
		URL = EndpointUserAvatar(u.ID, u.Avatar)
	}

	return URL + "?size=" + size
}
<commit_msg>Allow size parameter to be omitted (#468)<commit_after>package discordgo

import (
	"fmt"
	"strings"
)

// A User stores all data for an individual Discord user.
type User struct {
	ID            string `json:"id"`
	Email         string `json:"email"`
	Username      string `json:"username"`
	Avatar        string `json:"avatar"`
	Discriminator string `json:"discriminator"`
	Token         string `json:"token"`
	Verified      bool   `json:"verified"`
	MFAEnabled    bool   `json:"mfa_enabled"`
	Bot           bool   `json:"bot"`
}

// String returns a unique identifier of the form username#discriminator
func (u *User) String() string {
	return fmt.Sprintf("%s#%s", u.Username, u.Discriminator)
}

// Mention return a string which mentions the user
func (u *User) Mention() string {
	return fmt.Sprintf("<@%s>", u.ID)
}

// AvatarURL returns a URL to the user's avatar.
//    size:    The size of the user's avatar as a power of two
//             if size is an empty string, no size parameter will
//             be added to the URL.
func (u *User) AvatarURL(size string) string {
	var URL string
	if strings.HasPrefix(u.Avatar, "a_") {
		URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
	} else {
		URL = EndpointUserAvatar(u.ID, u.Avatar)
	}

	if size != "" {
		return URL + "?size=" + size
	}
	return URL
}
<|endoftext|>


<commit_before>package snowboard

import "net/http"

func digString(key string, el *Element) string {
	return el.Path(key).Value().String()
}

func digTitle(el *Element) string {
	return digString("meta.title", el)
}

func digDescription(el *Element) string {
	return el.Path("content").Index(0).Path("content").Value().String()
}

func digMetadata(el *Element) []Metadata {
	mds := []Metadata{}

	children, err := el.Path("attributes.meta").Children()
	if err != nil {
		return mds
	}

	for _, v := range children {
		md := Metadata{
			Name:  digString("content.key.content", v),
			Value: digString("content.value.content", v),
		}

		mds = append(mds, md)
	}

	return mds
}

func digResourceGroups(el *Element) (gs []ResourceGroup) {
	children, err := el.Path("content").Children()
	if err != nil {
		return
	}

	for _, child := range children {
		if digString("element", child) == "category" {
			g := &ResourceGroup{
				Title:     digString("meta.title", child),
				Resources: digResources(child),
			}

			gs = append(gs, *g)
		}
	}

	return
}

func digResources(el *Element) (rs []Resource) {
	children, err := el.Path("content").Children()
	if err != nil {
		return
	}

	for _, child := range children {
		if digString("element", child) == "resource" {
			r := &Resource{
				Title:       digString("meta.title", child),
				Transitions: digTransitions(child),
				Href:        extractHrefs(child),
			}

			rs = append(rs, *r)
		}
	}

	return
}

func digTransitions(el *Element) (ts []Transition) {
	children, err := el.Path("content").Children()
	if err != nil {
		return
	}

	for _, child := range children {
		if digString("element", child) == "transition" {
			t := &Transition{
				Title:        digString("meta.title", child),
				Transactions: digTransactions(child),
			}

			ts = append(ts, *t)
		}
	}

	return
}

func digTransactions(el *Element) (xs []Transaction) {
	children, err := el.Path("content").Children()
	if err != nil {
		return
	}

	for _, child := range children {
		if digString("element", child) == "httpTransaction" {
			x := &Transaction{
				Request:  extractRequest(child),
				Response: extractResponse(child),
			}

			xs = append(xs, *x)
		}
	}

	return
}

func extractRequest(child *Element) (r Request) {
	if digString("element", child) == "httpRequest" {
		return Request{
			Method: digString("attributes.method", child),
		}
	}

	return
}

func extractResponse(child *Element) (r Response) {
	if digString("element", child) == "httpResponse" {
		return Response{
			StatusCode: int(child.Path("attributes.statusCode").Value().Int()),
			Headers:    extractHeaders(child),
		}
	}

	return
}

func extractHeaders(child *Element) (h http.Header) {
	if digString("element", child) == "httpHeaders" {
		contents, err := child.Path("content").Children()
		if err != nil {
			return
		}

		for _, content := range contents {
			key := digString("content.key.content", content)
			val := digString("content.value.content", content)

			h.Set(key, val)
		}

		return
	}

	return
}

func extractHrefs(child *Element) (h Href) {
	h.Path = digString("href", child)

	contents, err := child.Path("attributes.hrefVariables.content").Children()
	if err != nil {
		return
	}

	for _, content := range contents {
		v := &HVariable{
			Name:        digString("content.key.content", content),
			Value:       digString("content.value.content", content),
			Description: digString("meta.description", content),
		}

		h.Variables = append(h.Variables, *v)
	}

	return
}
<commit_msg>check path existence before use<commit_after>package snowboard

import "net/http"

func digString(key string, el *Element) string {
	return el.Path(key).Value().String()
}

func digTitle(el *Element) string {
	return digString("meta.title", el)
}

func digDescription(el *Element) string {
	return el.Path("content").Index(0).Path("content").Value().String()
}

func digMetadata(el *Element) []Metadata {
	mds := []Metadata{}

	children, err := el.Path("attributes.meta").Children()
	if err != nil {
		return mds
	}

	for _, v := range children {
		md := Metadata{
			Name:  digString("content.key.content", v),
			Value: digString("content.value.content", v),
		}

		mds = append(mds, md)
	}

	return mds
}

func digResourceGroups(el *Element) (gs []ResourceGroup) {
	children, err := el.Path("content").Children()
	if err != nil {
		return
	}

	for _, child := range children {
		if digString("element", child) == "category" {
			g := &ResourceGroup{
				Title:     digString("meta.title", child),
				Resources: digResources(child),
			}

			gs = append(gs, *g)
		}
	}

	return
}

func digResources(el *Element) (rs []Resource) {
	children, err := el.Path("content").Children()
	if err != nil {
		return
	}

	for _, child := range children {
		if digString("element", child) == "resource" {
			r := &Resource{
				Title:       digString("meta.title", child),
				Transitions: digTransitions(child),
				Href:        extractHrefs(child),
			}

			rs = append(rs, *r)
		}
	}

	return
}

func digTransitions(el *Element) (ts []Transition) {
	children, err := el.Path("content").Children()
	if err != nil {
		return
	}

	for _, child := range children {
		if digString("element", child) == "transition" {
			t := &Transition{
				Title:        digString("meta.title", child),
				Transactions: digTransactions(child),
			}

			ts = append(ts, *t)
		}
	}

	return
}

func digTransactions(el *Element) (xs []Transaction) {
	children, err := el.Path("content").Children()
	if err != nil {
		return
	}

	for _, child := range children {
		if digString("element", child) == "httpTransaction" {
			x := &Transaction{
				Request:  extractRequest(child),
				Response: extractResponse(child),
			}

			xs = append(xs, *x)
		}
	}

	return
}

func extractRequest(child *Element) (r Request) {
	if digString("element", child) == "httpRequest" {
		return Request{
			Method: digString("attributes.method", child),
		}
	}

	return
}

func extractResponse(child *Element) (r Response) {
	if digString("element", child) == "httpResponse" {
		return Response{
			StatusCode: int(child.Path("attributes.statusCode").Value().Int()),
			Headers:    extractHeaders(child),
		}
	}

	return
}

func extractHeaders(child *Element) (h http.Header) {
	if digString("element", child) == "httpHeaders" {
		contents, err := child.Path("content").Children()
		if err != nil {
			return
		}

		for _, content := range contents {
			key := digString("content.key.content", content)
			val := digString("content.value.content", content)

			h.Set(key, val)
		}

		return
	}

	return
}

func extractHrefs(child *Element) (h Href) {
	if child.Path("href").Value().IsValid() {
		h.Path = digString("href", child)
	}

	contents, err := child.Path("attributes.hrefVariables.content").Children()
	if err != nil {
		return
	}

	for _, content := range contents {
		v := &HVariable{
			Name:        digString("content.key.content", content),
			Value:       digString("content.value.content", content),
			Description: digString("meta.description", content),
		}

		h.Variables = append(h.Variables, *v)
	}

	return
}
<|endoftext|>


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

package db

import "os"
import "strings"

// ExecuteDirectly is a convenience function for "one-off" queries.
// It's particularly convenient for queries that don't produce any
// results.
//
// If you need more control, for example to rebind parameters over
// and over again, to get results one by one, or to access metadata
// about the results, you should use the Prepare() and Execute()
// methods explicitly instead.
//
// TODO: results should be returned some other way...
func ExecuteDirectly(conn Connection, query string, params ...) (results [][]interface{}, err os.Error) {
	var s Statement;
	s, err = conn.Prepare(query);
	if err != nil || s == nil {
		return
	}
	defer s.Close();

	var c ClassicResultSet;
	con := conn.(ClassicConnection);
	c, err = con.ExecuteClassic(s, params);
	if err != nil || c == nil {
		return
	}
	defer c.Close();

	results, err = ClassicFetchAll(c);
	return;
}

// ParseQueryURL() helps database drivers parse URLs passed
// to Open(). ParseQueryURL() takes a string of the form
//
//	key=value;key=value;...;key=value
//
// and returns a map from keys to values. The empty string
// yields an empty map. Format violations or duplicate keys
// yield an error and an incomplete map.
func ParseQueryURL(str string) (opt map[string]string, err os.Error) {
	opt = make(map[string]string);
	if len(str) > 0 {
		err = parseQueryHelper(str, opt);
	}
	return;
}

func parseQueryHelper(str string, opt map[string]string) (err os.Error) {
	pairs := strings.Split(str, ";", 0);
	if len(pairs) == 0 {
		err = os.NewError("ParseQueryURL: No pairs in "+str);
		return; // nothing left to do
	}

	for _, p := range pairs {
		pieces := strings.Split(p, "=", 0);
		// we keep going even if there was an error to fill the
		// map as much as possible; this means we'll return only
		// the last error, a tradeoff
		if len(pieces) == 2 {
			if _, duplicate := opt[pieces[0]]; duplicate {
				err = os.NewError("ParseQueryURL: Duplicate key "+pieces[0]);
			}
			else {
				opt[pieces[0]] = pieces[1]
			}
		}
		else {
			err = os.NewError("ParseQueryURL: One '=' expected, got "+p);
		}
	}

	return;
}
<commit_msg>Gofmt to adjust to new semicolon syntax.<commit_after>// Copyright 2009 Peter H. Froehlich. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package db

import "os"
import "strings"

// ExecuteDirectly is a convenience function for "one-off" queries.
// It's particularly convenient for queries that don't produce any
// results.
//
// If you need more control, for example to rebind parameters over
// and over again, to get results one by one, or to access metadata
// about the results, you should use the Prepare() and Execute()
// methods explicitly instead.
//
// TODO: results should be returned some other way...
func ExecuteDirectly(conn Connection, query string, params ...) (results [][]interface{}, err os.Error) {
	var s Statement;
	s, err = conn.Prepare(query);
	if err != nil || s == nil {
		return
	}
	defer s.Close();

	var c ClassicResultSet;
	con := conn.(ClassicConnection);
	c, err = con.ExecuteClassic(s, params);
	if err != nil || c == nil {
		return
	}
	defer c.Close();

	results, err = ClassicFetchAll(c);
	return;
}

// ParseQueryURL() helps database drivers parse URLs passed
// to Open(). ParseQueryURL() takes a string of the form
//
//	key=value;key=value;...;key=value
//
// and returns a map from keys to values. The empty string
// yields an empty map. Format violations or duplicate keys
// yield an error and an incomplete map.
func ParseQueryURL(str string) (opt map[string]string, err os.Error) {
	opt = make(map[string]string);
	if len(str) > 0 {
		err = parseQueryHelper(str, opt)
	}
	return;
}

func parseQueryHelper(str string, opt map[string]string) (err os.Error) {
	pairs := strings.Split(str, ";", 0);
	if len(pairs) == 0 {
		err = os.NewError("ParseQueryURL: No pairs in " + str);
		return;	// nothing left to do
	}

	for _, p := range pairs {
		pieces := strings.Split(p, "=", 0);
		// we keep going even if there was an error to fill the
		// map as much as possible; this means we'll return only
		// the last error, a tradeoff
		if len(pieces) == 2 {
			if _, duplicate := opt[pieces[0]]; duplicate {
				err = os.NewError("ParseQueryURL: Duplicate key " + pieces[0])
			} else {
				opt[pieces[0]] = pieces[1]
			}
		} else {
			err = os.NewError("ParseQueryURL: One '=' expected, got " + p)
		}
	}

	return;
}
<|endoftext|>


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

package circonusgometrics

import (
	"github.com/circonus-labs/circonusllhist"
)

// Reset removes all existing counters and gauges.
func (m *CirconusMetrics) Reset() {
	m.cm.Lock()
	defer m.cm.Unlock()

	m.cfm.Lock()
	defer m.cfm.Unlock()

	m.gm.Lock()
	defer m.gm.Unlock()

	m.gfm.Lock()
	defer m.gfm.Unlock()

	m.hm.Lock()
	defer m.hm.Unlock()

	m.tm.Lock()
	defer m.tm.Unlock()

	m.tfm.Lock()
	defer m.tfm.Unlock()

	m.counters = make(map[string]uint64)
	m.counterFuncs = make(map[string]func() uint64)
	// m.gauges = make(map[string]string)
	m.gauges = make(map[string]interface{})
	m.gaugeFuncs = make(map[string]func() int64)
	m.histograms = make(map[string]*Histogram)
	m.text = make(map[string]string)
	m.textFuncs = make(map[string]func() string)
}

// snapshot returns a copy of the values of all registered counters and gauges.
func (m *CirconusMetrics) snapshot() (c map[string]uint64, g map[string]interface{}, h map[string]*circonusllhist.Histogram, t map[string]string) {
	// func (m *CirconusMetrics) snapshot() (c map[string]uint64, g map[string]string, h map[string]*circonusllhist.Histogram, t map[string]string) {
	c = m.snapCounters()
	g = m.snapGauges()
	h = m.snapHistograms()
	t = m.snapText()

	return
}

func (m *CirconusMetrics) snapCounters() map[string]uint64 {
	m.cm.Lock()
	defer m.cm.Unlock()
	m.cfm.Lock()
	defer m.cfm.Unlock()

	c := make(map[string]uint64, len(m.counters)+len(m.counterFuncs))

	for n, v := range m.counters {
		c[n] = v
	}
	if m.resetCounters && len(c) > 0 {
		m.counters = make(map[string]uint64)
	}

	for n, f := range m.counterFuncs {
		c[n] = f()
	}
	if m.resetCounters && len(c) > 0 {
		m.counterFuncs = make(map[string]func() uint64)
	}

	return c
}

func (m *CirconusMetrics) snapGauges() map[string]interface{} {
	// func (m *CirconusMetrics) snapGauges() map[string]string {
	m.gm.Lock()
	defer m.gm.Unlock()
	m.gfm.Lock()
	defer m.gfm.Unlock()

	// g := make(map[string]string, len(m.gauges)+len(m.gaugeFuncs))
	g := make(map[string]interface{}, len(m.gauges)+len(m.gaugeFuncs))

	for n, v := range m.gauges {
		g[n] = v
	}
	if m.resetGauges && len(g) > 0 {
		// m.gauges = make(map[string]string)
		m.gauges = make(map[string]interface{})
	}

	for n, f := range m.gaugeFuncs {
		g[n] = f() //m.gaugeValString(f())
	}
	if m.resetGauges && len(g) > 0 {
		m.gaugeFuncs = make(map[string]func() int64)
	}

	return g
}

func (m *CirconusMetrics) snapHistograms() map[string]*circonusllhist.Histogram {
	m.hm.Lock()
	defer m.hm.Unlock()

	h := make(map[string]*circonusllhist.Histogram, len(m.histograms))

	for n, hist := range m.histograms {
		hist.rw.Lock()
		h[n] = hist.hist.CopyAndReset()
		hist.rw.Unlock()
	}
	if m.resetHistograms && len(h) > 0 {
		m.histograms = make(map[string]*Histogram)
	}

	return h
}

func (m *CirconusMetrics) snapText() map[string]string {
	m.tm.Lock()
	defer m.tm.Unlock()
	m.tfm.Lock()
	defer m.tfm.Unlock()

	t := make(map[string]string, len(m.text)+len(m.textFuncs))

	for n, v := range m.text {
		t[n] = v
	}
	if m.resetText && len(t) > 0 {
		m.text = make(map[string]string)
	}

	for n, f := range m.textFuncs {
		t[n] = f()
	}
	if m.resetText && len(t) > 0 {
		m.textFuncs = make(map[string]func() string)
	}

	return t
}

func (m *CirconusMetrics) getGaugeType(v interface{}) string {
	mt := "n"
	switch v.(type) {
	case int:
		mt = "i"
	case int8:
		mt = "i"
	case int16:
		mt = "i"
	case int32:
		mt = "i"
	case uint:
		mt = "I"
	case uint8:
		mt = "I"
	case uint16:
		mt = "I"
	case uint32:
		mt = "I"
	case int64:
		mt = "l"
	case uint64:
		mt = "L"
	}

	return mt
}
<commit_msg>remove obsolete code<commit_after>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package circonusgometrics

import (
	"github.com/circonus-labs/circonusllhist"
)

// Reset removes all existing counters and gauges.
func (m *CirconusMetrics) Reset() {
	m.cm.Lock()
	defer m.cm.Unlock()

	m.cfm.Lock()
	defer m.cfm.Unlock()

	m.gm.Lock()
	defer m.gm.Unlock()

	m.gfm.Lock()
	defer m.gfm.Unlock()

	m.hm.Lock()
	defer m.hm.Unlock()

	m.tm.Lock()
	defer m.tm.Unlock()

	m.tfm.Lock()
	defer m.tfm.Unlock()

	m.counters = make(map[string]uint64)
	m.counterFuncs = make(map[string]func() uint64)
	m.gauges = make(map[string]interface{})
	m.gaugeFuncs = make(map[string]func() int64)
	m.histograms = make(map[string]*Histogram)
	m.text = make(map[string]string)
	m.textFuncs = make(map[string]func() string)
}

// snapshot returns a copy of the values of all registered counters and gauges.
func (m *CirconusMetrics) snapshot() (c map[string]uint64, g map[string]interface{}, h map[string]*circonusllhist.Histogram, t map[string]string) {
	c = m.snapCounters()
	g = m.snapGauges()
	h = m.snapHistograms()
	t = m.snapText()

	return
}

func (m *CirconusMetrics) snapCounters() map[string]uint64 {
	m.cm.Lock()
	defer m.cm.Unlock()
	m.cfm.Lock()
	defer m.cfm.Unlock()

	c := make(map[string]uint64, len(m.counters)+len(m.counterFuncs))

	for n, v := range m.counters {
		c[n] = v
	}
	if m.resetCounters && len(c) > 0 {
		m.counters = make(map[string]uint64)
	}

	for n, f := range m.counterFuncs {
		c[n] = f()
	}
	if m.resetCounters && len(c) > 0 {
		m.counterFuncs = make(map[string]func() uint64)
	}

	return c
}

func (m *CirconusMetrics) snapGauges() map[string]interface{} {
	m.gm.Lock()
	defer m.gm.Unlock()
	m.gfm.Lock()
	defer m.gfm.Unlock()

	g := make(map[string]interface{}, len(m.gauges)+len(m.gaugeFuncs))

	for n, v := range m.gauges {
		g[n] = v
	}
	if m.resetGauges && len(g) > 0 {
		m.gauges = make(map[string]interface{})
	}

	for n, f := range m.gaugeFuncs {
		g[n] = f()
	}
	if m.resetGauges && len(g) > 0 {
		m.gaugeFuncs = make(map[string]func() int64)
	}

	return g
}

func (m *CirconusMetrics) snapHistograms() map[string]*circonusllhist.Histogram {
	m.hm.Lock()
	defer m.hm.Unlock()

	h := make(map[string]*circonusllhist.Histogram, len(m.histograms))

	for n, hist := range m.histograms {
		hist.rw.Lock()
		h[n] = hist.hist.CopyAndReset()
		hist.rw.Unlock()
	}
	if m.resetHistograms && len(h) > 0 {
		m.histograms = make(map[string]*Histogram)
	}

	return h
}

func (m *CirconusMetrics) snapText() map[string]string {
	m.tm.Lock()
	defer m.tm.Unlock()
	m.tfm.Lock()
	defer m.tfm.Unlock()

	t := make(map[string]string, len(m.text)+len(m.textFuncs))

	for n, v := range m.text {
		t[n] = v
	}
	if m.resetText && len(t) > 0 {
		m.text = make(map[string]string)
	}

	for n, f := range m.textFuncs {
		t[n] = f()
	}
	if m.resetText && len(t) > 0 {
		m.textFuncs = make(map[string]func() string)
	}

	return t
}
<|endoftext|>


<commit_before>package geo

import (
	"io/ioutil"
	"net/http"
)

func ResponseData(url string) []byte {
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil
	}

	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		return nil
	}

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

	return data
}
<commit_msg>more comment<commit_after>package geo

import (
	"io/ioutil"
	"net/http"
)

// ResponseData gets response from url
func ResponseData(url string) []byte {
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil
	}

	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		return nil
	}

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

	return data
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package utils

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
	"regexp"
	"strings"
)

// UUID represent a universal identifier with 16 octets.
type UUID [16]byte

var validUUID = regexp.MustCompile("^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[8,9,a,b][0-9a-f]{3}-[0-9a-f]{12}$")

func UUIDFromString(s string) (UUID, error) {
	if !IsValidUUIDString(s) {
		return UUID{}, fmt.Errorf("invalid UUID: %q", s)
	}
	s = strings.Replace(s, "-", "", 4)
	raw, err := hex.DecodeString(s)
	if err != nil {
		return UUID{}, err
	}
	var uuid UUID
	copy(uuid[:], raw)
	return uuid, nil
}

// IsValidUUIDString returns true, if the given string matches a valid UUID (version 4, variant 2).
func IsValidUUIDString(s string) bool {
	return validUUID.MatchString(s)
}

// NewUUID generates a new version 4 UUID relying only on random numbers.
func NewUUID() (UUID, error) {
	uuid := UUID{}
	if _, err := io.ReadFull(rand.Reader, []byte(uuid[0:16])); err != nil {
		return UUID{}, err
	}
	// Set version (4) and variant (2) according to RfC 4122.
	var version byte = 4 << 4
	var variant byte = 8 << 4
	uuid[6] = version | (uuid[6] & 15)
	uuid[8] = variant | (uuid[8] & 15)
	return uuid, nil
}

// Copy returns a copy of the UUID.
func (uuid UUID) Copy() UUID {
	uuidCopy := uuid
	return uuidCopy
}

// Raw returns a copy of the UUID bytes.
func (uuid UUID) Raw() [16]byte {
	return [16]byte(uuid)
}

// String returns a hexadecimal string representation with
// standardized separators.
func (uuid UUID) String() string {
	return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
}
<commit_msg>Better representation of the regex<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.

package utils

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"io"
	"regexp"
	"strings"
)

// UUID represent a universal identifier with 16 octets.
type UUID [16]byte

// regex for validating that the UUID matches RFC 4122.
// This package specifically generates and accepts version 4 UUIDs
// where the string representation has the digit 4 at the beginning of
// the third grouping, and one of the hex digits 8 through b at the
// beginning of the fourth grouping.
// http://www.ietf.org/rfc/rfc4122.txt
var (
	block1  = "[0-9a-f]{8}"
	block2  = "[0-9a-f]{4}"
	version = "4"
	block3  = "[0-9a-f]{3}"
	variant = "[8,9,a,b]"
	block4  = "[0-9a-f]{3}"
	block5  = "[0-9a-f]{12}"

	validUUID = regexp.MustCompile("^" + block1 + "-" + block2 + "-" + version + block3 + "-" + variant + block4 + "-" + block5 + "$")
)

func UUIDFromString(s string) (UUID, error) {
	if !IsValidUUIDString(s) {
		return UUID{}, fmt.Errorf("invalid UUID: %q", s)
	}
	s = strings.Replace(s, "-", "", 4)
	raw, err := hex.DecodeString(s)
	if err != nil {
		return UUID{}, err
	}
	var uuid UUID
	copy(uuid[:], raw)
	return uuid, nil
}

// IsValidUUIDString returns true, if the given string matches a valid UUID (version 4, variant 2).
func IsValidUUIDString(s string) bool {
	return validUUID.MatchString(s)
}

// NewUUID generates a new version 4 UUID relying only on random numbers.
func NewUUID() (UUID, error) {
	uuid := UUID{}
	if _, err := io.ReadFull(rand.Reader, []byte(uuid[0:16])); err != nil {
		return UUID{}, err
	}
	// Set version (4) and variant (2) according to RfC 4122.
	var version byte = 4 << 4
	var variant byte = 8 << 4
	uuid[6] = version | (uuid[6] & 15)
	uuid[8] = variant | (uuid[8] & 15)
	return uuid, nil
}

// Copy returns a copy of the UUID.
func (uuid UUID) Copy() UUID {
	uuidCopy := uuid
	return uuidCopy
}

// Raw returns a copy of the UUID bytes.
func (uuid UUID) Raw() [16]byte {
	return [16]byte(uuid)
}

// String returns a hexadecimal string representation with
// standardized separators.
func (uuid UUID) String() string {
	return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
}
<|endoftext|>


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

// The uuid package can be used to generate and parse universally unique
// identifiers, a standardized format in the form of a 128 bit number.
//
// http://tools.ietf.org/html/rfc4122
package gocql

import (
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"net"
	"sync/atomic"
	"time"
)

type UUID [16]byte

var hardwareAddr []byte
var clockSeq uint32

const (
	VariantNCSCompat = 0
	VariantIETF      = 2
	VariantMicrosoft = 6
	VariantFuture    = 7
)

func init() {
	if interfaces, err := net.Interfaces(); err == nil {
		for _, i := range interfaces {
			if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 {
				hardwareAddr = i.HardwareAddr
				break
			}
		}
	}
	if hardwareAddr == nil {
		// If we failed to obtain the MAC address of the current computer,
		// we will use a randomly generated 6 byte sequence instead and set
		// the multicast bit as recommended in RFC 4122.
		hardwareAddr = make([]byte, 6)
		_, err := io.ReadFull(rand.Reader, hardwareAddr)
		if err != nil {
			panic(err)
		}
		hardwareAddr[0] = hardwareAddr[0] | 0x01
	}

	// initialize the clock sequence with a random number
	var clockSeqRand [2]byte
	io.ReadFull(rand.Reader, clockSeqRand[:])
	clockSeq = uint32(clockSeqRand[1])<<8 | uint32(clockSeqRand[0])
}

// ParseUUID parses a 32 digit hexadecimal number (that might contain hypens)
// represanting an UUID.
func ParseUUID(input string) (UUID, error) {
	var u UUID
	j := 0
	for _, r := range input {
		switch {
		case r == '-' && j&1 == 0:
			continue
		case r >= '0' && r <= '9' && j < 32:
			u[j/2] |= byte(r-'0') << uint(4-j&1*4)
		case r >= 'a' && r <= 'f' && j < 32:
			u[j/2] |= byte(r-'a'+10) << uint(4-j&1*4)
		case r >= 'A' && r <= 'F' && j < 32:
			u[j/2] |= byte(r-'A'+10) << uint(4-j&1*4)
		default:
			return UUID{}, fmt.Errorf("invalid UUID %q", input)
		}
		j += 1
	}
	if j != 32 {
		return UUID{}, fmt.Errorf("invalid UUID %q", input)
	}
	return u, nil
}

// UUIDFromBytes converts a raw byte slice to an UUID.
func UUIDFromBytes(input []byte) (UUID, error) {
	var u UUID
	if len(input) != 16 {
		return u, errors.New("UUIDs must be exactly 16 bytes long")
	}

	copy(u[:], input)
	return u, nil
}

// RandomUUID generates a totally random UUID (version 4) as described in
// RFC 4122.
func RandomUUID() (UUID, error) {
	var u UUID
	_, err := io.ReadFull(rand.Reader, u[:])
	if err != nil {
		return u, err
	}
	u[6] &= 0x0F // clear version
	u[6] |= 0x40 // set version to 4 (random uuid)
	u[8] &= 0x3F // clear variant
	u[8] |= 0x80 // set to IETF variant
	return u, nil
}

var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()

// TimeUUID generates a new time based UUID (version 1) using the current
// time as the timestamp.
func TimeUUID() UUID {
	return UUIDFromTime(time.Now())
}

// UUIDFromTime generates a new time based UUID (version 1) as described in
// RFC 4122. This UUID contains the MAC address of the node that generated
// the UUID, the given timestamp and a sequence number.
func UUIDFromTime(aTime time.Time) UUID {
	var u UUID

	utcTime := aTime.In(time.UTC)
	t := uint64(utcTime.Unix()-timeBase)*10000000 + uint64(utcTime.Nanosecond()/100)
	u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
	u[4], u[5] = byte(t>>40), byte(t>>32)
	u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)

	clock := atomic.AddUint32(&clockSeq, 1)
	u[8] = byte(clock >> 8)
	u[9] = byte(clock)

	copy(u[10:], hardwareAddr)

	u[6] |= 0x10 // set version to 1 (time based uuid)
	u[8] &= 0x3F // clear variant
	u[8] |= 0x80 // set to IETF variant

	return u
}

// String returns the UUID in it's canonical form, a 32 digit hexadecimal
// number in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (u UUID) String() string {
	return fmt.Sprintf("%x-%x-%x-%x-%x",
		u[0:4], u[4:6], u[6:8], u[8:10], u[10:16])
}

// Bytes returns the raw byte slice for this UUID. A UUID is always 128 bits
// (16 bytes) long.
func (u UUID) Bytes() []byte {
	return u[:]
}

// Variant returns the variant of this UUID. This package will only generate
// UUIDs in the IETF variant.
func (u UUID) Variant() int {
	x := u[8]
	if x&0x80 == 0 {
		return VariantNCSCompat
	}
	if x&0x40 == 0 {
		return VariantIETF
	}
	if x&0x20 == 0 {
		return VariantMicrosoft
	}
	return VariantFuture
}

// Version extracts the version of this UUID variant. The RFC 4122 describes
// five kinds of UUIDs.
func (u UUID) Version() int {
	return int(u[6] & 0xF0 >> 4)
}

// Node extracts the MAC address of the node who generated this UUID. It will
// return nil if the UUID is not a time based UUID (version 1).
func (u UUID) Node() []byte {
	if u.Version() != 1 {
		return nil
	}
	return u[10:]
}

// Timestamp extracts the timestamp information from a time based UUID
// (version 1).
func (u UUID) Timestamp() int64 {
	if u.Version() != 1 {
		return 0
	}
	return int64(uint64(u[0])<<24|uint64(u[1])<<16|
		uint64(u[2])<<8|uint64(u[3])) +
		int64(uint64(u[4])<<40|uint64(u[5])<<32) +
		int64(uint64(u[6]&0x0F)<<56|uint64(u[7])<<48)
}

// Time is like Timestamp, except that it returns a time.Time.
func (u UUID) Time() time.Time {
	if u.Version() != 1 {
		return time.Time{}
	}
	t := u.Timestamp()
	sec := t / 1e7
	nsec := t % 1e7
	return time.Unix(sec+timeBase, nsec).UTC()
}

// Marshaling for JSON
func (u UUID) MarshalJSON() ([]byte, error) {
	return []byte(`"` + u.String() + `"`), nil
}

// Unmarshaling for JSON
func (u *UUID) UnmarshalJSON(data []byte) error {
	str := string(data)
	if len(str) != 38 {
		return fmt.Errorf("invalid JSON UUID %s", str)
	}

	newU, err := ParseUUID(str[1:37])
	if err == nil {
		copy(u[:], newU[:])
	}

	return err
}
<commit_msg>Renamed 'newU' into 'parsed'<commit_after>// Copyright (c) 2012 The gocql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The uuid package can be used to generate and parse universally unique
// identifiers, a standardized format in the form of a 128 bit number.
//
// http://tools.ietf.org/html/rfc4122
package gocql

import (
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"net"
	"sync/atomic"
	"time"
)

type UUID [16]byte

var hardwareAddr []byte
var clockSeq uint32

const (
	VariantNCSCompat = 0
	VariantIETF      = 2
	VariantMicrosoft = 6
	VariantFuture    = 7
)

func init() {
	if interfaces, err := net.Interfaces(); err == nil {
		for _, i := range interfaces {
			if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 {
				hardwareAddr = i.HardwareAddr
				break
			}
		}
	}
	if hardwareAddr == nil {
		// If we failed to obtain the MAC address of the current computer,
		// we will use a randomly generated 6 byte sequence instead and set
		// the multicast bit as recommended in RFC 4122.
		hardwareAddr = make([]byte, 6)
		_, err := io.ReadFull(rand.Reader, hardwareAddr)
		if err != nil {
			panic(err)
		}
		hardwareAddr[0] = hardwareAddr[0] | 0x01
	}

	// initialize the clock sequence with a random number
	var clockSeqRand [2]byte
	io.ReadFull(rand.Reader, clockSeqRand[:])
	clockSeq = uint32(clockSeqRand[1])<<8 | uint32(clockSeqRand[0])
}

// ParseUUID parses a 32 digit hexadecimal number (that might contain hypens)
// represanting an UUID.
func ParseUUID(input string) (UUID, error) {
	var u UUID
	j := 0
	for _, r := range input {
		switch {
		case r == '-' && j&1 == 0:
			continue
		case r >= '0' && r <= '9' && j < 32:
			u[j/2] |= byte(r-'0') << uint(4-j&1*4)
		case r >= 'a' && r <= 'f' && j < 32:
			u[j/2] |= byte(r-'a'+10) << uint(4-j&1*4)
		case r >= 'A' && r <= 'F' && j < 32:
			u[j/2] |= byte(r-'A'+10) << uint(4-j&1*4)
		default:
			return UUID{}, fmt.Errorf("invalid UUID %q", input)
		}
		j += 1
	}
	if j != 32 {
		return UUID{}, fmt.Errorf("invalid UUID %q", input)
	}
	return u, nil
}

// UUIDFromBytes converts a raw byte slice to an UUID.
func UUIDFromBytes(input []byte) (UUID, error) {
	var u UUID
	if len(input) != 16 {
		return u, errors.New("UUIDs must be exactly 16 bytes long")
	}

	copy(u[:], input)
	return u, nil
}

// RandomUUID generates a totally random UUID (version 4) as described in
// RFC 4122.
func RandomUUID() (UUID, error) {
	var u UUID
	_, err := io.ReadFull(rand.Reader, u[:])
	if err != nil {
		return u, err
	}
	u[6] &= 0x0F // clear version
	u[6] |= 0x40 // set version to 4 (random uuid)
	u[8] &= 0x3F // clear variant
	u[8] |= 0x80 // set to IETF variant
	return u, nil
}

var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()

// TimeUUID generates a new time based UUID (version 1) using the current
// time as the timestamp.
func TimeUUID() UUID {
	return UUIDFromTime(time.Now())
}

// UUIDFromTime generates a new time based UUID (version 1) as described in
// RFC 4122. This UUID contains the MAC address of the node that generated
// the UUID, the given timestamp and a sequence number.
func UUIDFromTime(aTime time.Time) UUID {
	var u UUID

	utcTime := aTime.In(time.UTC)
	t := uint64(utcTime.Unix()-timeBase)*10000000 + uint64(utcTime.Nanosecond()/100)
	u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
	u[4], u[5] = byte(t>>40), byte(t>>32)
	u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)

	clock := atomic.AddUint32(&clockSeq, 1)
	u[8] = byte(clock >> 8)
	u[9] = byte(clock)

	copy(u[10:], hardwareAddr)

	u[6] |= 0x10 // set version to 1 (time based uuid)
	u[8] &= 0x3F // clear variant
	u[8] |= 0x80 // set to IETF variant

	return u
}

// String returns the UUID in it's canonical form, a 32 digit hexadecimal
// number in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (u UUID) String() string {
	return fmt.Sprintf("%x-%x-%x-%x-%x",
		u[0:4], u[4:6], u[6:8], u[8:10], u[10:16])
}

// Bytes returns the raw byte slice for this UUID. A UUID is always 128 bits
// (16 bytes) long.
func (u UUID) Bytes() []byte {
	return u[:]
}

// Variant returns the variant of this UUID. This package will only generate
// UUIDs in the IETF variant.
func (u UUID) Variant() int {
	x := u[8]
	if x&0x80 == 0 {
		return VariantNCSCompat
	}
	if x&0x40 == 0 {
		return VariantIETF
	}
	if x&0x20 == 0 {
		return VariantMicrosoft
	}
	return VariantFuture
}

// Version extracts the version of this UUID variant. The RFC 4122 describes
// five kinds of UUIDs.
func (u UUID) Version() int {
	return int(u[6] & 0xF0 >> 4)
}

// Node extracts the MAC address of the node who generated this UUID. It will
// return nil if the UUID is not a time based UUID (version 1).
func (u UUID) Node() []byte {
	if u.Version() != 1 {
		return nil
	}
	return u[10:]
}

// Timestamp extracts the timestamp information from a time based UUID
// (version 1).
func (u UUID) Timestamp() int64 {
	if u.Version() != 1 {
		return 0
	}
	return int64(uint64(u[0])<<24|uint64(u[1])<<16|
		uint64(u[2])<<8|uint64(u[3])) +
		int64(uint64(u[4])<<40|uint64(u[5])<<32) +
		int64(uint64(u[6]&0x0F)<<56|uint64(u[7])<<48)
}

// Time is like Timestamp, except that it returns a time.Time.
func (u UUID) Time() time.Time {
	if u.Version() != 1 {
		return time.Time{}
	}
	t := u.Timestamp()
	sec := t / 1e7
	nsec := t % 1e7
	return time.Unix(sec+timeBase, nsec).UTC()
}

// Marshaling for JSON
func (u UUID) MarshalJSON() ([]byte, error) {
	return []byte(`"` + u.String() + `"`), nil
}

// Unmarshaling for JSON
func (u *UUID) UnmarshalJSON(data []byte) error {
	str := string(data)
	if len(str) != 38 {
		return fmt.Errorf("invalid JSON UUID %s", str)
	}

	parsed, err := ParseUUID(str[1:37])
	if err == nil {
		copy(u[:], parsed[:])
	}

	return err
}
<|endoftext|>


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

package gocui

import (
	"bufio"
	"bytes"
	"errors"
	"strings"

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

// A View is a window. It maintains its own internal buffer and cursor
// position.
type View struct {
	name                   string
	x0, y0, x1, y1         int
	ox, oy                 int
	cx, cy                 int
	lines                  [][]rune
	bgColor, fgColor       Attribute
	selBgColor, selFgColor Attribute
	overwrite              bool // overwrite in edit mode

	// If Editable is true, keystrokes will be added to the view's internal
	// buffer at the cursor position.
	Editable bool

	// If Highlight is true, Sel{Bg,Fg}Colors will be used
	// for the line under the cursor position.
	Highlight bool
}

// newView returns a new View object.
func newView(name string, x0, y0, x1, y1 int) *View {
	v := &View{
		name: name,
		x0:   x0,
		y0:   y0,
		x1:   x1,
		y1:   y1,
	}
	return v
}

// Size returns the number of visible columns and rows in the View.
func (v *View) Size() (x, y int) {
	return v.x1 - v.x0 - 1, v.y1 - v.y0 - 1
}

// Name returns the name of the view.
func (v *View) Name() string {
	return v.name
}

// setRune writes a rune at the given point, relative to the view. It
// checks if the position is valid and applies the view's colors, taking
// into account if the cell must be highlighted.
func (v *View) setRune(x, y int, ch rune) error {
	maxX, maxY := v.Size()
	if x < 0 || x >= maxX || y < 0 || y >= maxY {
		return errors.New("invalid point")
	}

	var fgColor, bgColor Attribute
	if v.Highlight && y == v.cy {
		fgColor = v.selFgColor
		bgColor = v.selBgColor
	} else {
		fgColor = v.fgColor
		bgColor = v.bgColor
	}
	termbox.SetCell(v.x0+x+1, v.y0+y+1, ch,
		termbox.Attribute(fgColor), termbox.Attribute(bgColor))
	return nil
}

// SetCursor sets the cursor position of the view at the given point,
// relative to the view. It checks if the position is valid.
func (v *View) SetCursor(x, y int) error {
	maxX, maxY := v.Size()
	if x < 0 || x >= maxX || y < 0 || y >= maxY {
		return errors.New("invalid point")
	}
	v.cx = x
	v.cy = y
	return nil
}

// Cursor returns the cursor position of the view.
func (v *View) Cursor() (x, y int) {
	return v.cx, v.cy
}

// SetOrigin sets the origin position of the view's internal buffer,
// so the buffer starts to be printed from this point, which means that
// it is linked with the origin point of view. It can be used to
// implement Horizontal and Vertical scrolling with just incrementing
// or decrementing ox and oy.
func (v *View) SetOrigin(x, y int) error {
	if x < 0 || y < 0 {
		return errors.New("invalid point")
	}
	v.ox = x
	v.oy = y
	return nil
}

// Origin returns the origin position of the view.
func (v *View) Origin() (x, y int) {
	return v.ox, v.oy
}

// Write appends a byte slice into the view's internal buffer. Because
// View implements the io.Writer interface, it can be passed as parameter
// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
// be called to clear the view's buffer.
func (v *View) Write(p []byte) (n int, err error) {
	r := bytes.NewReader(p)
	s := bufio.NewScanner(r)
	for s.Scan() {
		line := bytes.Runes(s.Bytes())
		v.lines = append(v.lines, line)
	}
	if err := s.Err(); err != nil {
		return 0, err
	}
	return len(p), nil
}

// draw re-draws the view's contents.
func (v *View) draw() error {
	maxX, maxY := v.Size()
	y := 0
	for i, line := range v.lines {
		if i < v.oy {
			continue
		}
		x := 0
		for j, ch := range line {
			if j < v.ox {
				continue
			}
			if x >= 0 && x < maxX && y >= 0 && y < maxY {
				if err := v.setRune(x, y, ch); err != nil {
					return err
				}
			}
			x++
		}
		y++
	}
	return nil
}

// Clear empties the view's internal buffer.
func (v *View) Clear() {
	v.lines = nil
	v.clearRunes()
}

// clearRunes erases all the cells in the view.
func (v *View) clearRunes() {
	maxX, maxY := v.Size()
	for x := 0; x < maxX; x++ {
		for y := 0; y < maxY; y++ {
			termbox.SetCell(v.x0+x+1, v.y0+y+1, ' ',
				termbox.Attribute(v.fgColor), termbox.Attribute(v.bgColor))
		}
	}
}

// writeRune writes a rune into the view's internal buffer, at the
// position corresponding to the point (x, y). The length of the internal
// buffer is increased if the point is out of bounds. Overwrite mode is
// governed by the value of View.overwrite.
func (v *View) writeRune(x, y int, ch rune) error {
	x = v.ox + x
	y = v.oy + y

	if x < 0 || y < 0 {
		return errors.New("invalid point")
	}

	if y >= len(v.lines) {
		if y >= cap(v.lines) {
			s := make([][]rune, y+1, (y+1)*2)
			copy(s, v.lines)
			v.lines = s
		} else {
			v.lines = v.lines[:y+1]
		}
	}
	if v.lines[y] == nil {
		v.lines[y] = make([]rune, x+1, (x+1)*2)
	} else if x >= len(v.lines[y]) {
		if x >= cap(v.lines[y]) {
			s := make([]rune, x+1, (x+1)*2)
			copy(s, v.lines[y])
			v.lines[y] = s
		} else {
			v.lines[y] = v.lines[y][:x+1]
		}
	}
	if !v.overwrite {
		v.lines[y] = append(v.lines[y], ' ')
		copy(v.lines[y][x+1:], v.lines[y][x:])
	}
	v.lines[y][x] = ch
	return nil
}

// deleteRune removes a rune from the view's internal buffer, at the
// position corresponding to the point (x, y).
func (v *View) deleteRune(x, y int) error {
	x = v.ox + x
	y = v.oy + y

	if x < 0 || y < 0 || y >= len(v.lines) || v.lines[y] == nil || x >= len(v.lines[y]) {
		return errors.New("invalid point")
	}
	copy(v.lines[y][x:], v.lines[y][x+1:])
	v.lines[y][len(v.lines[y])-1] = ' '
	return nil
}

// addLine adds a line into the view's internal buffer at the position
// corresponding to the point (x, y).
func (v *View) addLine(y int) error {
	y = v.oy + y

	if y < 0 || y >= len(v.lines) {
		return errors.New("invalid point")
	}
	v.lines = append(v.lines, nil)
	copy(v.lines[y+1:], v.lines[y:])
	v.lines[y] = nil
	return nil
}

// Line returns a string with the line in the view's internal buffer
// at the position corresponding to the point (x, y).
func (v *View) Line(y int) (string, error) {
	y = v.oy + y

	if y < 0 || y >= len(v.lines) {
		return "", errors.New("invalid point")
	}
	return string(v.lines[y]), nil
}

// Word returns a string with the word in the view's internal buffer
// at the position corresponding to the point (x, y).
func (v *View) Word(x, y int) (string, error) {
	x = v.ox + x
	y = v.oy + y

	if y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
		return "", errors.New("invalid point")
	}
	l := string(v.lines[y])
	nl := strings.LastIndex(l[:x], " ")
	if nl == -1 {
		nl = 0
	} else {
		nl = nl + 1
	}
	nr := strings.Index(l[x:], " ")
	if nr == -1 {
		nr = len(l)
	} else {
		nr = nr + x
	}
	return string(l[nl:nr]), nil
}
<commit_msg>Fix typo in view.go<commit_after>// Copyright 2014 The gocui Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gocui

import (
	"bufio"
	"bytes"
	"errors"
	"strings"

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

// A View is a window. It maintains its own internal buffer and cursor
// position.
type View struct {
	name                   string
	x0, y0, x1, y1         int
	ox, oy                 int
	cx, cy                 int
	lines                  [][]rune
	bgColor, fgColor       Attribute
	selBgColor, selFgColor Attribute
	overwrite              bool // overwrite in edit mode

	// If Editable is true, keystrokes will be added to the view's internal
	// buffer at the cursor position.
	Editable bool

	// If Highlight is true, Sel{Bg,Fg}Colors will be used
	// for the line under the cursor position.
	Highlight bool
}

// newView returns a new View object.
func newView(name string, x0, y0, x1, y1 int) *View {
	v := &View{
		name: name,
		x0:   x0,
		y0:   y0,
		x1:   x1,
		y1:   y1,
	}
	return v
}

// Size returns the number of visible columns and rows in the View.
func (v *View) Size() (x, y int) {
	return v.x1 - v.x0 - 1, v.y1 - v.y0 - 1
}

// Name returns the name of the view.
func (v *View) Name() string {
	return v.name
}

// setRune writes a rune at the given point, relative to the view. It
// checks if the position is valid and applies the view's colors, taking
// into account if the cell must be highlighted.
func (v *View) setRune(x, y int, ch rune) error {
	maxX, maxY := v.Size()
	if x < 0 || x >= maxX || y < 0 || y >= maxY {
		return errors.New("invalid point")
	}

	var fgColor, bgColor Attribute
	if v.Highlight && y == v.cy {
		fgColor = v.selFgColor
		bgColor = v.selBgColor
	} else {
		fgColor = v.fgColor
		bgColor = v.bgColor
	}
	termbox.SetCell(v.x0+x+1, v.y0+y+1, ch,
		termbox.Attribute(fgColor), termbox.Attribute(bgColor))
	return nil
}

// SetCursor sets the cursor position of the view at the given point,
// relative to the view. It checks if the position is valid.
func (v *View) SetCursor(x, y int) error {
	maxX, maxY := v.Size()
	if x < 0 || x >= maxX || y < 0 || y >= maxY {
		return errors.New("invalid point")
	}
	v.cx = x
	v.cy = y
	return nil
}

// Cursor returns the cursor position of the view.
func (v *View) Cursor() (x, y int) {
	return v.cx, v.cy
}

// SetOrigin sets the origin position of the view's internal buffer,
// so the buffer starts to be printed from this point, which means that
// it is linked with the origin point of view. It can be used to
// implement Horizontal and Vertical scrolling with just incrementing
// or decrementing ox and oy.
func (v *View) SetOrigin(x, y int) error {
	if x < 0 || y < 0 {
		return errors.New("invalid point")
	}
	v.ox = x
	v.oy = y
	return nil
}

// Origin returns the origin position of the view.
func (v *View) Origin() (x, y int) {
	return v.ox, v.oy
}

// Write appends a byte slice into the view's internal buffer. Because
// View implements the io.Writer interface, it can be passed as parameter
// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
// be called to clear the view's buffer.
func (v *View) Write(p []byte) (n int, err error) {
	r := bytes.NewReader(p)
	s := bufio.NewScanner(r)
	for s.Scan() {
		line := bytes.Runes(s.Bytes())
		v.lines = append(v.lines, line)
	}
	if err := s.Err(); err != nil {
		return 0, err
	}
	return len(p), nil
}

// draw re-draws the view's contents.
func (v *View) draw() error {
	maxX, maxY := v.Size()
	y := 0
	for i, line := range v.lines {
		if i < v.oy {
			continue
		}
		x := 0
		for j, ch := range line {
			if j < v.ox {
				continue
			}
			if x >= 0 && x < maxX && y >= 0 && y < maxY {
				if err := v.setRune(x, y, ch); err != nil {
					return err
				}
			}
			x++
		}
		y++
	}
	return nil
}

// Clear empties the view's internal buffer.
func (v *View) Clear() {
	v.lines = nil
	v.clearRunes()
}

// clearRunes erases all the cells in the view.
func (v *View) clearRunes() {
	maxX, maxY := v.Size()
	for x := 0; x < maxX; x++ {
		for y := 0; y < maxY; y++ {
			termbox.SetCell(v.x0+x+1, v.y0+y+1, ' ',
				termbox.Attribute(v.fgColor), termbox.Attribute(v.bgColor))
		}
	}
}

// writeRune writes a rune into the view's internal buffer, at the
// position corresponding to the point (x, y). The length of the internal
// buffer is increased if the point is out of bounds. Overwrite mode is
// governed by the value of View.overwrite.
func (v *View) writeRune(x, y int, ch rune) error {
	x = v.ox + x
	y = v.oy + y

	if x < 0 || y < 0 {
		return errors.New("invalid point")
	}

	if y >= len(v.lines) {
		if y >= cap(v.lines) {
			s := make([][]rune, y+1, (y+1)*2)
			copy(s, v.lines)
			v.lines = s
		} else {
			v.lines = v.lines[:y+1]
		}
	}
	if v.lines[y] == nil {
		v.lines[y] = make([]rune, x+1, (x+1)*2)
	} else if x >= len(v.lines[y]) {
		if x >= cap(v.lines[y]) {
			s := make([]rune, x+1, (x+1)*2)
			copy(s, v.lines[y])
			v.lines[y] = s
		} else {
			v.lines[y] = v.lines[y][:x+1]
		}
	}
	if !v.overwrite {
		v.lines[y] = append(v.lines[y], ' ')
		copy(v.lines[y][x+1:], v.lines[y][x:])
	}
	v.lines[y][x] = ch
	return nil
}

// deleteRune removes a rune from the view's internal buffer, at the
// position corresponding to the point (x, y).
func (v *View) deleteRune(x, y int) error {
	x = v.ox + x
	y = v.oy + y

	if x < 0 || y < 0 || y >= len(v.lines) || v.lines[y] == nil || x >= len(v.lines[y]) {
		return errors.New("invalid point")
	}
	copy(v.lines[y][x:], v.lines[y][x+1:])
	v.lines[y][len(v.lines[y])-1] = ' '
	return nil
}

// addLine adds a line into the view's internal buffer at the position
// corresponding to the point (x, y).
func (v *View) addLine(y int) error {
	y = v.oy + y

	if y < 0 || y >= len(v.lines) {
		return errors.New("invalid point")
	}
	v.lines = append(v.lines, nil)
	copy(v.lines[y+1:], v.lines[y:])
	v.lines[y] = nil
	return nil
}

// Line returns a string with the line of the view's internal buffer
// at the position corresponding to the point (x, y).
func (v *View) Line(y int) (string, error) {
	y = v.oy + y

	if y < 0 || y >= len(v.lines) {
		return "", errors.New("invalid point")
	}
	return string(v.lines[y]), nil
}

// Word returns a string with the word of the view's internal buffer
// at the position corresponding to the point (x, y).
func (v *View) Word(x, y int) (string, error) {
	x = v.ox + x
	y = v.oy + y

	if y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
		return "", errors.New("invalid point")
	}
	l := string(v.lines[y])
	nl := strings.LastIndex(l[:x], " ")
	if nl == -1 {
		nl = 0
	} else {
		nl = nl + 1
	}
	nr := strings.Index(l[x:], " ")
	if nr == -1 {
		nr = len(l)
	} else {
		nr = nr + x
	}
	return string(l[nl:nr]), nil
}
<|endoftext|>