<commit_before>package tui

import (
	"image"
	"math"
)

var _ Widget = &Box{}

// Alignment is used to set the direction in which widgets are laid out.
type Alignment int

// Available alignment options.
const (
	Horizontal Alignment = iota
	Vertical
)

// Box is a layout for placing widgets either horizontally or vertically. If
// horizontally, all widgets will have the same height. If vertically, they
// will all have the same width.
type Box struct {
	WidgetBase

	children []Widget

	border bool
	title  string

	alignment Alignment
}

// NewVBox returns a new vertically aligned Box.
func NewVBox(c ...Widget) *Box {
	return &Box{
		children:  c,
		alignment: Vertical,
	}
}

// NewHBox returns a new horizontally aligned Box.
func NewHBox(c ...Widget) *Box {
	return &Box{
		children:  c,
		alignment: Horizontal,
	}
}

// Append adds the given widget at the end of the Box.
func (b *Box) Append(w Widget) {
	b.children = append(b.children, w)
}

// Prepend adds the given widget at the start of the Box.
func (b *Box) Prepend(w Widget) {
	b.children = append([]Widget{w}, b.children...)
}

// Insert adds the widget into the Box at a given index.
func (b *Box) Insert(i int, w Widget) {
	if len(b.children) < i || i < 0 {
		return
	}

	b.children = append(b.children, nil)
	copy(b.children[i+1:], b.children[i:])
	b.children[i] = w
}

// Remove deletes the widget from the Box at a given index.
func (b *Box) Remove(i int) {
	if len(b.children) <= i || i < 0 {
		return
	}

	b.children = append(b.children[:i], b.children[i+1:]...)
}

// Length returns the number of items in the box.
func (b *Box) Length() int {
	return len(b.children)
}

// SetBorder sets whether the border is visible or not.
func (b *Box) SetBorder(enabled bool) {
	b.border = enabled
}

// SetTitle sets the title of the box.
func (b *Box) SetTitle(title string) {
	b.title = title
}

// Alignment returns the current alignment of the Box.
func (b *Box) Alignment() Alignment {
	return b.alignment
}

// IsFocused return true if one of the children is focused.
func (b *Box) IsFocused() bool {
	for _, w := range b.children {
		if w.IsFocused() {
			return true
		}
	}
	return false
}

// Draw recursively draws the widgets it contains.
func (b *Box) Draw(p *Painter) {
	style := "box"
	if b.IsFocused() {
		style += ".focused"
	}

	sz := b.Size()

	if b.border {
		p.WithStyle(style+".border", func(p *Painter) {
			p.DrawRect(0, 0, sz.X, sz.Y)
		})
		p.WithStyle(style, func(p *Painter) {
			p.WithMask(image.Rect(0, 0, sz.X-1, 1), func(p *Painter) {
				p.DrawText(1, 0, b.title)
			})
		})
		p.Translate(1, 1)
		defer p.Restore()
	}

	var off image.Point
	for _, child := range b.children {
		switch b.Alignment() {
		case Horizontal:
			p.Translate(off.X, 0)
		case Vertical:
			p.Translate(0, off.Y)
		}

		p.WithMask(image.Rectangle{
			Min: image.ZP,
			Max: child.Size(),
		}, func(p *Painter) {
			child.Draw(p)
		})

		p.Restore()

		off = off.Add(child.Size())
	}
}

// MinSizeHint returns the minimum size hint for the layout.
func (b *Box) MinSizeHint() image.Point {
	var minSize image.Point

	for _, child := range b.children {
		size := child.MinSizeHint()
		if b.Alignment() == Horizontal {
			minSize.X += size.X
			if size.Y > minSize.Y {
				minSize.Y = size.Y
			}
		} else {
			minSize.Y += size.Y
			if size.X > minSize.X {
				minSize.X = size.X
			}
		}
	}

	if b.border {
		minSize = minSize.Add(image.Point{2, 2})
	}

	return minSize
}

// SizeHint returns the recommended size hint for the layout.
func (b *Box) SizeHint() image.Point {
	var sizeHint image.Point

	for _, child := range b.children {
		size := child.SizeHint()
		if b.Alignment() == Horizontal {
			sizeHint.X += size.X
			if size.Y > sizeHint.Y {
				sizeHint.Y = size.Y
			}
		} else {
			sizeHint.Y += size.Y
			if size.X > sizeHint.X {
				sizeHint.X = size.X
			}
		}
	}

	if b.border {
		sizeHint = sizeHint.Add(image.Point{2, 2})
	}

	return sizeHint
}

// OnKeyEvent handles an event and propagates it to all children.
func (b *Box) OnKeyEvent(ev KeyEvent) {
	for _, child := range b.children {
		child.OnKeyEvent(ev)
	}
}

// Resize recursively updates the size of the Box and all the widgets it
// contains. This is a potentially expensive operation and should be invoked
// with restraint.
//
// Resize is called by the layout engine and is not intended to be used by end
// users.
func (b *Box) Resize(size image.Point) {
	b.size = size
	inner := b.size
	if b.border {
		inner = b.size.Sub(image.Point{2, 2})
	}
	b.layoutChildren(inner)
}

func (b *Box) layoutChildren(size image.Point) {
	space := doLayout(b.children, dim(b.Alignment(), size), b.Alignment())

	for i, s := range space {
		switch b.Alignment() {
		case Horizontal:
			b.children[i].Resize(image.Point{s, size.Y})
		case Vertical:
			b.children[i].Resize(image.Point{size.X, s})
		}
	}
}

func doLayout(ws []Widget, space int, a Alignment) []int {
	sizes := make([]int, len(ws))

	if len(sizes) == 0 {
		return sizes
	}

	remaining := space

	// Distribute MinSizeHint
	for {
		var changed bool
		for i, sz := range sizes {
			if sz < dim(a, ws[i].MinSizeHint()) {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

	// Distribute Minimum
	for {
		var changed bool
		for i, sz := range sizes {
			p := alignedSizePolicy(a, ws[i])
			if p == Minimum && sz < dim(a, ws[i].SizeHint()) {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

	// Distribute Preferred
	for {
		var changed bool
		for i, sz := range sizes {
			p := alignedSizePolicy(a, ws[i])
			if (p == Preferred || p == Maximum) && sz < dim(a, ws[i].SizeHint()) {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

	// Distribute Expanding
	for {
		var changed bool
		for i, sz := range sizes {
			p := alignedSizePolicy(a, ws[i])
			if p == Expanding {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

	// Distribute remaining space
	for {
		min := math.MaxInt8
		for i, s := range sizes {
			p := alignedSizePolicy(a, ws[i])
			if (p == Preferred || p == Minimum) && s <= min {
				min = s
			}
		}
		var changed bool
		for i, sz := range sizes {
			if sz != min {
				continue
			}
			p := alignedSizePolicy(a, ws[i])
			if p == Preferred || p == Minimum {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

Resize:

	return sizes
}

func dim(a Alignment, pt image.Point) int {
	if a == Horizontal {
		return pt.X
	}
	return pt.Y
}

func alignedSizePolicy(a Alignment, w Widget) SizePolicy {
	hpol, vpol := w.SizePolicy()
	if a == Horizontal {
		return hpol
	}
	return vpol
}
<commit_msg>Make Box have a base style of 'box'<commit_after>package tui

import (
	"image"
	"math"
)

var _ Widget = &Box{}

// Alignment is used to set the direction in which widgets are laid out.
type Alignment int

// Available alignment options.
const (
	Horizontal Alignment = iota
	Vertical
)

// Box is a layout for placing widgets either horizontally or vertically. If
// horizontally, all widgets will have the same height. If vertically, they
// will all have the same width.
type Box struct {
	WidgetBase

	children []Widget

	border bool
	title  string

	alignment Alignment
}

// NewVBox returns a new vertically aligned Box.
func NewVBox(c ...Widget) *Box {
	return &Box{
		children:  c,
		alignment: Vertical,
	}
}

// NewHBox returns a new horizontally aligned Box.
func NewHBox(c ...Widget) *Box {
	return &Box{
		children:  c,
		alignment: Horizontal,
	}
}

// Append adds the given widget at the end of the Box.
func (b *Box) Append(w Widget) {
	b.children = append(b.children, w)
}

// Prepend adds the given widget at the start of the Box.
func (b *Box) Prepend(w Widget) {
	b.children = append([]Widget{w}, b.children...)
}

// Insert adds the widget into the Box at a given index.
func (b *Box) Insert(i int, w Widget) {
	if len(b.children) < i || i < 0 {
		return
	}

	b.children = append(b.children, nil)
	copy(b.children[i+1:], b.children[i:])
	b.children[i] = w
}

// Remove deletes the widget from the Box at a given index.
func (b *Box) Remove(i int) {
	if len(b.children) <= i || i < 0 {
		return
	}

	b.children = append(b.children[:i], b.children[i+1:]...)
}

// Length returns the number of items in the box.
func (b *Box) Length() int {
	return len(b.children)
}

// SetBorder sets whether the border is visible or not.
func (b *Box) SetBorder(enabled bool) {
	b.border = enabled
}

// SetTitle sets the title of the box.
func (b *Box) SetTitle(title string) {
	b.title = title
}

// Alignment returns the current alignment of the Box.
func (b *Box) Alignment() Alignment {
	return b.alignment
}

// IsFocused return true if one of the children is focused.
func (b *Box) IsFocused() bool {
	for _, w := range b.children {
		if w.IsFocused() {
			return true
		}
	}
	return false
}

// Draw recursively draws the widgets it contains.
func (b *Box) Draw(p *Painter) {
	style := "box"
	if b.IsFocused() {
		style += ".focused"
	}

	p.WithStyle(style, func(p *Painter) {

		sz := b.Size()

		if b.border {
			p.WithStyle(style+".border", func(p *Painter) {
				p.DrawRect(0, 0, sz.X, sz.Y)
			})
			p.WithStyle(style, func(p *Painter) {
				p.WithMask(image.Rect(0, 0, sz.X-1, 1), func(p *Painter) {
					p.DrawText(1, 0, b.title)
				})
			})
			p.Translate(1, 1)
			defer p.Restore()
		}

		var off image.Point
		for _, child := range b.children {
			switch b.Alignment() {
			case Horizontal:
				p.Translate(off.X, 0)
			case Vertical:
				p.Translate(0, off.Y)
			}

			p.WithMask(image.Rectangle{
				Min: image.ZP,
				Max: child.Size(),
			}, func(p *Painter) {
				child.Draw(p)
			})

			p.Restore()

			off = off.Add(child.Size())
		}
	})
}

// MinSizeHint returns the minimum size hint for the layout.
func (b *Box) MinSizeHint() image.Point {
	var minSize image.Point

	for _, child := range b.children {
		size := child.MinSizeHint()
		if b.Alignment() == Horizontal {
			minSize.X += size.X
			if size.Y > minSize.Y {
				minSize.Y = size.Y
			}
		} else {
			minSize.Y += size.Y
			if size.X > minSize.X {
				minSize.X = size.X
			}
		}
	}

	if b.border {
		minSize = minSize.Add(image.Point{2, 2})
	}

	return minSize
}

// SizeHint returns the recommended size hint for the layout.
func (b *Box) SizeHint() image.Point {
	var sizeHint image.Point

	for _, child := range b.children {
		size := child.SizeHint()
		if b.Alignment() == Horizontal {
			sizeHint.X += size.X
			if size.Y > sizeHint.Y {
				sizeHint.Y = size.Y
			}
		} else {
			sizeHint.Y += size.Y
			if size.X > sizeHint.X {
				sizeHint.X = size.X
			}
		}
	}

	if b.border {
		sizeHint = sizeHint.Add(image.Point{2, 2})
	}

	return sizeHint
}

// OnKeyEvent handles an event and propagates it to all children.
func (b *Box) OnKeyEvent(ev KeyEvent) {
	for _, child := range b.children {
		child.OnKeyEvent(ev)
	}
}

// Resize recursively updates the size of the Box and all the widgets it
// contains. This is a potentially expensive operation and should be invoked
// with restraint.
//
// Resize is called by the layout engine and is not intended to be used by end
// users.
func (b *Box) Resize(size image.Point) {
	b.size = size
	inner := b.size
	if b.border {
		inner = b.size.Sub(image.Point{2, 2})
	}
	b.layoutChildren(inner)
}

func (b *Box) layoutChildren(size image.Point) {
	space := doLayout(b.children, dim(b.Alignment(), size), b.Alignment())

	for i, s := range space {
		switch b.Alignment() {
		case Horizontal:
			b.children[i].Resize(image.Point{s, size.Y})
		case Vertical:
			b.children[i].Resize(image.Point{size.X, s})
		}
	}
}

func doLayout(ws []Widget, space int, a Alignment) []int {
	sizes := make([]int, len(ws))

	if len(sizes) == 0 {
		return sizes
	}

	remaining := space

	// Distribute MinSizeHint
	for {
		var changed bool
		for i, sz := range sizes {
			if sz < dim(a, ws[i].MinSizeHint()) {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

	// Distribute Minimum
	for {
		var changed bool
		for i, sz := range sizes {
			p := alignedSizePolicy(a, ws[i])
			if p == Minimum && sz < dim(a, ws[i].SizeHint()) {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

	// Distribute Preferred
	for {
		var changed bool
		for i, sz := range sizes {
			p := alignedSizePolicy(a, ws[i])
			if (p == Preferred || p == Maximum) && sz < dim(a, ws[i].SizeHint()) {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

	// Distribute Expanding
	for {
		var changed bool
		for i, sz := range sizes {
			p := alignedSizePolicy(a, ws[i])
			if p == Expanding {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

	// Distribute remaining space
	for {
		min := math.MaxInt8
		for i, s := range sizes {
			p := alignedSizePolicy(a, ws[i])
			if (p == Preferred || p == Minimum) && s <= min {
				min = s
			}
		}
		var changed bool
		for i, sz := range sizes {
			if sz != min {
				continue
			}
			p := alignedSizePolicy(a, ws[i])
			if p == Preferred || p == Minimum {
				sizes[i] = sz + 1
				remaining--
				if remaining <= 0 {
					goto Resize
				}
				changed = true
			}
		}
		if !changed {
			break
		}
	}

Resize:

	return sizes
}

func dim(a Alignment, pt image.Point) int {
	if a == Horizontal {
		return pt.X
	}
	return pt.Y
}

func alignedSizePolicy(a Alignment, w Widget) SizePolicy {
	hpol, vpol := w.SizePolicy()
	if a == Horizontal {
		return hpol
	}
	return vpol
}
<|endoftext|>


<commit_before>package gocct

import (
	"reflect"
)

type Tree interface {
	// Returns the root node of the tree
	Root() Node
	// Adds a child to the provided parent.
	// Returns true, nil if added successfully,
	// false, current parent if
	// the node already exists in the tree
	Add(parent Node, child Node) (success bool, otherParent Node)
	// Get the parent of the provided node
	Parent(child Node) (parent Node)
	// Depth first walk of the tree calling the provided function for each node visited
	Walk(func(depth int, node Node))

	// Remove(node Node) (bool)
	// GoWalk() chan<- Visit
	// Children(parent Node) []Node
	//
}

type Visit struct {
	N Node
	I int
}

// Node, an interface{} type store in the tree.
// Tider then writing interface{} everywhere
type Node interface{}

// Fluent API for building a tree
type Builder interface {
	Add(n Node) Builder
	Down() Builder
	Up() Builder
	Build() Tree
}

// Create a new tree with a hidden root and return the root and the tree
func NewTree() (Tree, Node) {
	t := &ctree{
		make(map[Node][]Node),
		make(map[Node]Node),
		new(interface{}),
		true,
	}
	t.c2[t.root] = nil
	return t, t.root
}

// Creates a tree that allow non pointer node.
// Client beware, do not mutate object or pass non keyable objects
func NewTree_MutableNodes() (Tree, Node) {
	t := &ctree{
		make(map[Node][]Node),
		make(map[Node]Node),
		new(interface{}),
		false,
	}
	t.c2[(Node)(t.root)] = nil
	return (Tree)(t), t.root
}

// The internal structure of the centralised tree
type ctree struct {
	// Map of parent to slice of children
	p2 map[Node][]Node
	// Map of child to parent
	c2 map[Node]Node
	// Hidden root node of the tree
	root    Node
	ptrOnly bool
}

// Add a child to a parent and create the p2c and c2p pointers
// If the child already exists anywhere in the tree the operations fails and the
// existing parent is returned with the boolean status
func (t *ctree) Add(p Node, c Node) (bool, Node) {
	if t.ptrOnly {
		if reflect.TypeOf(c).Kind() != reflect.Ptr {
			panic("Child node is not a pointer")
		}
		if reflect.TypeOf(p).Kind() != reflect.Ptr {
			panic("Parent node is not a pointer")
		}
	}
	if orginal, exist := t.c2[c]; exist {
		return false, orginal
	}
	t.p2[p] = append(t.p2[p], c)
	t.c2[c] = p
	return true, nil
}

func (t *ctree) Parent(c Node) Node {
	return t.c2[c]
}

// A depth first walk of the tree calling the provided function at each node
func (t *ctree) Walk(f func(int, Node)) {
	for _, o := range t.p2[t.root] {
		walk(t, o, 0, f)
	}
}

func walk(t *ctree, node Node, depth int, f func(int, Node)) {
	f(depth, node)
	for _, o := range t.p2[node] {
		walk(t, o, depth+1, f)
	}
}

// Return the root of the tree
func (t *ctree) Root() Node {
	return t.root
}

// Builder's state
type builder struct {
	tree Tree
	curr Node
	last Node
}

func BuildTree() Builder {
	t, r := NewTree()
	b := &builder{t, r, nil}
	return b
}
func BuildTree_MutableNodes() Builder {
	t, r := NewTree_MutableNodes()
	b := &builder{t, r, nil}
	return b
}
func (b *builder) Add(n Node) Builder {
	ok, _ := b.tree.Add(b.curr, n)
	if ok {
		b.last = n
	}
	return b
}
func (b *builder) Down() Builder {
	b.curr = b.last
	return b
}
func (b *builder) Up() Builder {
	b.curr = b.tree.Parent(b.curr)
	b.last = b.curr
	return b
}
func (b *builder) Build() Tree {
	return b.tree
}
<commit_msg>Added get children method<commit_after>package gocct

import (
	"reflect"
)

type Tree interface {
	// Returns the root node of the tree
	Root() Node
	// Adds a child to the provided parent.
	// Returns true, nil if added successfully,
	// false, current parent if
	// the node already exists in the tree
	Add(parent Node, child Node) (success bool, otherParent Node)
	// Get the parent of the provided node
	Parent(child Node) (parent Node)
	// Depth first walk of the tree calling the provided function for each node visited
	Walk(func(depth int, node Node))

	// Remove(node Node) (bool)
	// GoWalk() chan<- Visit

	// Children of parent
	Children(parent Node) []Node
	//
}

type Visit struct {
	N Node
	I int
}

// Node, an interface{} type store in the tree.
// Tider then writing interface{} everywhere
type Node interface{}

// Fluent API for building a tree
type Builder interface {
	Add(n Node) Builder
	Down() Builder
	Up() Builder
	Build() Tree
}

// Create a new tree with a hidden root and return the root and the tree
func NewTree() (Tree, Node) {
	t := &ctree{
		make(map[Node][]Node),
		make(map[Node]Node),
		new(interface{}),
		true,
	}
	t.c2[t.root] = nil
	return t, t.root
}

// Creates a tree that allow non pointer node.
// Client beware, do not mutate object or pass non keyable objects
func NewTree_MutableNodes() (Tree, Node) {
	t := &ctree{
		make(map[Node][]Node),
		make(map[Node]Node),
		new(interface{}),
		false,
	}
	t.c2[(Node)(t.root)] = nil
	return (Tree)(t), t.root
}

// The internal structure of the centralised tree
type ctree struct {
	// Map of parent to slice of children
	p2 map[Node][]Node
	// Map of child to parent
	c2 map[Node]Node
	// Hidden root node of the tree
	root    Node
	ptrOnly bool
}

// Add a child to a parent and create the p2c and c2p pointers
// If the child already exists anywhere in the tree the operations fails and the
// existing parent is returned with the boolean status
func (t *ctree) Add(p Node, c Node) (bool, Node) {
	if t.ptrOnly {
		if reflect.TypeOf(c).Kind() != reflect.Ptr {
			panic("Child node is not a pointer")
		}
		if reflect.TypeOf(p).Kind() != reflect.Ptr {
			panic("Parent node is not a pointer")
		}
	}
	if orginal, exist := t.c2[c]; exist {
		return false, orginal
	}
	t.p2[p] = append(t.p2[p], c)
	t.c2[c] = p
	return true, nil
}

func (t *ctree) Parent(c Node) Node {
	return t.c2[c]
}

func (t *ctree) Children(p Node) []Node {
	return t.p2[p]
}

// A depth first walk of the tree calling the provided function at each node
func (t *ctree) Walk(f func(int, Node)) {
	for _, o := range t.p2[t.root] {
		walk(t, o, 0, f)
	}
}

func walk(t *ctree, node Node, depth int, f func(int, Node)) {
	f(depth, node)
	for _, o := range t.p2[node] {
		walk(t, o, depth+1, f)
	}
}

// Return the root of the tree
func (t *ctree) Root() Node {
	return t.root
}

// Builder's state
type builder struct {
	tree Tree
	curr Node
	last Node
}

func BuildTree() Builder {
	t, r := NewTree()
	b := &builder{t, r, nil}
	return b
}
func BuildTree_MutableNodes() Builder {
	t, r := NewTree_MutableNodes()
	b := &builder{t, r, nil}
	return b
}
func (b *builder) Add(n Node) Builder {
	ok, _ := b.tree.Add(b.curr, n)
	if ok {
		b.last = n
	}
	return b
}
func (b *builder) Down() Builder {
	b.curr = b.last
	return b
}
func (b *builder) Up() Builder {
	b.curr = b.tree.Parent(b.curr)
	b.last = b.curr
	return b
}
func (b *builder) Build() Tree {
	return b.tree
}
<|endoftext|>


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

// Package cli provides base constructs to build complex command line
// applications.
//
// By nesting components, one can build command line applications like: the
// go command.
//
package cli

import (
	"bytes"
	"context"
	"flag"
	"io"
	"strings"
	"text/template"
)

// Component represents a command line component
type Component struct {
	// Components are the sub-components of the current component
	Components []*Component

	// Run runs the component
	// args are the arguments after the component name
	Run func(ctx context.Context, comp *Component, args []string)

	// UsageLine is the one-line usage message.
	// The first word in the line is taken to be the component name
	UsageLine string

	// Short is the short description of the component
	Short string

	// Long is the longer more detailed description of the component
	Long string

	// flagSet is a set of flags specific to this component
	flagSet *flag.FlagSet
}

// FlagSet returns the set of command line flags
func (c *Component) FlagSet() *flag.FlagSet {
	if nil == c.flagSet {
		c.flagSet = flag.NewFlagSet(c.Name(), flag.ExitOnError)
		c.flagSet.Usage = c.Usage
	}

	return c.flagSet
}

// Name returns the name of the component: the first word in the UsageLine
func (c *Component) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

// Runnable returns whether this component is runnable or pure informational
func (c *Component) Runnable() bool {
	return nil != c.Run
}

// SetOutput sets the destination for usage messages.
// If output is nil, stderr is used
func (c *Component) SetOutput(output io.Writer) {
	c.FlagSet().SetOutput(output)
}

var usageTemplate = `
{{- if .component.Runnable -}}
Usage: {{.component.UsageLine}}
{{end}}
{{- if ne (len .component.Long) 0 -}}
{{.component.Long | trim}}
{{end}}
{{- if ne (len .component.Components) 0}}
The components are:
{{- range .component.Components}}
{{- if .Runnable}}
  {{.Name | printf "%-11s"}} {{.Short -}}
{{end -}}
{{end}}
{{end}}
{{- if ne (len .flags) 0}}
The flags are:
{{.flags -}}
{{end}}`

// Usage prints out the usage information
func (c *Component) Usage() {
	flagSet := c.FlagSet()
	output := flagSet.Output()

	// Capture the output of the flagset so that it can be merged with the rest
	// of the message
	var buf bytes.Buffer
	flagSet.SetOutput(&buf)
	flagSet.PrintDefaults()

	flagSet.SetOutput(output)

	tmpl(output, usageTemplate, map[string]interface{}{
		"component": c,
		"flags":     buf.String(),
	})
}

// Passthrough is a implementation of the Run function that passes the
// execution through the sub commands
func Passthrough(ctx context.Context, component *Component, args []string) {
	flagSet := component.FlagSet()

	if flag.ErrHelp == flagSet.Parse(args) {
		return
	}

	if flagSet.NArg() < 1 {
		flagSet.Usage()
		return
	}

	name := flagSet.Arg(0)

	for _, comp := range component.Components {
		if name == comp.Name() {
			if comp.Runnable() {
				comp.Run(ctx, comp, flagSet.Args()[1:])
				return
			}
		}
	}
	flagSet.Usage()
}

func tmpl(w io.Writer, text string, data interface{}) {
	t := template.New("top")
	t.Funcs(template.FuncMap{
		"trim": strings.TrimSpace,
	})
	template.Must(t.Parse(text))
	t.Execute(w, data)
}
<commit_msg>SetOutput also sets the output of all sub components.<commit_after>// Copyright (c) 2017 Qian Qiao
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package cli provides base constructs to build complex command line
// applications.
//
// By nesting components, one can build command line applications like: the
// go command.
//
package cli

import (
	"bytes"
	"context"
	"flag"
	"io"
	"strings"
	"text/template"
)

// Component represents a command line component
type Component struct {
	// Components are the sub-components of the current component
	Components []*Component

	// Run runs the component
	// args are the arguments after the component name
	Run func(ctx context.Context, comp *Component, args []string)

	// UsageLine is the one-line usage message.
	// The first word in the line is taken to be the component name
	UsageLine string

	// Short is the short description of the component
	Short string

	// Long is the longer more detailed description of the component
	Long string

	// flagSet is a set of flags specific to this component
	flagSet *flag.FlagSet
}

// FlagSet returns the set of command line flags
func (c *Component) FlagSet() *flag.FlagSet {
	if nil == c.flagSet {
		c.flagSet = flag.NewFlagSet(c.Name(), flag.ExitOnError)
		c.flagSet.Usage = c.Usage
	}

	return c.flagSet
}

// Name returns the name of the component: the first word in the UsageLine
func (c *Component) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

// Runnable returns whether this component is runnable or pure informational
func (c *Component) Runnable() bool {
	return nil != c.Run
}

// SetOutput sets the destination for usage messages.
// If output is nil, stderr is used
func (c *Component) SetOutput(output io.Writer) {
	c.FlagSet().SetOutput(output)

	for _, c := range c.Components {
		c.SetOutput(output)
	}
}

var usageTemplate = `
{{- if .component.Runnable -}}
Usage: {{.component.UsageLine}}
{{end}}
{{- if ne (len .component.Long) 0 -}}
{{.component.Long | trim}}
{{end}}
{{- if ne (len .component.Components) 0}}
The components are:
{{- range .component.Components}}
{{- if .Runnable}}
  {{.Name | printf "%-11s"}} {{.Short -}}
{{end -}}
{{end}}
{{end}}
{{- if ne (len .flags) 0}}
The flags are:
{{.flags -}}
{{end}}`

// Usage prints out the usage information
func (c *Component) Usage() {
	flagSet := c.FlagSet()
	output := flagSet.Output()

	// Capture the output of the flagset so that it can be merged with the rest
	// of the message
	var buf bytes.Buffer
	flagSet.SetOutput(&buf)
	flagSet.PrintDefaults()

	flagSet.SetOutput(output)

	tmpl(output, usageTemplate, map[string]interface{}{
		"component": c,
		"flags":     buf.String(),
	})
}

// Passthrough is a implementation of the Run function that passes the
// execution through the sub commands
func Passthrough(ctx context.Context, comp *Component, args []string) {
	flagSet := comp.FlagSet()

	if flag.ErrHelp == flagSet.Parse(args) {
		return
	}

	if flagSet.NArg() < 1 {
		flagSet.Usage()
		return
	}

	name := flagSet.Arg(0)

	for _, c := range comp.Components {
		if name == c.Name() {
			if c.Runnable() {
				c.Run(ctx, c, flagSet.Args()[1:])
				return
			}
		}
	}
	flagSet.Usage()
}

func tmpl(w io.Writer, text string, data interface{}) {
	t := template.New("top")
	t.Funcs(template.FuncMap{
		"trim": strings.TrimSpace,
	})
	template.Must(t.Parse(text))
	t.Execute(w, data)
}
<|endoftext|>


<commit_before>package peco

import (
	"fmt"
	"os"
	"reflect"
	"runtime"

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

type cmdOptions struct {
	OptHelp           bool   `short:"h" long:"help" description:"show this help message and exit"`
	OptTTY            string `long:"tty" description:"path to the TTY (usually, the value of $TTY)"`
	OptQuery          string `long:"query" description:"initial value for query"`
	OptRcfile         string `long:"rcfile" description:"path to the settings file"`
	OptNoIgnoreCase   bool   `long:"no-ignore-case" description:"start in case-sensitive-mode (DEPRECATED)" default:"false"`
	OptVersion        bool   `long:"version" description:"print the version and exit"`
	OptBufferSize     int    `long:"buffer-size" short:"b" description:"number of lines to keep in search buffer"`
	OptEnableNullSep  bool   `long:"null" description:"expect NUL (\\0) as separator for target/output"`
	OptInitialIndex   int    `long:"initial-index" description:"position of the initial index of the selection (0 base)"`
	OptInitialMatcher string `long:"initial-matcher" description:"specify the default matcher"`
	OptPrompt         string `long:"prompt" description:"specify the prompt string"`
	OptLayout         string `long:"layout" description:"layout to be used 'top-down' (default) or 'bottom-up'" default:"top-down"`
}

func showHelp() {
	// The ONLY reason we're not using go-flags' help option is
	// because I wanted to tweak the format just a bit... but
	// there wasn't an easy way to do so
	os.Stderr.WriteString(`
Usage: peco [options] [FILE]

Options:
`)

	t := reflect.TypeOf(cmdOptions{})
	for i := 0; i < t.NumField(); i++ {
		tag := t.Field(i).Tag

		var o string
		if s := tag.Get("short"); s != "" {
			o = fmt.Sprintf("-%s, --%s", tag.Get("short"), tag.Get("long"))
		} else {
			o = fmt.Sprintf("--%s", tag.Get("long"))
		}

		fmt.Fprintf(
			os.Stderr,
			"  %-21s %s\n",
			o,
			tag.Get("description"),
		)
	}
}

// BufferSize returns the specified buffer size. Fulfills CtxOptions
func (o cmdOptions) BufferSize() int {
	return o.OptBufferSize
}

// EnableNullSep returns tru if --null was specified. Fulfills CtxOptions
func (o cmdOptions) EnableNullSep() bool {
	return o.OptEnableNullSep
}

func (o cmdOptions) InitialIndex() int {
	if o.OptInitialIndex >= 0 {
		return o.OptInitialIndex + 1
	}
	return 1
}

func (o cmdOptions) LayoutType() string {
	return o.OptLayout
}

type CLI struct {
}

func (cli *CLI) Run() error {
	opts := &cmdOptions{}
	p := flags.NewParser(opts, flags.PrintErrors)
	args, err := p.Parse()
	if err != nil {
		showHelp()
		return err
	}

	if opts.OptLayout != "" {
		if !IsValidLayoutType(LayoutType(opts.OptLayout)) {
			return fmt.Errorf("unknown layout: '%s'\n", opts.OptLayout)
		}
	}

	if opts.OptHelp {
		showHelp()
		return nil
	}

	if opts.OptVersion {
		fmt.Fprintf(os.Stderr, "peco: %s\n", version)
		return nil
	}

	var in *os.File

	// receive in from either a file or Stdin
	switch {
	case len(args) > 0:
		in, err = os.Open(args[0])
		if err != nil {
			return err
		}
	case !IsTty(os.Stdin.Fd()):
		in = os.Stdin
	default:
		return fmt.Errorf("You must supply something to work with via filename or stdin")
	}

	ctx := NewCtx(opts)
	defer func() {
		ch := ctx.ResultCh()
		if ch == nil {
			return
		}

		for match := range ch {
			line := match.Output()
			if line[len(line)-1] != '\n' {
				line = line + "\n"
			}
			fmt.Fprint(os.Stdout, line)
		}
	}()

	if opts.OptRcfile == "" {
		file, err := LocateRcfile()
		if err == nil {
			opts.OptRcfile = file
		}
	}

	// Default matcher is IgnoreCase
	ctx.MatcherSet.SetCurrentByName(IgnoreCaseMatch)

	if opts.OptRcfile != "" {
		err = ctx.ReadConfig(opts.OptRcfile)
		if err != nil {
			return err
		}
	}

	if len(opts.OptPrompt) > 0 {
		ctx.SetPrompt(opts.OptPrompt)
	}

	// Deprecated. --no-ignore-case options will be removed in later.
	if opts.OptNoIgnoreCase {
		ctx.MatcherSet.SetCurrentByName(CaseSensitiveMatch)
	}

	if len(opts.OptInitialMatcher) > 0 {
		if !ctx.MatcherSet.SetCurrentByName(opts.OptInitialMatcher) {
			return fmt.Errorf("unknown matcher: '%s'\n", opts.OptInitialMatcher)
		}
	}

	// Try waiting for something available in the source stream
	// before doing any terminal initialization (also done by termbox)
	reader := ctx.NewBufferReader(in)
	ctx.AddWaitGroup(1)
	go reader.Loop()

	// This channel blocks until we receive something from `in`
	<-reader.InputReadyCh()

	err = TtyReady()
	if err != nil {
		return err
	}
	defer TtyTerm()

	err = termbox.Init()
	if err != nil {
		return err
	}
	defer termbox.Close()

	// Windows handle Esc/Alt self
	if runtime.GOOS == "windows" {
		termbox.SetInputMode(termbox.InputEsc | termbox.InputAlt)
	}

	view := ctx.NewView()
	filter := ctx.NewFilter()
	input := ctx.NewInput()
	sig := ctx.NewSignalHandler()

	loopers := []interface {
		Loop()
	}{
		view,
		filter,
		input,
		sig,
	}
	for _, looper := range loopers {
		ctx.AddWaitGroup(1)
		go looper.Loop()
	}

	if len(opts.OptQuery) > 0 {
		ctx.SetQuery([]rune(opts.OptQuery))
		ctx.ExecQuery()
	} else {
		ctx.SendDraw(nil)
	}

	ctx.WaitDone()

	return ctx.Error()
}
<commit_msg>Rename<commit_after>package peco

import (
	"fmt"
	"os"
	"reflect"
	"runtime"

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

type CLIOptions struct {
	OptHelp           bool   `short:"h" long:"help" description:"show this help message and exit"`
	OptTTY            string `long:"tty" description:"path to the TTY (usually, the value of $TTY)"`
	OptQuery          string `long:"query" description:"initial value for query"`
	OptRcfile         string `long:"rcfile" description:"path to the settings file"`
	OptNoIgnoreCase   bool   `long:"no-ignore-case" description:"start in case-sensitive-mode (DEPRECATED)" default:"false"`
	OptVersion        bool   `long:"version" description:"print the version and exit"`
	OptBufferSize     int    `long:"buffer-size" short:"b" description:"number of lines to keep in search buffer"`
	OptEnableNullSep  bool   `long:"null" description:"expect NUL (\\0) as separator for target/output"`
	OptInitialIndex   int    `long:"initial-index" description:"position of the initial index of the selection (0 base)"`
	OptInitialMatcher string `long:"initial-matcher" description:"specify the default matcher"`
	OptPrompt         string `long:"prompt" description:"specify the prompt string"`
	OptLayout         string `long:"layout" description:"layout to be used 'top-down' (default) or 'bottom-up'" default:"top-down"`
}

func showHelp() {
	// The ONLY reason we're not using go-flags' help option is
	// because I wanted to tweak the format just a bit... but
	// there wasn't an easy way to do so
	os.Stderr.WriteString(`
Usage: peco [options] [FILE]

Options:
`)

	t := reflect.TypeOf(CLIOptions{})
	for i := 0; i < t.NumField(); i++ {
		tag := t.Field(i).Tag

		var o string
		if s := tag.Get("short"); s != "" {
			o = fmt.Sprintf("-%s, --%s", tag.Get("short"), tag.Get("long"))
		} else {
			o = fmt.Sprintf("--%s", tag.Get("long"))
		}

		fmt.Fprintf(
			os.Stderr,
			"  %-21s %s\n",
			o,
			tag.Get("description"),
		)
	}
}

// BufferSize returns the specified buffer size. Fulfills CtxOptions
func (o CLIOptions) BufferSize() int {
	return o.OptBufferSize
}

// EnableNullSep returns tru if --null was specified. Fulfills CtxOptions
func (o CLIOptions) EnableNullSep() bool {
	return o.OptEnableNullSep
}

func (o CLIOptions) InitialIndex() int {
	if o.OptInitialIndex >= 0 {
		return o.OptInitialIndex + 1
	}
	return 1
}

func (o CLIOptions) LayoutType() string {
	return o.OptLayout
}

type CLI struct {
}

func (cli *CLI) parseOptions() (*CLIOptions, []string, error) {
	opts := &CLIOptions{}
	p := flags.NewParser(opts, flags.PrintErrors)
	args, err := p.Parse()
	if err != nil {
		showHelp()
		return nil, nil, err
	}

	if opts.OptLayout != "" {
		if !IsValidLayoutType(LayoutType(opts.OptLayout)) {
			return nil, nil, fmt.Errorf("unknown layout: '%s'\n", opts.OptLayout)
		}
	}

	return opts, args, nil
}

func (cli *CLI) Run() error {
	opts, args, err := cli.parseOptions()
	if err != nil {
		return err
	}

	if opts.OptHelp {
		showHelp()
		return nil
	}

	if opts.OptVersion {
		fmt.Fprintf(os.Stderr, "peco: %s\n", version)
		return nil
	}

	var in *os.File

	// receive in from either a file or Stdin
	switch {
	case len(args) > 0:
		in, err = os.Open(args[0])
		if err != nil {
			return err
		}
	case !IsTty(os.Stdin.Fd()):
		in = os.Stdin
	default:
		return fmt.Errorf("You must supply something to work with via filename or stdin")
	}

	ctx := NewCtx(opts)
	defer func() {
		ch := ctx.ResultCh()
		if ch == nil {
			return
		}

		for match := range ch {
			line := match.Output()
			if line[len(line)-1] != '\n' {
				line = line + "\n"
			}
			fmt.Fprint(os.Stdout, line)
		}
	}()

	if opts.OptRcfile == "" {
		file, err := LocateRcfile()
		if err == nil {
			opts.OptRcfile = file
		}
	}

	// Default matcher is IgnoreCase
	ctx.MatcherSet.SetCurrentByName(IgnoreCaseMatch)

	if opts.OptRcfile != "" {
		err = ctx.ReadConfig(opts.OptRcfile)
		if err != nil {
			return err
		}
	}

	if len(opts.OptPrompt) > 0 {
		ctx.SetPrompt(opts.OptPrompt)
	}

	// Deprecated. --no-ignore-case options will be removed in later.
	if opts.OptNoIgnoreCase {
		ctx.MatcherSet.SetCurrentByName(CaseSensitiveMatch)
	}

	if len(opts.OptInitialMatcher) > 0 {
		if !ctx.MatcherSet.SetCurrentByName(opts.OptInitialMatcher) {
			return fmt.Errorf("unknown matcher: '%s'\n", opts.OptInitialMatcher)
		}
	}

	// Try waiting for something available in the source stream
	// before doing any terminal initialization (also done by termbox)
	reader := ctx.NewBufferReader(in)
	ctx.AddWaitGroup(1)
	go reader.Loop()

	// This channel blocks until we receive something from `in`
	<-reader.InputReadyCh()

	err = TtyReady()
	if err != nil {
		return err
	}
	defer TtyTerm()

	err = termbox.Init()
	if err != nil {
		return err
	}
	defer termbox.Close()

	// Windows handle Esc/Alt self
	if runtime.GOOS == "windows" {
		termbox.SetInputMode(termbox.InputEsc | termbox.InputAlt)
	}

	view := ctx.NewView()
	filter := ctx.NewFilter()
	input := ctx.NewInput()
	sig := ctx.NewSignalHandler()

	loopers := []interface {
		Loop()
	}{
		view,
		filter,
		input,
		sig,
	}
	for _, looper := range loopers {
		ctx.AddWaitGroup(1)
		go looper.Loop()
	}

	if len(opts.OptQuery) > 0 {
		ctx.SetQuery([]rune(opts.OptQuery))
		ctx.ExecQuery()
	} else {
		ctx.SendDraw(nil)
	}

	ctx.WaitDone()

	return ctx.Error()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
)

var patchVersion string
var Log = logrus.New()

func init() {
	Log.Formatter = &prefixed.TextFormatter{TimestampFormat: time.RFC3339}
}

func main() {
	app := cli.NewApp()
	app.Name = "gettyup"
	app.Version = "0.0.2" + patchVersion
	app.Usage = "interact with the Getty Images ESP API"
	app.Author = "Jordan Peterson"
	app.Email = "dysolution@gmail.com"
	app.Flags = []cli.Flag{
		cli.BoolFlag{Name: "debug, D", Usage: "enable debug output"},
		cli.BoolFlag{Name: "quiet, q", Usage: "suppress pretty-printed JSON from ESP's response"},
		cli.StringFlag{Name: "key, k", Usage: "your ESP API key", EnvVar: "ESP_API_KEY"},
		cli.StringFlag{Name: "secret", Usage: "your ESP API secret", EnvVar: "ESP_API_SECRET"},
		cli.StringFlag{Name: "username, u", Usage: "your ESP username", EnvVar: "ESP_USERNAME"},
		cli.StringFlag{Name: "password, p", Usage: "your ESP password", EnvVar: "ESP_PASSWORD"},
		cli.StringFlag{Name: "token, t", Usage: "use an existing OAuth2 token", EnvVar: "ESP_TOKEN"},
		cli.StringFlag{
			Name:        "s3-bucket, b",
			Value:       "oregon",
			Usage:       "nearest S3 bucket = [germany|ireland|oregon|singapore|tokyo|virginia]",
			Destination: &uploadBucket,
			EnvVar:      "S3_BUCKET",
		},
	}
	app.Before = func(c *cli.Context) error {
		client = getClient(
			c.String("key"),
			c.String("secret"),
			c.String("username"),
			c.String("password"),
		)
		quiet = c.Bool("quiet") == true
		if c.Bool("debug") == true {
			Log.Level = logrus.DebugLevel
		}
		token = stringToToken(c.String("token"))
		return nil
	}
	app.Commands = []cli.Command{
		{
			Name:   "token",
			Usage:  "retrieve and print an OAuth2 authorization token",
			Action: func(c *cli.Context) { fmt.Println(client.Token) },
		},
		{
			Name:  "batch",
			Usage: "work with Submission Batches",
			Subcommands: []cli.Command{
				{
					Name:   "create",
					Usage:  "create a new Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Batch{c}.Create()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-name, n"},
						cli.StringFlag{Name: "submission-type, t", Usage: batchTypes},
						cli.StringFlag{Name: "note"},
						cli.StringFlag{Name: "assignment-id"},
						cli.StringFlag{Name: "brief-id"},
						cli.StringFlag{Name: "event-id"},
						cli.BoolTFlag{Name: "save-extracted-metadata"},
					},
				},
				{
					Name:   "get",
					Usage:  "get a specific Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Batch{c}.Get()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "index",
					Usage:  "get all Submission Batches",
					Action: func(c *cli.Context) { prettyPrint(Batch{c}.Index()) },
				},
				{
					Name:   "update",
					Usage:  "update an existing Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Batch{c}.Update()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "submission-name, n"},
						cli.StringFlag{Name: "note"},
					},
				},
				{
					Name:   "delete",
					Usage:  "delete an existing Submission Batch",
					Action: func(c *cli.Context) { Batch{c}.Delete() },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "last",
					Usage:  "get the most recent Submission Batch",
					Action: func(c *cli.Context) { fmt.Println(Batch{c}.Last().ID) },
				},
			},
		},
		{
			Name:  "contribution",
			Usage: "work with Contributions",
			Subcommands: []cli.Command{
				{
					Name:   "create",
					Usage:  "create a new Contribution within a Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Create()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "camera-shot-date"},
						cli.StringFlag{Name: "collection-code"},
						cli.StringFlag{Name: "content-provider-name"},
						cli.StringFlag{Name: "content-provider-title"},
						cli.StringFlag{Name: "country-of-shoot"},
						cli.StringFlag{Name: "credit-line"},
						cli.StringFlag{Name: "external-file-location"},
						cli.StringFlag{Name: "file-name"},
						cli.StringFlag{Name: "file-path"},
						cli.StringFlag{Name: "headline"},
						cli.StringFlag{Name: "iptc-category"},
						cli.StringFlag{Name: "mime-type"},
						cli.StringFlag{Name: "parent-source"},
						cli.StringFlag{Name: "recorded-date"},
						cli.StringFlag{Name: "risk-category"},
						cli.StringFlag{Name: "shot-speed"},
						cli.StringFlag{Name: "source"},
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "submitted-to-review-at"},
						cli.StringFlag{Name: "upload-id"},
						cli.StringSliceFlag{Name: "site-destination"},
					},
				},
				{
					Name:   "get",
					Usage:  "get a specific Contribution",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Get()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "contribution-id, c"},
					},
				},
				{
					Name:   "index",
					Usage:  "get all Contributions for a Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Index()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "update",
					Usage:  "update an existing Contribution",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Update()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "camera-shot-date"},
						cli.StringFlag{Name: "collection-code"},
						cli.StringFlag{Name: "content-provider-name"},
						cli.StringFlag{Name: "content-provider-title"},
						cli.StringFlag{Name: "contribution-id, c"},
						cli.StringFlag{Name: "country-of-shoot"},
						cli.StringFlag{Name: "credit-line"},
						cli.StringFlag{Name: "external-file-location"},
						cli.StringFlag{Name: "file-name"},
						cli.StringFlag{Name: "file-path"},
						cli.StringFlag{Name: "headline"},
						cli.StringFlag{Name: "iptc-category"},
						cli.StringFlag{Name: "mime-type"},
						cli.StringFlag{Name: "parent-source"},
						cli.StringFlag{Name: "recorded-date"},
						cli.StringFlag{Name: "risk-category"},
						cli.StringFlag{Name: "shot-speed"},
						cli.StringFlag{Name: "source"},
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "submitted-to-review-at"},
						cli.StringFlag{Name: "upload-id"},
						cli.StringSliceFlag{Name: "site-destination"},
					},
				},
				{
					Name:   "submit",
					Usage:  "submit an existing Contribution for review and publication",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Submit()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "contribution-id, c"},
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "delete",
					Usage:  "delete an existing Contribution",
					Action: func(c *cli.Context) { Contribution{c}.Delete() },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "contribution-id, c"},
					},
				},
			},
		},
		{
			Name:  "release",
			Usage: "work with Releases",
			Subcommands: []cli.Command{
				{
					Name:   "create",
					Usage:  "create a new Release within a Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Release{c}.Create()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "external-file-location"},
						cli.StringFlag{Name: "file-name"},
						cli.StringFlag{Name: "file-path"},
						cli.StringFlag{Name: "mime-type"},
						cli.StringFlag{Name: "model-date-of-birth"},
						cli.StringFlag{Name: "model-gender"},
						cli.StringFlag{Name: "release-type", Usage: releaseTypes},
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringSliceFlag{Name: "model-ethnicities"},
					},
				},
				{
					Name:   "get",
					Usage:  "get a specific Release",
					Action: func(c *cli.Context) { prettyPrint(Release{c}.Get()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "release-id, r"},
					},
				},
				{
					Name:   "index",
					Usage:  "get all Releases for a Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Release{c}.Index()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "delete",
					Usage:  "delete an existing Release",
					Action: func(c *cli.Context) { Release{c}.Delete() },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "release-id, r"},
					},
				},
			},
		},
		{
			Name:   "controlled_values",
			Usage:  "lists of values for fields with controlled vocabularies",
			Action: func(c *cli.Context) { prettyPrint(GetControlledValues(c)) },
		},
		{
			Name:   "transcoder",
			Usage:  "video transcoder mapping values",
			Action: func(c *cli.Context) { prettyPrint(GetTranscoderMappings(c)) },
		},
		{
			Name:   "keywords",
			Usage:  "controlled vocabularies for describing Contributions",
			Action: func(c *cli.Context) { GetKeywords(c) },
		},
		{
			Name:  "people",
			Usage: "controlled vocabularies and values for metadata about people",
			Subcommands: []cli.Command{
				{
					Name:   "compositions",
					Usage:  "all known values for Compositions",
					Action: func(c *cli.Context) { prettyPrint(TermService{}.GetCompositions(c)) },
				},
				{
					Name:   "expressions",
					Usage:  "all known values for Expressions",
					Action: func(c *cli.Context) { prettyPrint(TermService{}.GetExpressions(c)) },
				},
				{
					Name:   "number_of_people",
					Usage:  "all known values for Number Of People",
					Action: func(c *cli.Context) { prettyPrint(TermService{}.GetNumberOfPeople(c)) },
				},
				{
					Name:   "personalities",
					Usage:  "controlled vocabularies for describing famous personalities",
					Action: func(c *cli.Context) { GetPersonalities(c) },
				},
			},
		},
	}
	app.Run(os.Args)

}
<commit_msg>feat: allow disabling saving extracted metadata<commit_after>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
)

var patchVersion string
var Log = logrus.New()

func init() {
	Log.Formatter = &prefixed.TextFormatter{TimestampFormat: time.RFC3339}
}

func main() {
	app := cli.NewApp()
	app.Name = "gettyup"
	app.Version = "0.0.2" + patchVersion
	app.Usage = "interact with the Getty Images ESP API"
	app.Author = "Jordan Peterson"
	app.Email = "dysolution@gmail.com"
	app.Flags = []cli.Flag{
		cli.BoolFlag{Name: "debug, D", Usage: "enable debug output"},
		cli.BoolFlag{Name: "quiet, q", Usage: "suppress pretty-printed JSON from ESP's response"},
		cli.StringFlag{Name: "key, k", Usage: "your ESP API key", EnvVar: "ESP_API_KEY"},
		cli.StringFlag{Name: "secret", Usage: "your ESP API secret", EnvVar: "ESP_API_SECRET"},
		cli.StringFlag{Name: "username, u", Usage: "your ESP username", EnvVar: "ESP_USERNAME"},
		cli.StringFlag{Name: "password, p", Usage: "your ESP password", EnvVar: "ESP_PASSWORD"},
		cli.StringFlag{Name: "token, t", Usage: "use an existing OAuth2 token", EnvVar: "ESP_TOKEN"},
		cli.StringFlag{
			Name:        "s3-bucket, b",
			Value:       "oregon",
			Usage:       "nearest S3 bucket = [germany|ireland|oregon|singapore|tokyo|virginia]",
			Destination: &uploadBucket,
			EnvVar:      "S3_BUCKET",
		},
	}
	app.Before = func(c *cli.Context) error {
		client = getClient(
			c.String("key"),
			c.String("secret"),
			c.String("username"),
			c.String("password"),
		)
		quiet = c.Bool("quiet") == true
		if c.Bool("debug") == true {
			Log.Level = logrus.DebugLevel
		}
		token = stringToToken(c.String("token"))
		return nil
	}
	app.Commands = []cli.Command{
		{
			Name:   "token",
			Usage:  "retrieve and print an OAuth2 authorization token",
			Action: func(c *cli.Context) { fmt.Println(client.Token) },
		},
		{
			Name:  "batch",
			Usage: "work with Submission Batches",
			Subcommands: []cli.Command{
				{
					Name:   "create",
					Usage:  "create a new Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Batch{c}.Create()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-name, n"},
						cli.StringFlag{Name: "submission-type, t", Usage: batchTypes},
						cli.StringFlag{Name: "note"},
						cli.StringFlag{Name: "assignment-id"},
						cli.StringFlag{Name: "brief-id"},
						cli.StringFlag{Name: "event-id"},
						cli.BoolTFlag{Name: "save-extracted-metadata"},
					},
				},
				{
					Name:   "get",
					Usage:  "get a specific Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Batch{c}.Get()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "index",
					Usage:  "get all Submission Batches",
					Action: func(c *cli.Context) { prettyPrint(Batch{c}.Index()) },
				},
				{
					Name:   "update",
					Usage:  "update an existing Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Batch{c}.Update()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "submission-name, n"},
						cli.StringFlag{Name: "save-extracted-metadata"},
						cli.StringFlag{Name: "note"},
					},
				},
				{
					Name:   "delete",
					Usage:  "delete an existing Submission Batch",
					Action: func(c *cli.Context) { Batch{c}.Delete() },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "last",
					Usage:  "get the most recent Submission Batch",
					Action: func(c *cli.Context) { fmt.Println(Batch{c}.Last().ID) },
				},
			},
		},
		{
			Name:  "contribution",
			Usage: "work with Contributions",
			Subcommands: []cli.Command{
				{
					Name:   "create",
					Usage:  "create a new Contribution within a Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Create()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "camera-shot-date"},
						cli.StringFlag{Name: "collection-code"},
						cli.StringFlag{Name: "content-provider-name"},
						cli.StringFlag{Name: "content-provider-title"},
						cli.StringFlag{Name: "country-of-shoot"},
						cli.StringFlag{Name: "credit-line"},
						cli.StringFlag{Name: "external-file-location"},
						cli.StringFlag{Name: "file-name"},
						cli.StringFlag{Name: "file-path"},
						cli.StringFlag{Name: "headline"},
						cli.StringFlag{Name: "iptc-category"},
						cli.StringFlag{Name: "mime-type"},
						cli.StringFlag{Name: "parent-source"},
						cli.StringFlag{Name: "recorded-date"},
						cli.StringFlag{Name: "risk-category"},
						cli.StringFlag{Name: "shot-speed"},
						cli.StringFlag{Name: "source"},
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "submitted-to-review-at"},
						cli.StringFlag{Name: "upload-id"},
						cli.StringSliceFlag{Name: "site-destination"},
					},
				},
				{
					Name:   "get",
					Usage:  "get a specific Contribution",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Get()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "contribution-id, c"},
					},
				},
				{
					Name:   "index",
					Usage:  "get all Contributions for a Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Index()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "update",
					Usage:  "update an existing Contribution",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Update()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "camera-shot-date"},
						cli.StringFlag{Name: "collection-code"},
						cli.StringFlag{Name: "content-provider-name"},
						cli.StringFlag{Name: "content-provider-title"},
						cli.StringFlag{Name: "contribution-id, c"},
						cli.StringFlag{Name: "country-of-shoot"},
						cli.StringFlag{Name: "credit-line"},
						cli.StringFlag{Name: "external-file-location"},
						cli.StringFlag{Name: "file-name"},
						cli.StringFlag{Name: "file-path"},
						cli.StringFlag{Name: "headline"},
						cli.StringFlag{Name: "iptc-category"},
						cli.StringFlag{Name: "mime-type"},
						cli.StringFlag{Name: "parent-source"},
						cli.StringFlag{Name: "recorded-date"},
						cli.StringFlag{Name: "risk-category"},
						cli.StringFlag{Name: "shot-speed"},
						cli.StringFlag{Name: "source"},
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "submitted-to-review-at"},
						cli.StringFlag{Name: "upload-id"},
						cli.StringSliceFlag{Name: "site-destination"},
					},
				},
				{
					Name:   "submit",
					Usage:  "submit an existing Contribution for review and publication",
					Action: func(c *cli.Context) { prettyPrint(Contribution{c}.Submit()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "contribution-id, c"},
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "delete",
					Usage:  "delete an existing Contribution",
					Action: func(c *cli.Context) { Contribution{c}.Delete() },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "contribution-id, c"},
					},
				},
			},
		},
		{
			Name:  "release",
			Usage: "work with Releases",
			Subcommands: []cli.Command{
				{
					Name:   "create",
					Usage:  "create a new Release within a Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Release{c}.Create()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "external-file-location"},
						cli.StringFlag{Name: "file-name"},
						cli.StringFlag{Name: "file-path"},
						cli.StringFlag{Name: "mime-type"},
						cli.StringFlag{Name: "model-date-of-birth"},
						cli.StringFlag{Name: "model-gender"},
						cli.StringFlag{Name: "release-type", Usage: releaseTypes},
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringSliceFlag{Name: "model-ethnicities"},
					},
				},
				{
					Name:   "get",
					Usage:  "get a specific Release",
					Action: func(c *cli.Context) { prettyPrint(Release{c}.Get()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "release-id, r"},
					},
				},
				{
					Name:   "index",
					Usage:  "get all Releases for a Submission Batch",
					Action: func(c *cli.Context) { prettyPrint(Release{c}.Index()) },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
					},
				},
				{
					Name:   "delete",
					Usage:  "delete an existing Release",
					Action: func(c *cli.Context) { Release{c}.Delete() },
					Flags: []cli.Flag{
						cli.StringFlag{Name: "submission-batch-id, b"},
						cli.StringFlag{Name: "release-id, r"},
					},
				},
			},
		},
		{
			Name:   "controlled_values",
			Usage:  "lists of values for fields with controlled vocabularies",
			Action: func(c *cli.Context) { prettyPrint(GetControlledValues(c)) },
		},
		{
			Name:   "transcoder",
			Usage:  "video transcoder mapping values",
			Action: func(c *cli.Context) { prettyPrint(GetTranscoderMappings(c)) },
		},
		{
			Name:   "keywords",
			Usage:  "controlled vocabularies for describing Contributions",
			Action: func(c *cli.Context) { GetKeywords(c) },
		},
		{
			Name:  "people",
			Usage: "controlled vocabularies and values for metadata about people",
			Subcommands: []cli.Command{
				{
					Name:   "compositions",
					Usage:  "all known values for Compositions",
					Action: func(c *cli.Context) { prettyPrint(TermService{}.GetCompositions(c)) },
				},
				{
					Name:   "expressions",
					Usage:  "all known values for Expressions",
					Action: func(c *cli.Context) { prettyPrint(TermService{}.GetExpressions(c)) },
				},
				{
					Name:   "number_of_people",
					Usage:  "all known values for Number Of People",
					Action: func(c *cli.Context) { prettyPrint(TermService{}.GetNumberOfPeople(c)) },
				},
				{
					Name:   "personalities",
					Usage:  "controlled vocabularies for describing famous personalities",
					Action: func(c *cli.Context) { GetPersonalities(c) },
				},
			},
		},
	}
	app.Run(os.Args)

}
<|endoftext|>


<commit_before>// Diglet is a set of geospatial tools focused around rendering large feature sets efficiently.
package main

import (
	"os"
	"strings"

	"github.com/buckhx/diglet/mbt"
	"github.com/buckhx/diglet/resources"
	"github.com/buckhx/diglet/util"
	"github.com/buckhx/diglet/wms"

	"github.com/codegangsta/cli"
	"github.com/davecheney/profile"
)

//go:generate go run scripts/include.go static/static.html
func client(args []string) {
	app := cli.NewApp()
	app.Name = "diglet"
	app.Usage = "Your friend in the tile business"
	app.Version = resources.Version()
	app.Commands = []cli.Command{
		{
			Name:        "wms",
			Aliases:     []string{"serve"},
			Usage:       "Starts the diglet Web Map Service",
			Description: "Starts the diglet Web Map Service",
			ArgsUsage:   "mbtiles_directory",
			Action: func(c *cli.Context) {
				port := c.String("port")
				args := c.Args()
				if len(args) < 1 {
					die(c, "directory path to serve mbtiles from is required")
				}
				mbt := args[0]
				if mbt == "" {
					die(c, "mbtiles_directory is required")
				}
				cert := c.String("cert")
				key := c.String("key")
				server := wms.MBTServer(mbt, port)
				if (cert != "") && (key != "") {
					server.RunTLS(&cert, &key)
				} else if cert != "" || key != "" {
					die(c, "Both cert & key are required to serve over TLS/SSL")
				} else {
					server.Run()
				}
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "port",
					Value: "8080",
					Usage: "Port to bind",
				},
				cli.StringFlag{
					Name:  "cert, tls-certificate",
					Usage: "Path to .pem TLS Certificate. Both cert & key required to serve HTTPS",
				},
				cli.StringFlag{
					Name:  "key, tls-private-key",
					Usage: "Path to .pem TLS Private Key. Both cert & key required to serve HTTPS",
				},
				cli.BoolFlag{
					Name:  "tms-origin",
					Usage: "NOT IMPLEMENTED: Use TMS origin, SW origin w/ Y increasing North-wise",
				},
			},
		},
		{
			Name:        "mbt",
			Aliases:     []string{"build"},
			Usage:       "Builds an mbtiles database from the input data source",
			Description: "Builds an mbtiles database from the given format",
			ArgsUsage:   "input_source",
			Action: func(c *cli.Context) {
				out := c.String("output")
				desc := c.String("desc")
				layer := c.String("layer-name")
				zmin := uint(c.Int("min"))
				zmax := uint(c.Int("max"))
				extent := uint(c.Int("extent"))
				args := c.Args()
				if len(args) < 1 {
					die(c, "an input data source is required")
				}
				in := args[0]
				if in == "" || out == "" {
					die(c, "--in & --out required")
				}
				if zmax < zmin || zmin < 0 || zmax > 23 {
					die(c, "--max > --min, --min > 9 --max < 24 not satisfied")
				}
				force := c.Bool("force")
				if force {
					os.Remove(out)
				}
				/*
						lat := c.String("csv-lat")
						lon := c.String("csv-lon")
						delim := c.String("csv-delimiter")
						source := mbt.CsvTiles(in, delim, lat, lon)
					source := mbt.GeojsonTiles(in)
					mbt.BuildTileset(ts, source, zmin, zmax)
				*/
				upsert := c.Bool("upsert")
				filter := strings.Split(c.String("filter"), ",")
				if tiles, err := mbt.InitTiles(in, out, upsert, filter, desc, extent); err != nil {
					util.Fatal(err.Error())
				} else {
					err = tiles.Build(layer, zmin, zmax)
					if err != nil {
						util.Fatal(err.Error())
					} else {
						file, _ := os.Open(out)
						defer file.Close()
						stat, _ := file.Stat()
						exp := float64(stat.Size()) / float64(1<<20)
						util.Info("%s was successfully caught!", out)
						util.Info("Diglet gained %f MB of EXP!", exp)
					}
				}
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "o, output",
					Usage: "REQUIRED: Path to write mbtiles to",
				},
				cli.StringFlag{
					Name:  "input-type",
					Value: "sniff",
					Usage: "Type of input files, 'sniff' will pick type based on the extension",
				},
				cli.BoolFlag{
					Name:  "f, force",
					Usage: "Remove the existing .mbtiles file before running.",
				},
				cli.BoolFlag{
					Name:  "u, upsert",
					Usage: "Upsert into mbtiles instead of replacing.",
				},
				cli.StringFlag{
					Name:  "layer-name",
					Value: "features",
					Usage: "Name of the layer for the features to be added to",
				},
				cli.StringFlag{
					Name:  "desc, description",
					Value: "Generated from Diglet",
					Usage: "Value inserted into the description entry of the mbtiles",
				},
				cli.IntFlag{
					Name:  "extent",
					Value: 4096,
					Usage: "Extent of tiles to be built. Default is 4096",
				},
				cli.IntFlag{
					Name:  "max, max-zoom",
					Value: 10,
					Usage: "Maximum zoom level to build tiles for. Not Implemented.",
				},
				cli.IntFlag{
					Name:  "min, min-zoom",
					Value: 5,
					Usage: "Minimum zoom level to build tiles from. Not Implemented.",
				},
				cli.StringFlag{
					Name: "filter",
					Usage: "Only include fields keys in this comma delimited list.\t" +
						"EXAMPLE --filter name,date,case_number,id\t" +
						"NOTE all fields are lowercased and non-word chars replaced with '_'",
				},
				cli.StringFlag{
					Name:  "csv-lat",
					Value: "latitude",
				},
				cli.StringFlag{
					Name:  "csv-lon",
					Value: "longitude",
				},
				cli.StringFlag{
					Name:  "csv-geometry",
					Value: "geometry",
					Usage: "Column containing geometry in geojson-like 'coordinates' form",
				},
				cli.StringFlag{
					Name:  "csv-delimiter",
					Value: ",",
				},
			},
		},
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug",
			Usage: "Print debugging log lines",
		},
	}
	app.Before = func(c *cli.Context) error {
		if c.Bool("debug") {
			util.DEBUG = true
		}
		return nil
	}
	app.Run(args)
}

func main() {
	for _, arg := range os.Args {
		if arg == "--debug" {
			config := &profile.Config{
				MemProfile: true,
				CPUProfile: true,
			}
			defer profile.Start(config).Stop()
		}
	}
	client(os.Args)
}

func die(c *cli.Context, msg string) {
	cli.ShowSubcommandHelp(c)
	util.Fatal(msg)
}

/*
Go! Diglet!
Diglet used Earthquake
Foe DEWGONG fainted
Diglet gain 1960 EXP. Points
ELITE FOUR LORELEI is about to use CLOYSTER
sent out
Diglet fainted!
*/
<commit_msg>hotfix: cleanup cache & default filter<commit_after>// Diglet is a set of geospatial tools focused around rendering large feature sets efficiently.
package main

import (
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/buckhx/diglet/mbt"
	"github.com/buckhx/diglet/resources"
	"github.com/buckhx/diglet/util"
	"github.com/buckhx/diglet/wms"

	"github.com/codegangsta/cli"
	"github.com/davecheney/profile"
)

//go:generate go run scripts/include.go static/static.html
func client(args []string) {
	app := cli.NewApp()
	app.Name = "diglet"
	app.Usage = "Your friend in the tile business"
	app.Version = resources.Version()
	app.Commands = []cli.Command{
		{
			Name:        "wms",
			Aliases:     []string{"serve"},
			Usage:       "Starts the diglet Web Map Service",
			Description: "Starts the diglet Web Map Service",
			ArgsUsage:   "mbtiles_directory",
			Action: func(c *cli.Context) {
				port := c.String("port")
				args := c.Args()
				if len(args) < 1 {
					die(c, "directory path to serve mbtiles from is required")
				}
				mbt := args[0]
				if mbt == "" {
					die(c, "mbtiles_directory is required")
				}
				cert := c.String("cert")
				key := c.String("key")
				server := wms.MBTServer(mbt, port)
				if (cert != "") && (key != "") {
					server.RunTLS(&cert, &key)
				} else if cert != "" || key != "" {
					die(c, "Both cert & key are required to serve over TLS/SSL")
				} else {
					sigs := make(chan os.Signal, 1)
					done := make(chan bool, 1)
					signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
					defer os.Remove(mbt + "/" + wms.CacheName) //TODO make path.Join
					go func() {
						err := server.Run()
						util.Error(err)
						done <- true
					}()
					go func() {
						<-sigs
						done <- true
					}()
					<-done
				}
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "port",
					Value: "8080",
					Usage: "Port to bind",
				},
				cli.StringFlag{
					Name:  "cert, tls-certificate",
					Usage: "Path to .pem TLS Certificate. Both cert & key required to serve HTTPS",
				},
				cli.StringFlag{
					Name:  "key, tls-private-key",
					Usage: "Path to .pem TLS Private Key. Both cert & key required to serve HTTPS",
				},
				cli.BoolFlag{
					Name:  "tms-origin",
					Usage: "NOT IMPLEMENTED: Use TMS origin, SW origin w/ Y increasing North-wise",
				},
			},
		},
		{
			Name:        "mbt",
			Aliases:     []string{"build"},
			Usage:       "Builds an mbtiles database from the input data source",
			Description: "Builds an mbtiles database from the given format",
			ArgsUsage:   "input_source",
			Action: func(c *cli.Context) {
				out := c.String("output")
				desc := c.String("desc")
				layer := c.String("layer-name")
				zmin := uint(c.Int("min"))
				zmax := uint(c.Int("max"))
				extent := uint(c.Int("extent"))
				args := c.Args()
				if len(args) < 1 {
					die(c, "an input data source is required")
				}
				in := args[0]
				if in == "" || out == "" {
					die(c, "--in & --out required")
				}
				if zmax < zmin || zmin < 0 || zmax > 23 {
					die(c, "--max > --min, --min > 9 --max < 24 not satisfied")
				}
				force := c.Bool("force")
				if force {
					os.Remove(out)
				}
				/*
						lat := c.String("csv-lat")
						lon := c.String("csv-lon")
						delim := c.String("csv-delimiter")
						source := mbt.CsvTiles(in, delim, lat, lon)
					source := mbt.GeojsonTiles(in)
					mbt.BuildTileset(ts, source, zmin, zmax)
				*/
				upsert := c.Bool("upsert")
				var filter []string
				if len(c.String("filter")) > 0 {
					filter = strings.Split(c.String("filter"), ",")
				}
				if tiles, err := mbt.InitTiles(in, out, upsert, filter, desc, extent); err != nil {
					util.Fatal(err.Error())
				} else {
					err = tiles.Build(layer, zmin, zmax)
					if err != nil {
						util.Fatal(err.Error())
					} else {
						file, _ := os.Open(out)
						defer file.Close()
						stat, _ := file.Stat()
						exp := float64(stat.Size()) / float64(1<<20)
						util.Info("%s was successfully caught!", out)
						util.Info("Diglet gained %f MB of EXP!", exp)
					}
				}
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "o, output",
					Usage: "REQUIRED: Path to write mbtiles to",
				},
				cli.StringFlag{
					Name:  "input-type",
					Value: "sniff",
					Usage: "Type of input files, 'sniff' will pick type based on the extension",
				},
				cli.BoolFlag{
					Name:  "f, force",
					Usage: "Remove the existing .mbtiles file before running.",
				},
				cli.BoolFlag{
					Name:  "u, upsert",
					Usage: "Upsert into mbtiles instead of replacing.",
				},
				cli.StringFlag{
					Name:  "layer-name",
					Value: "features",
					Usage: "Name of the layer for the features to be added to",
				},
				cli.StringFlag{
					Name:  "desc, description",
					Value: "Generated from Diglet",
					Usage: "Value inserted into the description entry of the mbtiles",
				},
				cli.IntFlag{
					Name:  "extent",
					Value: 4096,
					Usage: "Extent of tiles to be built. Default is 4096",
				},
				cli.IntFlag{
					Name:  "max, max-zoom",
					Value: 10,
					Usage: "Maximum zoom level to build tiles for. Not Implemented.",
				},
				cli.IntFlag{
					Name:  "min, min-zoom",
					Value: 5,
					Usage: "Minimum zoom level to build tiles from. Not Implemented.",
				},
				cli.StringFlag{
					Name: "filter",
					Usage: "Only include fields keys in this comma delimited list.\t" +
						"EXAMPLE --filter name,date,case_number,id\t" +
						"NOTE all fields are lowercased and non-word chars replaced with '_'",
				},
				cli.StringFlag{
					Name:  "csv-lat",
					Value: "latitude",
				},
				cli.StringFlag{
					Name:  "csv-lon",
					Value: "longitude",
				},
				cli.StringFlag{
					Name:  "csv-geometry",
					Value: "geometry",
					Usage: "Column containing geometry in geojson-like 'coordinates' form",
				},
				cli.StringFlag{
					Name:  "csv-delimiter",
					Value: ",",
				},
			},
		},
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug",
			Usage: "Print debugging log lines",
		},
	}
	app.Before = func(c *cli.Context) error {
		if c.Bool("debug") {
			util.DEBUG = true
		}
		return nil
	}
	app.Run(args)
}

func main() {
	for _, arg := range os.Args {
		if arg == "--debug" {
			config := &profile.Config{
				MemProfile: true,
				CPUProfile: true,
			}
			defer profile.Start(config).Stop()
		}
	}
	client(os.Args)
}

func die(c *cli.Context, msg string) {
	cli.ShowSubcommandHelp(c)
	util.Fatal(msg)
}

/*
Go! Diglet!
Diglet used Earthquake
Foe DEWGONG fainted
Diglet gain 1960 EXP. Points
ELITE FOUR LORELEI is about to use CLOYSTER
sent out
Diglet fainted!
*/
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"go/format"
	"log"
	"os"
	"runtime"

	gen "github.com/tgulacsi/gowsdl/generator"
	flags "github.com/jessevdk/go-flags"
)

const version = "v0.0.1"

var opts struct {
	Version    bool   `short:"v" long:"version" description:"Shows gowsdl version"`
	Package    string `short:"p" long:"package" description:"Package under which code will be generated" default:"myservice"`
	OutputFile string `short:"o" long:"output" description:"File where the generated code will be saved" default:"myservice.go"`
	IgnoreTls  bool   `short:"i" long:"ignore-tls" description:"Ignores invalid TLS certificates. It is not recomended for production. Use at your own risk" default:"false"`
}

func init() {
	if os.Getenv("GOMAXPROCS") == "" {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}

	log.SetFlags(0)
	log.SetOutput(os.Stdout)
	log.SetPrefix("🍀  ")
}

func main() {
	args, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(1)
	}

	if opts.Version {
		log.Println(version)
		os.Exit(0)
	}

	if len(args) == 0 {
		log.Fatalln("WSDL file is required to start the party")
	}

	if opts.OutputFile == args[0] {
		log.Fatalln("Output file cannot be the same WSDL file")
	}

	gowsdl, err := gen.NewGoWsdl(args[0], opts.Package, opts.IgnoreTls)
	if err != nil {
		log.Fatalln(err)
	}

	gocode, err := gowsdl.Start()
	if err != nil {
		log.Fatalln(err)
	}

	pkg := "./" + opts.Package
	err = os.Mkdir(pkg, 0744)

	if perr, ok := err.(*os.PathError); ok && os.IsExist(perr.Err) {
		log.Printf("Package directory %s already exist, skipping creation\n", pkg)
	} else {
		if err != nil {
			log.Fatalln(err)
		}
	}

	fd, err := os.Create(pkg + "/" + opts.OutputFile)
	if err != nil {
		log.Fatalln(err)
	}
	defer fd.Close()

	data := new(bytes.Buffer)
	data.Write(gocode["header"])
	data.Write(gocode["types"])
	data.Write(gocode["operations"])

	source, err := format.Source(data.Bytes())
	if err != nil {
		fd.Write(data.Bytes())
		log.Fatalln(err)
	}

	fd.Write(source)

	log.Println("Done 💩")
}
<commit_msg>revert import change<commit_after>package main

import (
	"bytes"
	"go/format"
	"log"
	"os"
	"runtime"

	gen "github.com/cloudescape/gowsdl/generator"
	flags "github.com/jessevdk/go-flags"
)

const version = "v0.0.1"

var opts struct {
	Version    bool   `short:"v" long:"version" description:"Shows gowsdl version"`
	Package    string `short:"p" long:"package" description:"Package under which code will be generated" default:"myservice"`
	OutputFile string `short:"o" long:"output" description:"File where the generated code will be saved" default:"myservice.go"`
	IgnoreTls  bool   `short:"i" long:"ignore-tls" description:"Ignores invalid TLS certificates. It is not recomended for production. Use at your own risk" default:"false"`
}

func init() {
	if os.Getenv("GOMAXPROCS") == "" {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}

	log.SetFlags(0)
	log.SetOutput(os.Stdout)
	log.SetPrefix("🍀  ")
}

func main() {
	args, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(1)
	}

	if opts.Version {
		log.Println(version)
		os.Exit(0)
	}

	if len(args) == 0 {
		log.Fatalln("WSDL file is required to start the party")
	}

	if opts.OutputFile == args[0] {
		log.Fatalln("Output file cannot be the same WSDL file")
	}

	gowsdl, err := gen.NewGoWsdl(args[0], opts.Package, opts.IgnoreTls)
	if err != nil {
		log.Fatalln(err)
	}

	gocode, err := gowsdl.Start()
	if err != nil {
		log.Fatalln(err)
	}

	pkg := "./" + opts.Package
	err = os.Mkdir(pkg, 0744)

	if perr, ok := err.(*os.PathError); ok && os.IsExist(perr.Err) {
		log.Printf("Package directory %s already exist, skipping creation\n", pkg)
	} else {
		if err != nil {
			log.Fatalln(err)
		}
	}

	fd, err := os.Create(pkg + "/" + opts.OutputFile)
	if err != nil {
		log.Fatalln(err)
	}
	defer fd.Close()

	data := new(bytes.Buffer)
	data.Write(gocode["header"])
	data.Write(gocode["types"])
	data.Write(gocode["operations"])

	source, err := format.Source(data.Bytes())
	if err != nil {
		fd.Write(data.Bytes())
		log.Fatalln(err)
	}

	fd.Write(source)

	log.Println("Done 💩")
}
<|endoftext|>


<commit_before>// +build go1.2

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

// Package com is an open source project for commonly used functions for the Go programming language.
package com

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"github.com/admpub/log"
)

// ElapsedMemory 内存占用
func ElapsedMemory() (ret string) {
	memStat := new(runtime.MemStats)
	runtime.ReadMemStats(memStat)
	ret = FormatByte(memStat.Alloc, 3)
	return
}

// ExecCmdDirBytes executes system command in given directory
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
	bufOut := new(bytes.Buffer)
	bufErr := new(bytes.Buffer)

	cmd := exec.Command(cmdName, args...)
	cmd.Dir = dir
	cmd.Stdout = bufOut
	cmd.Stderr = bufErr

	err := cmd.Run()
	return bufOut.Bytes(), bufErr.Bytes(), err
}

// ExecCmdBytes executes system command
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdBytes(cmdName string, args ...string) ([]byte, []byte, error) {
	return ExecCmdDirBytes("", cmdName, args...)
}

// ExecCmdDir executes system command in given directory
// and return stdout, stderr in string type, along with possible error.
func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
	bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
	return string(bufOut), string(bufErr), err
}

// ExecCmd executes system command
// and return stdout, stderr in string type, along with possible error.
func ExecCmd(cmdName string, args ...string) (string, string, error) {
	return ExecCmdDir("", cmdName, args...)
}

// WritePidFile writes the process ID to the file at PidFile.
// It does nothing if PidFile is not set.
func WritePidFile(pidFile string) error {
	if pidFile == "" {
		return nil
	}
	pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
	return ioutil.WriteFile(pidFile, pid, 0644)
}

var (
	space  = rune(' ')
	quote  = rune('"')
	slash  = rune('\\')
	envOS  = regexp.MustCompile(`\{\$[a-zA-Z0-9_]+\}`)
	envWin = regexp.MustCompile(`\{%[a-zA-Z0-9_]+%\}`)
)

func ParseArgs(command string) (params []string) {
	item := []rune{}
	hasQuote := false
	hasSlash := false
	maxIndex := len(command) - 1
	//tower.exe -c tower.yaml -p "eee\"ddd" -t aaaa
	for k, v := range command {
		if !hasQuote {
			if v == space {
				params = append(params, string(item))
				item = []rune{}
				continue
			}
			if v == quote {
				hasQuote = true
				continue
			}
		} else {
			if !hasSlash && v == quote {
				hasQuote = false
				continue
			}
			if !hasSlash && v == slash && k+1 <= maxIndex && command[k+1] == '"' {
				hasSlash = true
				continue
			}
			hasSlash = false
		}
		item = append(item, v)
	}
	if len(item) > 0 {
		params = append(params, string(item))
	}
	for k, v := range params {
		v = envWin.ReplaceAllStringFunc(v, getWinEnv)
		params[k] = envOS.ReplaceAllStringFunc(v, getEnv)
	}
	//fmt.Printf("---> %#v\n", params)
	//params = []string{}
	return
}

func getWinEnv(s string) string {
	s = strings.TrimPrefix(s, `{%`)
	s = strings.TrimSuffix(s, `%}`)
	return os.Getenv(s)
}

func getEnv(s string) string {
	s = strings.TrimPrefix(s, `{$`)
	s = strings.TrimSuffix(s, `}`)
	return os.Getenv(s)
}

type CmdResultCapturer struct {
	Do func([]byte) error
}

func (this CmdResultCapturer) Write(p []byte) (n int, err error) {
	err = this.Do(p)
	n = len(p)
	return
}

func (this CmdResultCapturer) WriteString(p string) (n int, err error) {
	err = this.Do([]byte(p))
	n = len(p)
	return
}

func CreateCmdStr(command string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return CreateCmdStrWithWriter(command, out)
}

func CreateCmd(params []string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return CreateCmdWithWriter(params, out)
}

func CreateCmdStrWithWriter(command string, writer ...io.Writer) *exec.Cmd {
	params := ParseArgs(command)
	return CreateCmdWithWriter(params, writer...)
}

func CreateCmdWithWriter(params []string, writer ...io.Writer) *exec.Cmd {
	var cmd *exec.Cmd
	length := len(params)
	if length == 0 || len(params[0]) == 0 {
		return cmd
	}
	if length > 1 {
		cmd = exec.Command(params[0], params[1:]...)
	} else {
		cmd = exec.Command(params[0])
	}
	var wOut, wErr io.Writer = os.Stdout, os.Stderr
	length = len(writer)
	if length > 0 {
		if writer[0] != nil {
			wOut = writer[0]
		}
		if length > 1 && writer[1] != nil {
			wErr = writer[1]
		}
	}
	cmd.Stdout = wOut
	cmd.Stderr = wErr
	return cmd
}

func RunCmdStr(command string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return RunCmdStrWithWriter(command, out)
}

func RunCmd(params []string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return RunCmdWithWriter(params, out)
}

func RunCmdStrWithWriter(command string, writer ...io.Writer) *exec.Cmd {
	params := ParseArgs(command)
	return RunCmdWithWriter(params, writer...)
}

func RunCmdWithWriter(params []string, writer ...io.Writer) *exec.Cmd {
	cmd := CreateCmdWithWriter(params, writer...)

	go func() {
		err := cmd.Run()
		if err != nil {
			cmd.Stderr.Write([]byte(err.Error()))
		}
	}()

	return cmd
}

func CloseProcessFromPidFile(pidFile string) (err error) {
	if pidFile == `` {
		return
	}
	b, err := ioutil.ReadFile(pidFile)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return
	}
	pid, err := strconv.Atoi(strings.TrimSpace(string(b)))
	if err != nil {
		log.Error(err.Error())
		return nil
	}
	return CloseProcessFromPid(pid)
}

func CloseProcessFromPid(pid int) (err error) {
	if pid <= 0 {
		return nil
	}
	procs, err := os.FindProcess(pid)
	if err == nil {
		return procs.Kill()
	}
	return
}
<commit_msg>update<commit_after>// +build go1.2

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

// Package com is an open source project for commonly used functions for the Go programming language.
package com

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/admpub/log"
)

// ElapsedMemory 内存占用
func ElapsedMemory() (ret string) {
	memStat := new(runtime.MemStats)
	runtime.ReadMemStats(memStat)
	ret = FormatByte(memStat.Alloc, 3)
	return
}

// ExecCmdDirBytes executes system command in given directory
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
	bufOut := new(bytes.Buffer)
	bufErr := new(bytes.Buffer)

	cmd := exec.Command(cmdName, args...)
	cmd.Dir = dir
	cmd.Stdout = bufOut
	cmd.Stderr = bufErr

	err := cmd.Run()
	return bufOut.Bytes(), bufErr.Bytes(), err
}

// ExecCmdBytes executes system command
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdBytes(cmdName string, args ...string) ([]byte, []byte, error) {
	return ExecCmdDirBytes("", cmdName, args...)
}

// ExecCmdDir executes system command in given directory
// and return stdout, stderr in string type, along with possible error.
func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
	bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
	return string(bufOut), string(bufErr), err
}

// ExecCmd executes system command
// and return stdout, stderr in string type, along with possible error.
func ExecCmd(cmdName string, args ...string) (string, string, error) {
	return ExecCmdDir("", cmdName, args...)
}

// WritePidFile writes the process ID to the file at PidFile.
// It does nothing if PidFile is not set.
func WritePidFile(pidFile string) error {
	if pidFile == "" {
		return nil
	}
	pid := []byte(strconv.Itoa(os.Getpid()) + "\n")
	return ioutil.WriteFile(pidFile, pid, 0644)
}

var (
	space  = rune(' ')
	quote  = rune('"')
	slash  = rune('\\')
	envOS  = regexp.MustCompile(`\{\$[a-zA-Z0-9_]+\}`)
	envWin = regexp.MustCompile(`\{%[a-zA-Z0-9_]+%\}`)
)

func ParseArgs(command string) (params []string) {
	item := []rune{}
	hasQuote := false
	hasSlash := false
	maxIndex := len(command) - 1
	//tower.exe -c tower.yaml -p "eee\"ddd" -t aaaa
	for k, v := range command {
		if !hasQuote {
			if v == space {
				params = append(params, string(item))
				item = []rune{}
				continue
			}
			if v == quote {
				hasQuote = true
				continue
			}
		} else {
			if !hasSlash && v == quote {
				hasQuote = false
				continue
			}
			if !hasSlash && v == slash && k+1 <= maxIndex && command[k+1] == '"' {
				hasSlash = true
				continue
			}
			hasSlash = false
		}
		item = append(item, v)
	}
	if len(item) > 0 {
		params = append(params, string(item))
	}
	for k, v := range params {
		v = envWin.ReplaceAllStringFunc(v, getWinEnv)
		params[k] = envOS.ReplaceAllStringFunc(v, getEnv)
	}
	//fmt.Printf("---> %#v\n", params)
	//params = []string{}
	return
}

func getWinEnv(s string) string {
	s = strings.TrimPrefix(s, `{%`)
	s = strings.TrimSuffix(s, `%}`)
	return os.Getenv(s)
}

func getEnv(s string) string {
	s = strings.TrimPrefix(s, `{$`)
	s = strings.TrimSuffix(s, `}`)
	return os.Getenv(s)
}

type CmdResultCapturer struct {
	Do func([]byte) error
}

func (this CmdResultCapturer) Write(p []byte) (n int, err error) {
	err = this.Do(p)
	n = len(p)
	return
}

func (this CmdResultCapturer) WriteString(p string) (n int, err error) {
	err = this.Do([]byte(p))
	n = len(p)
	return
}

func CreateCmdStr(command string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return CreateCmdStrWithWriter(command, out)
}

func CreateCmd(params []string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return CreateCmdWithWriter(params, out)
}

func CreateCmdStrWithWriter(command string, writer ...io.Writer) *exec.Cmd {
	params := ParseArgs(command)
	return CreateCmdWithWriter(params, writer...)
}

func CreateCmdWithWriter(params []string, writer ...io.Writer) *exec.Cmd {
	var cmd *exec.Cmd
	length := len(params)
	if length == 0 || len(params[0]) == 0 {
		return cmd
	}
	if length > 1 {
		cmd = exec.Command(params[0], params[1:]...)
	} else {
		cmd = exec.Command(params[0])
	}
	var wOut, wErr io.Writer = os.Stdout, os.Stderr
	length = len(writer)
	if length > 0 {
		if writer[0] != nil {
			wOut = writer[0]
		}
		if length > 1 && writer[1] != nil {
			wErr = writer[1]
		}
	}
	cmd.Stdout = wOut
	cmd.Stderr = wErr
	return cmd
}

func RunCmdStr(command string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return RunCmdStrWithWriter(command, out)
}

func RunCmd(params []string, recvResult func([]byte) error) *exec.Cmd {
	out := CmdResultCapturer{Do: recvResult}
	return RunCmdWithWriter(params, out)
}

func RunCmdStrWithWriter(command string, writer ...io.Writer) *exec.Cmd {
	params := ParseArgs(command)
	return RunCmdWithWriter(params, writer...)
}

func RunCmdWithWriter(params []string, writer ...io.Writer) *exec.Cmd {
	cmd := CreateCmdWithWriter(params, writer...)

	go func() {
		err := cmd.Run()
		if err != nil {
			cmd.Stderr.Write([]byte(err.Error()))
		}
	}()

	return cmd
}

func RunCmdWithWriterx(params []string, wait time.Duration, writer ...io.Writer) (cmd *exec.Cmd, err error) {
	cmd = CreateCmdWithWriter(params, writer...)
	go func() {
		err = cmd.Run()
		if err != nil {
			cmd.Stderr.Write([]byte(err.Error()))
		}
	}()
	time.Sleep(wait)
	return
}

func CloseProcessFromPidFile(pidFile string) (err error) {
	if pidFile == `` {
		return
	}
	b, err := ioutil.ReadFile(pidFile)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return
	}
	pid, err := strconv.Atoi(strings.TrimSpace(string(b)))
	if err != nil {
		log.Error(err.Error())
		return nil
	}
	return CloseProcessFromPid(pid)
}

func CloseProcessFromPid(pid int) (err error) {
	if pid <= 0 {
		return nil
	}
	procs, err := os.FindProcess(pid)
	if err == nil {
		return procs.Kill()
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"github.com/THUNDERGROOVE/census"
	"github.com/nlopes/slack"
	"log"
	"strings"
	"text/template"
	"fmt"
)

var Commands = make(map[string]*Cmd)

const lookup = `
{{if .Character}}
({{.Faction.Name.En}}) {{if .Outfit.Alias }}[{{.Outfit.Alias}}]{{end}} {{.Name.First}}@{{.ServerName}} BR: {{.Battlerank.Rank}} :cert: {{.GetCerts}}\
Kills: {{.GetKills}} Deaths: {{.GetDeaths}} KDR: {{.KDRS}} TK: %{{.TKPercent}}\
{{if .Outfit.Name}} Outfit: {{.Outfit.Name}} with {{.Outfit.MemberCount}} members \{{end}}
Defended: {{.GetFacilitiesDefended}} Captured: {{.GetFacilitiesCaptured}}\
Get more stats @ ps4{{if .Parent.IsEU}}eu{{else}}us{{end}}.ps2.fisu.pw/player/?name={{.Name.First}}
{{else}}
Uh got nil character?
{{end}}
`

const helpText = `Hi.  I'm stats-bot.  You can ask me to '!lookup <name>' or '!lookupeu <name>'`

type Global struct {
	*census.Character
	Dev bool
}

var lookupTmpl *template.Template

func init() {

	var err error
	lookupTmpl = template.New("")
	lookupTmpl, err = lookupTmpl.Parse(lookup)
	if err != nil {
		log.Fatalf("Template failed to compile: [%v]", err.Error())
	}
	RegisterCommand("help", func(bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
		Respond(helpText, out, ev)
	})

	RegisterCommand("lookup", func(bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
		LookupWith(Census, CensusEU, bot, out, ev)
	})
	RegisterCommand("lookupeu", func(bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
		LookupWith(CensusEU, Census, bot, out, ev)
	})
}

func LookupWith(c *census.Census, fallbackc *census.Census, bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
	args := strings.Split(ev.Text, " ")
	if len(args) <= 1 {
		Respond("Do you really expect me to lookup nothing?", out, ev)
		return
	}
	name := args[1]
	char, err := c.QueryCharacterByExactName(name)
	if err != nil {
		if strings.Contains(err.Error(), "Get") {
			Respond("ERROR: The server closed the connection on us.  The API is either down or we are being rate-limited", out, ev)
			return
		} else if err != nil {
			Respond(fmt.Sprintf("Couldn't find the character '%v'", name), out, ev)
		}
		log.Printf("Error getting character info: [%v] trying fallback", err.Error())

		char, err = fallbackc.QueryCharacterByExactName(name)
		if err != nil {
			if strings.Contains(err.Error(), "Get") {
				Respond("ERROR: The server closed the connection on us.  The API is either down or we are being rate-limited", out, ev)
				return
			} else if err != nil {
				Respond(fmt.Sprintf("Couldn't find the character '%v'", name), out, ev)
				return
			}
		}
	}
	if char == nil {
		log.Printf("Query didn't return any error but character was nil")
		Respond("Query didn't return any error but character was nil", out, ev)
		return
	}
	buff := bytes.NewBuffer([]byte(""))
	if err := lookupTmpl.Execute(buff, Global{Character: char, Dev: Dev}); err != nil {
		buff.WriteString("\nerror encountered" + err.Error())
	}
	Respond(buff.String(), out, ev)
}

type Cmd struct {
	name    string
	handler func(*slack.Slack, chan slack.OutgoingMessage, *slack.MessageEvent)
}

func RegisterCommand(name string, handler func(*slack.Slack, chan slack.OutgoingMessage, *slack.MessageEvent)) {
	cmd := new(Cmd)
	cmd.name = name
	cmd.handler = handler
	Commands[name] = cmd
}

func Dispatch(bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Recovered from panic in dispatch")
		}
	}()

	if bot.GetInfo().User.Id == ev.UserId {
		return
	}
	c := strings.ToLower(strings.Split(ev.Text, " ")[0])
	if len(ev.Text) == 0 {
		log.Printf("Got blank message")
		return
	}
	if ev.Text[0] == '!' {

		if v, ok := Commands[strings.TrimLeft(c, "!")]; ok {

			//log.Printf("[Dispatch] Sending to %v", v.name)
			v.handler(bot, out, ev)

		} else {
			log.Printf("[Dispatch] Unhandled command '%v' ev: '%v'", c, ev.Text)
			Respond("!I don't know what you want from me :( do 'help'?", out, ev)
		}
	}
}

func Respond(s string, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
	lines := strings.Split(s, "\\")
	for _, v := range lines {
		o := slack.OutgoingMessage{}
		o.Text = v
		o.ChannelId = ev.ChannelId
		o.Type = ev.Type
		out <- o
	}
}

func parseURL(url string) string {
	url = strings.Split(url, "//")[1]
	url = strings.Split(url, ".slack.com/")[0]
	return url
}

func TKPercent(char *census.Character) float64 {
	kills := char.TeamKillsInLast(150)
	return (float64(kills) / 1000) * 100
}
<commit_msg>Forgot to return<commit_after>package main

import (
	"bytes"
	"github.com/THUNDERGROOVE/census"
	"github.com/nlopes/slack"
	"log"
	"strings"
	"text/template"
	"fmt"
)

var Commands = make(map[string]*Cmd)

const lookup = `
{{if .Character}}
({{.Faction.Name.En}}) {{if .Outfit.Alias }}[{{.Outfit.Alias}}]{{end}} {{.Name.First}}@{{.ServerName}} BR: {{.Battlerank.Rank}} :cert: {{.GetCerts}}\
Kills: {{.GetKills}} Deaths: {{.GetDeaths}} KDR: {{.KDRS}} TK: %{{.TKPercent}}\
{{if .Outfit.Name}} Outfit: {{.Outfit.Name}} with {{.Outfit.MemberCount}} members \{{end}}
Defended: {{.GetFacilitiesDefended}} Captured: {{.GetFacilitiesCaptured}}\
Get more stats @ ps4{{if .Parent.IsEU}}eu{{else}}us{{end}}.ps2.fisu.pw/player/?name={{.Name.First}}
{{else}}
Uh got nil character?
{{end}}
`

const helpText = `Hi.  I'm stats-bot.  You can ask me to '!lookup <name>' or '!lookupeu <name>'`

type Global struct {
	*census.Character
	Dev bool
}

var lookupTmpl *template.Template

func init() {

	var err error
	lookupTmpl = template.New("")
	lookupTmpl, err = lookupTmpl.Parse(lookup)
	if err != nil {
		log.Fatalf("Template failed to compile: [%v]", err.Error())
	}
	RegisterCommand("help", func(bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
		Respond(helpText, out, ev)
	})

	RegisterCommand("lookup", func(bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
		LookupWith(Census, CensusEU, bot, out, ev)
	})
	RegisterCommand("lookupeu", func(bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
		LookupWith(CensusEU, Census, bot, out, ev)
	})
}

func LookupWith(c *census.Census, fallbackc *census.Census, bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
	args := strings.Split(ev.Text, " ")
	if len(args) <= 1 {
		Respond("Do you really expect me to lookup nothing?", out, ev)
		return
	}
	name := args[1]
	char, err := c.QueryCharacterByExactName(name)
	if err != nil {
		if strings.Contains(err.Error(), "Get") {
			Respond("ERROR: The server closed the connection on us.  The API is either down or we are being rate-limited", out, ev)
			return
		} else if err != nil {
			Respond(fmt.Sprintf("Couldn't find the character '%v'", name), out, ev)
			return
		}
		log.Printf("Error getting character info: [%v] trying fallback", err.Error())

		char, err = fallbackc.QueryCharacterByExactName(name)
		if err != nil {
			if strings.Contains(err.Error(), "Get") {
				Respond("ERROR: The server closed the connection on us.  The API is either down or we are being rate-limited", out, ev)
				return
			} else if err != nil {
				Respond(fmt.Sprintf("Couldn't find the character '%v'", name), out, ev)
				return
			}
		}
	}
	if char == nil {
		log.Printf("Query didn't return any error but character was nil")
		Respond("Query didn't return any error but character was nil", out, ev)
		return
	}
	buff := bytes.NewBuffer([]byte(""))
	if err := lookupTmpl.Execute(buff, Global{Character: char, Dev: Dev}); err != nil {
		buff.WriteString("\nerror encountered" + err.Error())
	}
	Respond(buff.String(), out, ev)
}

type Cmd struct {
	name    string
	handler func(*slack.Slack, chan slack.OutgoingMessage, *slack.MessageEvent)
}

func RegisterCommand(name string, handler func(*slack.Slack, chan slack.OutgoingMessage, *slack.MessageEvent)) {
	cmd := new(Cmd)
	cmd.name = name
	cmd.handler = handler
	Commands[name] = cmd
}

func Dispatch(bot *slack.Slack, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Recovered from panic in dispatch")
		}
	}()

	if bot.GetInfo().User.Id == ev.UserId {
		return
	}
	c := strings.ToLower(strings.Split(ev.Text, " ")[0])
	if len(ev.Text) == 0 {
		log.Printf("Got blank message")
		return
	}
	if ev.Text[0] == '!' {

		if v, ok := Commands[strings.TrimLeft(c, "!")]; ok {

			//log.Printf("[Dispatch] Sending to %v", v.name)
			v.handler(bot, out, ev)

		} else {
			log.Printf("[Dispatch] Unhandled command '%v' ev: '%v'", c, ev.Text)
			Respond("!I don't know what you want from me :( do 'help'?", out, ev)
		}
	}
}

func Respond(s string, out chan slack.OutgoingMessage, ev *slack.MessageEvent) {
	lines := strings.Split(s, "\\")
	for _, v := range lines {
		o := slack.OutgoingMessage{}
		o.Text = v
		o.ChannelId = ev.ChannelId
		o.Type = ev.Type
		out <- o
	}
}

func parseURL(url string) string {
	url = strings.Split(url, "//")[1]
	url = strings.Split(url, ".slack.com/")[0]
	return url
}

func TKPercent(char *census.Character) float64 {
	kills := char.TeamKillsInLast(150)
	return (float64(kills) / 1000) * 100
}
<|endoftext|>