<commit_before>// Copyright 2015 Matthew Collins
//
// 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 steven

import (
	"os"
	"runtime"

	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/thinkofdeath/steven/console"
	"github.com/thinkofdeath/steven/protocol"
	"github.com/thinkofdeath/steven/render/gl"
	"github.com/thinkofdeath/steven/ui"
)

var window *glfw.Window

func init() {
	runtime.LockOSThread()
}

var (
	renderVSync = console.NewBoolVar("r_vsync", true, console.Mutable, console.Serializable).
			Doc(`
r_vsync controls whether vsync is enabled. VSync tries to
keep the refreshing of the game in sync with the monitor's
refresh rate.
`)
	mouseSensitivity = console.NewIntVar("cl_mouse_speed", 8000, console.Mutable, console.Serializable).
				Doc(`
cl_mouse_speed controls how fast you rotate when moving
the mouse. Higher values means faster rotation.
`)
)

func init() {
	renderVSync.Callback(func() {
		if glfw.GetCurrentContext() == nil {
			return
		}
		if renderVSync.Value() {
			glfw.SwapInterval(1)
		} else {
			glfw.SwapInterval(0)
		}
	})
}

func startWindow() {
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 2)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	glfw.WindowHint(glfw.DepthBits, 32)
	glfw.WindowHint(glfw.StencilBits, 0)
	if os.Getenv("STEVEN_DEBUG") == "true" {
		glfw.WindowHint(glfw.OpenGLDebugContext, glfw.True)
	}

	var err error
	window, err = glfw.CreateWindow(854, 480, "Steven", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()
	if renderVSync.Value() {
		glfw.SwapInterval(1)
	} else {
		glfw.SwapInterval(0)
	}

	window.SetCursorPosCallback(onMouseMove)
	window.SetMouseButtonCallback(onMouseClick)
	window.SetKeyCallback(onKey)
	window.SetCharCallback(onChar)
	window.SetScrollCallback(onScroll)
	window.SetFocusCallback(onFocus)

	gl.Init()

	start()

	for !window.ShouldClose() {
		draw()
		window.SwapBuffers()
		glfw.PollEvents()
	}
}

func onScroll(w *glfw.Window, xoff float64, yoff float64) {
	if currentScreen != nil || !ready {
		return
	}
	if yoff < 0 {
		Client.currentHotbarSlot++
	} else {
		Client.currentHotbarSlot--
	}
	if Client.currentHotbarSlot < 0 {
		Client.currentHotbarSlot = 8
	} else if Client.currentHotbarSlot > 8 {
		Client.currentHotbarSlot = 0
	}

	Client.network.Write(&protocol.HeldItemChange{Slot: int16(Client.currentHotbarSlot)})
}

var lockMouse bool

func onFocus(w *glfw.Window, focused bool) {
	if !focused {
		lockMouse = false
		window.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
		for i := range Client.KeyState {
			Client.KeyState[i] = false
		}
	} else if lockMouse {
		w.SetInputMode(glfw.CursorMode, glfw.CursorDisabled)
	}
}

func onMouseMove(w *glfw.Window, xpos float64, ypos float64) {
	width, height := w.GetSize()
	if currentScreen != nil {
		fw, fh := w.GetFramebufferSize()
		currentScreen.hover(xpos*(float64(fw)/float64(width)), ypos*(float64(fh)/float64(height)), fw, fh)
		return
	}
	if !lockMouse {
		return
	}
	ww, hh := float64(width/2), float64(height/2)
	w.SetCursorPos(ww, hh)

	s := float64(10000-mouseSensitivity.Value()) + 0.01
	rotate((xpos-ww)/s, (ypos-hh)/s)
}

func onMouseClick(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
	if currentScreen != nil {
		if button != glfw.MouseButtonLeft || action == glfw.Repeat {
			return
		}
		width, height := w.GetSize()
		xpos, ypos := w.GetCursorPos()
		fw, fh := w.GetFramebufferSize()
		currentScreen.click(action == glfw.Press, xpos*(float64(fw)/float64(width)), ypos*(float64(fh)/float64(height)), fw, fh)
		return
	}
	if !Client.chat.enteringText && lockMouse && action != glfw.Repeat {
		Client.MouseAction(button, action == glfw.Press)
	}
	if button == glfw.MouseButtonLeft && action == glfw.Press && !Client.chat.enteringText {
		lockMouse = true
		w.SetInputMode(glfw.CursorMode, glfw.CursorDisabled)
	}
}

type Key int

const (
	KeyForward Key = iota
	KeyBackwards
	KeyLeft
	KeyRight
	KeySprint
	KeyJump
)

var keyStateMap = map[glfw.Key]Key{
	glfw.KeyW:           KeyForward,
	glfw.KeyS:           KeyBackwards,
	glfw.KeyA:           KeyLeft,
	glfw.KeyD:           KeyRight,
	glfw.KeyLeftControl: KeySprint,
	glfw.KeySpace:       KeyJump,
}

func onChar(w *glfw.Window, char rune) {
	if currentScreen != nil {
		ui.HandleChar(w, char)
	}
}

func onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	// Debug override
	if key == glfw.KeyGraveAccent && action == glfw.Release {
		con.focus()
		return
	}

	if currentScreen != nil {
		ui.HandleKey(w, key, scancode, action, mods)
		return
	}
	if Client.chat.enteringText {
		Client.chat.handleKey(w, key, scancode, action, mods)
		return
	}

	if k, ok := keyStateMap[key]; action != glfw.Repeat && ok {
		Client.KeyState[k] = action == glfw.Press
	}
	switch key {
	case glfw.KeyEscape:
		if action == glfw.Release {
			setScreen(newGameMenu())
		}
	case glfw.KeyF1:
		if action == glfw.Release {
			if Client.scene.IsVisible() {
				Client.scene.Hide()
				Client.hotbarScene.Hide()
			} else {
				Client.scene.Show()
				Client.hotbarScene.Show()
			}
		}
	case glfw.KeyF3:
		if action == glfw.Release {
			Client.toggleDebug()
		}
	case glfw.KeyF5:
		if action == glfw.Release {
			Client.cycleCamera()
		}
	case glfw.KeyTab:
		if action == glfw.Press {
			Client.playerList.set(true)
		} else if action == glfw.Release {
			Client.playerList.set(false)
		}
	case glfw.KeyE:
		if action == glfw.Release {
			wasPlayer := Client.activeInventory == Client.playerInventory
			closeInventory()
			if wasPlayer {
				return
			}
			openInventory(Client.playerInventory)
		}
	case glfw.KeyT:
		state := w.GetKey(glfw.KeyF3)
		if action == glfw.Release && state == glfw.Press {
			reloadResources()
			return
		}
		fallthrough
	case glfw.KeySlash:
		if action != glfw.Release {
			return
		}
		for i := range Client.KeyState {
			Client.KeyState[i] = false
		}
		Client.chat.enteringText = true
		if key == glfw.KeySlash {
			Client.chat.inputLine = append(Client.chat.inputLine, '/')
		}
		lockMouse = false
		w.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
		w.SetCharCallback(Client.chat.handleChar)
	}
}
<commit_msg>steven: allow for the number keys to be used to select a hotbar slot<commit_after>// Copyright 2015 Matthew Collins
//
// 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 steven

import (
	"os"
	"runtime"

	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/thinkofdeath/steven/console"
	"github.com/thinkofdeath/steven/protocol"
	"github.com/thinkofdeath/steven/render/gl"
	"github.com/thinkofdeath/steven/ui"
)

var window *glfw.Window

func init() {
	runtime.LockOSThread()
}

var (
	renderVSync = console.NewBoolVar("r_vsync", true, console.Mutable, console.Serializable).
			Doc(`
r_vsync controls whether vsync is enabled. VSync tries to
keep the refreshing of the game in sync with the monitor's
refresh rate.
`)
	mouseSensitivity = console.NewIntVar("cl_mouse_speed", 8000, console.Mutable, console.Serializable).
				Doc(`
cl_mouse_speed controls how fast you rotate when moving
the mouse. Higher values means faster rotation.
`)
)

func init() {
	renderVSync.Callback(func() {
		if glfw.GetCurrentContext() == nil {
			return
		}
		if renderVSync.Value() {
			glfw.SwapInterval(1)
		} else {
			glfw.SwapInterval(0)
		}
	})
}

func startWindow() {
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 2)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	glfw.WindowHint(glfw.DepthBits, 32)
	glfw.WindowHint(glfw.StencilBits, 0)
	if os.Getenv("STEVEN_DEBUG") == "true" {
		glfw.WindowHint(glfw.OpenGLDebugContext, glfw.True)
	}

	var err error
	window, err = glfw.CreateWindow(854, 480, "Steven", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()
	if renderVSync.Value() {
		glfw.SwapInterval(1)
	} else {
		glfw.SwapInterval(0)
	}

	window.SetCursorPosCallback(onMouseMove)
	window.SetMouseButtonCallback(onMouseClick)
	window.SetKeyCallback(onKey)
	window.SetCharCallback(onChar)
	window.SetScrollCallback(onScroll)
	window.SetFocusCallback(onFocus)

	gl.Init()

	start()

	for !window.ShouldClose() {
		draw()
		window.SwapBuffers()
		glfw.PollEvents()
	}
}

func onScroll(w *glfw.Window, xoff float64, yoff float64) {
	if currentScreen != nil || !ready {
		return
	}
	if yoff < 0 {
		Client.currentHotbarSlot++
	} else {
		Client.currentHotbarSlot--
	}
	if Client.currentHotbarSlot < 0 {
		Client.currentHotbarSlot = 8
	} else if Client.currentHotbarSlot > 8 {
		Client.currentHotbarSlot = 0
	}

	Client.network.Write(&protocol.HeldItemChange{Slot: int16(Client.currentHotbarSlot)})
}

var lockMouse bool

func onFocus(w *glfw.Window, focused bool) {
	if !focused {
		lockMouse = false
		window.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
		for i := range Client.KeyState {
			Client.KeyState[i] = false
		}
	} else if lockMouse {
		w.SetInputMode(glfw.CursorMode, glfw.CursorDisabled)
	}
}

func onMouseMove(w *glfw.Window, xpos float64, ypos float64) {
	width, height := w.GetSize()
	if currentScreen != nil {
		fw, fh := w.GetFramebufferSize()
		currentScreen.hover(xpos*(float64(fw)/float64(width)), ypos*(float64(fh)/float64(height)), fw, fh)
		return
	}
	if !lockMouse {
		return
	}
	ww, hh := float64(width/2), float64(height/2)
	w.SetCursorPos(ww, hh)

	s := float64(10000-mouseSensitivity.Value()) + 0.01
	rotate((xpos-ww)/s, (ypos-hh)/s)
}

func onMouseClick(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
	if currentScreen != nil {
		if button != glfw.MouseButtonLeft || action == glfw.Repeat {
			return
		}
		width, height := w.GetSize()
		xpos, ypos := w.GetCursorPos()
		fw, fh := w.GetFramebufferSize()
		currentScreen.click(action == glfw.Press, xpos*(float64(fw)/float64(width)), ypos*(float64(fh)/float64(height)), fw, fh)
		return
	}
	if !Client.chat.enteringText && lockMouse && action != glfw.Repeat {
		Client.MouseAction(button, action == glfw.Press)
	}
	if button == glfw.MouseButtonLeft && action == glfw.Press && !Client.chat.enteringText {
		lockMouse = true
		w.SetInputMode(glfw.CursorMode, glfw.CursorDisabled)
	}
}

type Key int

const (
	KeyForward Key = iota
	KeyBackwards
	KeyLeft
	KeyRight
	KeySprint
	KeyJump
)

var keyStateMap = map[glfw.Key]Key{
	glfw.KeyW:           KeyForward,
	glfw.KeyS:           KeyBackwards,
	glfw.KeyA:           KeyLeft,
	glfw.KeyD:           KeyRight,
	glfw.KeyLeftControl: KeySprint,
	glfw.KeySpace:       KeyJump,
}

func onChar(w *glfw.Window, char rune) {
	if currentScreen != nil {
		ui.HandleChar(w, char)
	}
}

func onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	// Debug override
	if key == glfw.KeyGraveAccent && action == glfw.Release {
		con.focus()
		return
	}

	if currentScreen != nil {
		ui.HandleKey(w, key, scancode, action, mods)
		return
	}
	if Client.chat.enteringText {
		Client.chat.handleKey(w, key, scancode, action, mods)
		return
	}

	if k, ok := keyStateMap[key]; action != glfw.Repeat && ok {
		Client.KeyState[k] = action == glfw.Press
	}
	if key >= glfw.Key0 && key <= glfw.Key9 && action == glfw.Press {
		slot := int((8 + (key - glfw.Key0)) % 9)
		Client.currentHotbarSlot = slot
		Client.network.Write(&protocol.HeldItemChange{Slot: int16(Client.currentHotbarSlot)})
	}
	switch key {
	case glfw.KeyEscape:
		if action == glfw.Release {
			setScreen(newGameMenu())
		}
	case glfw.KeyF1:
		if action == glfw.Release {
			if Client.scene.IsVisible() {
				Client.scene.Hide()
				Client.hotbarScene.Hide()
			} else {
				Client.scene.Show()
				Client.hotbarScene.Show()
			}
		}
	case glfw.KeyF3:
		if action == glfw.Release {
			Client.toggleDebug()
		}
	case glfw.KeyF5:
		if action == glfw.Release {
			Client.cycleCamera()
		}
	case glfw.KeyTab:
		if action == glfw.Press {
			Client.playerList.set(true)
		} else if action == glfw.Release {
			Client.playerList.set(false)
		}
	case glfw.KeyE:
		if action == glfw.Release {
			wasPlayer := Client.activeInventory == Client.playerInventory
			closeInventory()
			if wasPlayer {
				return
			}
			openInventory(Client.playerInventory)
		}
	case glfw.KeyT:
		state := w.GetKey(glfw.KeyF3)
		if action == glfw.Release && state == glfw.Press {
			reloadResources()
			return
		}
		fallthrough
	case glfw.KeySlash:
		if action != glfw.Release {
			return
		}
		for i := range Client.KeyState {
			Client.KeyState[i] = false
		}
		Client.chat.enteringText = true
		if key == glfw.KeySlash {
			Client.chat.inputLine = append(Client.chat.inputLine, '/')
		}
		lockMouse = false
		w.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
		w.SetCharCallback(Client.chat.handleChar)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Pani Networks
// All Rights Reserved.
//
// 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 kubernetes implements kubernetes API specific
// helper functions.
package kubernetes

import (
	"github.com/romana/core/romana/util"
)

// GetTenantName returns kubernetes tenant name corresponding
// to the UUID being used in romana tenants.
func GetTenantName(uid string) (string, error) {
	return "", util.ErrUnimplementedFeature
}

// TenantExists returns true/false depending on
// kubernetes tenant name or uuid exists.
func TenantExists(name string) bool {
	// Unimplemented
	return false
}

// GetTenantUUID returns kubernetes tenant
// UUID corresponding to the name.
func GetTenantUUID(name string) (string, error) {
	return "", util.ErrUnimplementedFeature
}

// CreateTenant creates kubernetes specific tenant
// corresponding to the name given.
func CreateTenant(name string) error {
	return util.ErrUnimplementedFeature
}
<commit_msg>listener: remove file which was copied in wrong package by mistake.<commit_after><|endoftext|>


<commit_before>// +build windows,unit

// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 config

import (
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestParseGMSACapability(t *testing.T) {
	os.Setenv("ECS_GMSA_SUPPORTED", "False")
	defer os.Unsetenv("ECS_GMSA_SUPPORTED")

	assert.False(t, parseGMSACapability())
}
<commit_msg>Add a test for upper-to-lower conversion on parsing Windows env vars<commit_after>// +build windows,unit

// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 config

import (
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestParseGMSACapability(t *testing.T) {
	os.Setenv("ECS_GMSA_SUPPORTED", "False")
	defer os.Unsetenv("ECS_GMSA_SUPPORTED")

	assert.False(t, parseGMSACapability())
}

func TestParseBooleanEnvVar(t *testing.T) {
	os.Setenv("EXAMPLE_SETTING", "True")
	defer os.Unsetenv("EXAMPLE_SETTING")

	assert.True(t, parseBooleanDefaultFalseConfig("EXAMPLE_SETTING"))
	assert.True(t, parseBooleanDefaultTrueConfig("EXAMPLE_SETTING"))

	os.Setenv("EXAMPLE_SETTING", "False")
	assert.False(t, parseBooleanDefaultFalseConfig("EXAMPLE_SETTING"))
	assert.False(t, parseBooleanDefaultTrueConfig("EXAMPLE_SETTING"))
}
<|endoftext|>


<commit_before>package digraph

import (
	"container/list"
	"errors"
	"fmt"
)

var (
	// ErrCycle is returned when creating an edge between two vertices would result
	// in a cycle in the digraph
	ErrCycle = errors.New("digraph: cycle between edges")

	// ErrEdgeExists is returned when an edge between two vertices already exists
	ErrEdgeExists = errors.New("digraph: edge already exists")

	// ErrVertexExists is returned when a vertex with the same value already exists
	ErrVertexExists = errors.New("digraph: vertex already exists")
)

// Vertex represents a vertex or "node" in the digraph
type Vertex interface{}

// Digraph represents a "digraph", or directed graph data structure
type Digraph struct {
	adjList     map[Vertex]AdjacencyList
	edgeCount   int
	vertexCount int
}

// New creates a new acyclic Digraph, and initializes its adjacency list
func New() *Digraph {
	return &Digraph{
		adjList: map[Vertex]AdjacencyList{},
	}
}

// AddVertex tries to add a new vertex to the root of the adjacency list on the digraph
func (d *Digraph) AddVertex(vertex Vertex) error {
	// Check for a previous, identical vertex
	if _, found := d.adjList[vertex]; found {
		return ErrVertexExists
	}

	// Add the vertex to the adjacency list, initialize a new linked-list
	d.adjList[vertex] = AdjacencyList{list.New()}
	d.vertexCount++

	return nil
}

// AddEdge tries to add a new edge between two vertices on the adjacency list
func (d *Digraph) AddEdge(source Vertex, target Vertex) error {
	// Ensure vertices are not identical
	if source == target {
		return ErrCycle
	}

	// Add both vertices to the graph, ignoring if they already exist
	d.AddVertex(source)
	d.AddVertex(target)

	// Check if this digraph already has this edge
	if d.HasEdge(source, target) {
		// Return false, edge already exists
		return ErrEdgeExists
	}

	// Do a depth-first search from the target to the source to determine if a cycle will
	// result if this edge is created
	if d.DepthFirstSearch(target, source) {
		// Return false, a cycle will be created
		return ErrCycle
	}

	// Retrieve adjacency list
	adjList := d.adjList[source]

	// Target was not found, so add an edge between source and target
	adjList.list.PushBack(target)
	d.edgeCount++

	// Store adjacency list
	d.adjList[source] = adjList

	return nil
}

// discovered maps out which vertices have been discovered using Depth-First Search
var discovered map[Vertex]bool

// DepthFirstSearch searches the digraph for the target vertex, using the Depth-First
// Search algorithm, and returning true if a path to the target is found
func (d *Digraph) DepthFirstSearch(source Vertex, target Vertex) bool {
	// Clear discovery map
	discovered = map[Vertex]bool{}

	// Begin recursive Depth-First Search, looking for all vertices reachable from source
	d.dfs(source)

	// Check if target was discovered during Depth-First Search
	result := discovered[target]

	// Clear discovery map, return result
	discovered = map[Vertex]bool{}
	return result
}

// dfs implements a recursive Depth-First Search algorithm
func (d *Digraph) dfs(target Vertex) {
	// Get the adjacency list for this vertex
	adjList := d.adjList[target]

	// Check all adjacent vertices
	for _, v := range adjList.Adjacent() {
		// Check if vertex has not been discovered
		if !discovered[v] {
			// Mark it as discovered, recursively continue traversal
			discovered[v] = true
			d.dfs(v)
		}
	}
}

// EdgeCount returns the number of edges in the digraph
func (d *Digraph) EdgeCount() int {
	return d.edgeCount
}

// HasEdge determines if the digraph has an existing edge between source and target,
// returning true if it does, or false if it does not
func (d *Digraph) HasEdge(source Vertex, target Vertex) bool {
	// Retrieve adjacency list for this source
	adjList := d.adjList[source]

	// Search for target vertex
	if v := adjList.Search(target); v != nil {
		// Vertex is adjacent, edge exists
		return true
	}

	// No result, edge does not exist
	return false
}

// Print displays a printed "tree" of the digraph to the console
func (d *Digraph) Print(root Vertex) error {
	// Check if the vertex actually exists
	if _, ok := d.adjList[root]; !ok {
		return errors.New("digraph: root node does not exist, cannot print graph")
	}

	// Begin recursive printing at the specified root vertex
	d.printRecursive(root, "")
	return nil
}

// printRecursive handles the printing of each vertex in "tree" form
func (d *Digraph) printRecursive(vertex Vertex, prefix string) {
	// Print the current vertex
	fmt.Println(prefix, "-", vertex)

	// Get the current adjacency list, get adjacent vertices
	adjList := d.adjList[vertex]
	adjacent := adjList.Adjacent()

	// Iterate all adjacent vertices
	for i, v := range adjacent {
		// If last iteration, don't add a pipe character
		if i == len(adjacent)-1 {
			d.printRecursive(v, prefix+"    ")
		} else {
			// Add pipe character to show multiple items belong to same parent
			d.printRecursive(v, prefix+"   |")
		}
	}
}

// VertexCount returns the number of vertices in the digraph
func (d *Digraph) VertexCount() int {
	return d.vertexCount
}
<commit_msg>digraph.HasEdge: check if source edge exists<commit_after>package digraph

import (
	"container/list"
	"errors"
	"fmt"
)

var (
	// ErrCycle is returned when creating an edge between two vertices would result
	// in a cycle in the digraph
	ErrCycle = errors.New("digraph: cycle between edges")

	// ErrEdgeExists is returned when an edge between two vertices already exists
	ErrEdgeExists = errors.New("digraph: edge already exists")

	// ErrVertexExists is returned when a vertex with the same value already exists
	ErrVertexExists = errors.New("digraph: vertex already exists")
)

// Vertex represents a vertex or "node" in the digraph
type Vertex interface{}

// Digraph represents a "digraph", or directed graph data structure
type Digraph struct {
	adjList     map[Vertex]AdjacencyList
	edgeCount   int
	vertexCount int
}

// New creates a new acyclic Digraph, and initializes its adjacency list
func New() *Digraph {
	return &Digraph{
		adjList: map[Vertex]AdjacencyList{},
	}
}

// AddVertex tries to add a new vertex to the root of the adjacency list on the digraph
func (d *Digraph) AddVertex(vertex Vertex) error {
	// Check for a previous, identical vertex
	if _, found := d.adjList[vertex]; found {
		return ErrVertexExists
	}

	// Add the vertex to the adjacency list, initialize a new linked-list
	d.adjList[vertex] = AdjacencyList{list.New()}
	d.vertexCount++

	return nil
}

// AddEdge tries to add a new edge between two vertices on the adjacency list
func (d *Digraph) AddEdge(source Vertex, target Vertex) error {
	// Ensure vertices are not identical
	if source == target {
		return ErrCycle
	}

	// Add both vertices to the graph, ignoring if they already exist
	d.AddVertex(source)
	d.AddVertex(target)

	// Check if this digraph already has this edge
	if d.HasEdge(source, target) {
		// Return false, edge already exists
		return ErrEdgeExists
	}

	// Do a depth-first search from the target to the source to determine if a cycle will
	// result if this edge is created
	if d.DepthFirstSearch(target, source) {
		// Return false, a cycle will be created
		return ErrCycle
	}

	// Retrieve adjacency list
	adjList := d.adjList[source]

	// Target was not found, so add an edge between source and target
	adjList.list.PushBack(target)
	d.edgeCount++

	// Store adjacency list
	d.adjList[source] = adjList

	return nil
}

// discovered maps out which vertices have been discovered using Depth-First Search
var discovered map[Vertex]bool

// DepthFirstSearch searches the digraph for the target vertex, using the Depth-First
// Search algorithm, and returning true if a path to the target is found
func (d *Digraph) DepthFirstSearch(source Vertex, target Vertex) bool {
	// Clear discovery map
	discovered = map[Vertex]bool{}

	// Begin recursive Depth-First Search, looking for all vertices reachable from source
	d.dfs(source)

	// Check if target was discovered during Depth-First Search
	result := discovered[target]

	// Clear discovery map, return result
	discovered = map[Vertex]bool{}
	return result
}

// dfs implements a recursive Depth-First Search algorithm
func (d *Digraph) dfs(target Vertex) {
	// Get the adjacency list for this vertex
	adjList := d.adjList[target]

	// Check all adjacent vertices
	for _, v := range adjList.Adjacent() {
		// Check if vertex has not been discovered
		if !discovered[v] {
			// Mark it as discovered, recursively continue traversal
			discovered[v] = true
			d.dfs(v)
		}
	}
}

// EdgeCount returns the number of edges in the digraph
func (d *Digraph) EdgeCount() int {
	return d.edgeCount
}

// HasEdge determines if the digraph has an existing edge between source and target,
// returning true if it does, or false if it does not
func (d *Digraph) HasEdge(source Vertex, target Vertex) bool {
	// Check if the source vertex exists
	if _, found := d.adjList[source]; !found {
		return false
	}

	// Retrieve adjacency list for this source
	adjList := d.adjList[source]

	// Search for target vertex
	if v := adjList.Search(target); v != nil {
		// Vertex is adjacent, edge exists
		return true
	}

	// No result, edge does not exist
	return false
}

// Print displays a printed "tree" of the digraph to the console
func (d *Digraph) Print(root Vertex) error {
	// Check if the vertex actually exists
	if _, ok := d.adjList[root]; !ok {
		return errors.New("digraph: root node does not exist, cannot print graph")
	}

	// Begin recursive printing at the specified root vertex
	d.printRecursive(root, "")
	return nil
}

// printRecursive handles the printing of each vertex in "tree" form
func (d *Digraph) printRecursive(vertex Vertex, prefix string) {
	// Print the current vertex
	fmt.Println(prefix, "-", vertex)

	// Get the current adjacency list, get adjacent vertices
	adjList := d.adjList[vertex]
	adjacent := adjList.Adjacent()

	// Iterate all adjacent vertices
	for i, v := range adjacent {
		// If last iteration, don't add a pipe character
		if i == len(adjacent)-1 {
			d.printRecursive(v, prefix+"    ")
		} else {
			// Add pipe character to show multiple items belong to same parent
			d.printRecursive(v, prefix+"   |")
		}
	}
}

// VertexCount returns the number of vertices in the digraph
func (d *Digraph) VertexCount() int {
	return d.vertexCount
}
<|endoftext|>


<commit_before>// (c) Copyright 2015 JONNALAGADDA Srinivas
//
// 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 flow

import (
	"database/sql"
	"errors"
	"strings"
)

// DocType enumerates the types of documents in the system, as defined
// by the consuming application.  Each document type has an associated
// workflow definition that drives its life cycle.
//
// Accordingly, `flow` does not assume anything about the specifics of
// the any document type.  Instead, it treats document types as plain,
// but controlled, vocabulary.  Nonetheless, it is highly recommended,
// but not necessary, that document types be defined in a system of
// hierarchical namespaces. For example:
//
//     PUR:RFQ
//
// could mean that the department is 'Purchasing', while the document
// type is 'Request For Quotation'.  As a variant,
//
//     PUR:ORD
//
// could mean that the document type is 'Purchase Order'.
//
// N.B. All document types must be defined as constant strings.
type DocType string

// NewDocType creates and registers a new document type in the system.
func NewDocType(otx *sql.Tx, dt DocType) error {
	name := strings.TrimSpace(string(dt))
	if name == "" {
		return errors.New("document type cannot be empty")
	}

	var tx *sql.Tx
	if otx == nil {
		tx, err := db.Begin()
		if err != nil {
			return err
		}
		defer tx.Rollback()
	} else {
		tx = otx
	}

	_, err := tx.Exec("INSERT INTO wf_doctypes_master(name) VALUES(?)", name)
	if err != nil {
		return err
	}

	if otx == nil {
		err = tx.Commit()
		if err != nil {
			return err
		}
	}
	return nil
}

// DocTypeExists answers `true` if a document type with the given name
// is registered; `false` otherwise.
func DocTypeExists(dt DocType) (bool, error) {
	name := strings.TrimSpace(string(dt))
	if name == "" {
		return false, errors.New("document type cannot be empty")
	}

	row := db.QueryRow("SELECT COUNT(*) from wf_doctypes_master WHERE name = ?", name)
	var n int64
	err := row.Scan(&n)
	if err != nil {
		return false, err
	}

	if n == 0 {
		return false, nil
	}
	return true, nil
}
<commit_msg>Provide a resource-like interface to `DocType`<commit_after>// (c) Copyright 2015 JONNALAGADDA Srinivas
//
// 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 flow

import (
	"database/sql"
	"errors"
	"math"
	"strings"
)

// DocType enumerates the types of documents in the system, as defined
// by the consuming application.  Each document type has an associated
// workflow definition that drives its life cycle.
//
// Accordingly, `flow` does not assume anything about the specifics of
// the any document type.  Instead, it treats document types as plain,
// but controlled, vocabulary.  Nonetheless, it is highly recommended,
// but not necessary, that document types be defined in a system of
// hierarchical namespaces. For example:
//
//     PUR:RFQ
//
// could mean that the department is 'Purchasing', while the document
// type is 'Request For Quotation'.  As a variant,
//
//     PUR:ORD
//
// could mean that the document type is 'Purchase Order'.
//
// N.B. All document types must be defined as constant strings.
type DocType string

// Unexported type, only for convenience methods.
type _DocTypes struct{}

var _doctypes *_DocTypes

func init() {
	_doctypes = &_DocTypes{}
}

// DocTypes provides a resource-like interface to document types in
// the system.
func DocTypes() *_DocTypes {
	return _doctypes
}

// List answers a subset of the document types, based on the input
// specification.
//
// Result set begins with ID >= `offset`, and has not more than
// `limit` elements.  A value of `0` for `offset` fetches from the
// beginning, while a value of `0` for `limit` fetches until the end.
func (dts *_DocTypes) List(offset, limit int64) ([]DocType, error) {
	if offset < 0 || limit < 0 {
		return nil, errors.New("offset and limit must be non-negative integers")
	}
	if limit == 0 {
		limit = math.MaxInt64
	}

	q := `
	SELECT name
	FROM wf_doctypes_master
	ORDER BY id
	LIMIT ? OFFSET ?
	`
	rows, err := db.Query(q, limit, offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var name string
	dtary := make([]DocType, 0, 10)
	for rows.Next() {
		err = rows.Scan(&name)
		if err != nil {
			return nil, err
		}
		dtary = append(dtary, DocType(name))
	}
	if err = rows.Err(); err != nil {
		return nil, err
	}

	return dtary, nil
}

// New creates and registers a new document type in the system.
func (dts *_DocTypes) New(otx *sql.Tx, dt DocType) error {
	name := strings.TrimSpace(string(dt))
	if name == "" {
		return errors.New("document type cannot be empty")
	}

	var tx *sql.Tx
	if otx == nil {
		tx, err := db.Begin()
		if err != nil {
			return err
		}
		defer tx.Rollback()
	} else {
		tx = otx
	}

	_, err := tx.Exec("INSERT INTO wf_doctypes_master(name) VALUES(?)", name)
	if err != nil {
		return err
	}

	if otx == nil {
		err = tx.Commit()
		if err != nil {
			return err
		}
	}
	return nil
}

// Exists answers `true` if a document type with the given name is
// registered; `false` otherwise.
func (dts *_DocTypes) Exists(dt DocType) (bool, error) {
	name := strings.TrimSpace(string(dt))
	if name == "" {
		return false, errors.New("document type cannot be empty")
	}

	row := db.QueryRow("SELECT COUNT(*) from wf_doctypes_master WHERE name = ?", name)
	var n int64
	err := row.Scan(&n)
	if err != nil {
		return false, err
	}

	if n == 0 {
		return false, nil
	}
	return true, nil
}
<|endoftext|>


<commit_before>package kinesis

import (
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/gliderlabs/logspout/router"
)

type Drainer struct {
	Buffer *recordBuffer
}

func newDrainer(a *KinesisAdapter, streamName string, m *router.Message) {
	buffer, err := newRecordBuffer(a.Client, streamName)
	if err != nil {
		logErr(err)
	}

	d := &Drainer{Buffer: buffer}
	go d.Drain()

	if os.Getenv("KINESIS_STREAM_CREATION") == "true" {
		createStream(a, d, streamName, m)
	} else {
		a.addDrainer(streamName, d)
	}
}

// Drain flushes the buffer every second.
func (d *Drainer) Drain() {
	for _ = range time.Tick(time.Second * 1) {
		logErr(d.Buffer.Flush())
	}
}

func createStream(a *KinesisAdapter, d *Drainer, streamName string, m *router.Message) {
	_, err := a.Client.CreateStream(&kinesis.CreateStreamInput{
		ShardCount: aws.Int64(1),
		StreamName: aws.String(streamName),
	})

	if err != nil {
		if reqErr, ok := err.(awserr.RequestFailure); ok {
			if reqErr.Code() == "ResourceInUseException" {
				a.addDrainer(streamName, d)
			} else {
				logErr(err)
			}
		} else {
			logErr(err)
		}
	} else {
		debugLog("kinesis: need to create stream for %s", streamName)
		waitForActive(a, d, m)
	}
}

func waitForActive(a *KinesisAdapter, d *Drainer, m *router.Message) {
	streamName := *d.Buffer.input.StreamName
	var streamStatus string

	params := &kinesis.DescribeStreamInput{StreamName: aws.String(streamName)}
	resp := &kinesis.DescribeStreamOutput{}
	for {
		resp, _ = a.Client.DescribeStream(params)
		if streamStatus = *resp.StreamDescription.StreamStatus; streamStatus == "ACTIVE" {
			logErr(tagStream(a, streamName, m))
			a.addDrainer(streamName, d)
			break
		} else {
			time.Sleep(4 * time.Second)
		}

		debugLog("kinesis: status for stream %s: %s", streamName, streamStatus)
	}
}

func tagStream(a *KinesisAdapter, streamName string, m *router.Message) error {
	if os.Getenv("KINESIS_TAG_STREAM") == "true" {
		if tagKey := os.Getenv("KINESIS_STREAM_TAG_KEY"); tagKey != "" {
			tmpl, err := compileTmpl("KINESIS_STREAM_TAG_VALUE")
			if err != nil {
				return err
			}

			tagValue, err := executeTmpl(tmpl, m)
			if err != nil {
				return err
			}

			tags := map[string]*string{
				tagKey: aws.String(tagValue),
			}

			params := &kinesis.AddTagsToStreamInput{
				StreamName: aws.String(streamName),
				Tags:       tags,
			}

			_, err = a.Client.AddTagsToStream(params)
			return err
		}

		return nil
	}

	return nil
}
<commit_msg>Reduce to two environment variable.<commit_after>package kinesis

import (
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/gliderlabs/logspout/router"
)

type Drainer struct {
	Buffer *recordBuffer
}

func newDrainer(a *KinesisAdapter, streamName string, m *router.Message) {
	buffer, err := newRecordBuffer(a.Client, streamName)
	if err != nil {
		logErr(err)
	}

	d := &Drainer{Buffer: buffer}
	go d.Drain()

	if os.Getenv("KINESIS_STREAM_CREATION") == "true" {
		createStream(a, d, streamName, m)
	} else {
		a.addDrainer(streamName, d)
	}
}

// Drain flushes the buffer every second.
func (d *Drainer) Drain() {
	for _ = range time.Tick(time.Second * 1) {
		logErr(d.Buffer.Flush())
	}
}

func createStream(a *KinesisAdapter, d *Drainer, streamName string, m *router.Message) {
	_, err := a.Client.CreateStream(&kinesis.CreateStreamInput{
		ShardCount: aws.Int64(1),
		StreamName: aws.String(streamName),
	})

	if err != nil {
		if reqErr, ok := err.(awserr.RequestFailure); ok {
			if reqErr.Code() == "ResourceInUseException" {
				a.addDrainer(streamName, d)
			} else {
				logErr(err)
			}
		} else {
			logErr(err)
		}
	} else {
		debugLog("kinesis: need to create stream for %s", streamName)
		waitForActive(a, d, m)
	}
}

func waitForActive(a *KinesisAdapter, d *Drainer, m *router.Message) {
	streamName := *d.Buffer.input.StreamName
	var streamStatus string

	params := &kinesis.DescribeStreamInput{StreamName: aws.String(streamName)}
	resp := &kinesis.DescribeStreamOutput{}
	for {
		resp, _ = a.Client.DescribeStream(params)
		if streamStatus = *resp.StreamDescription.StreamStatus; streamStatus == "ACTIVE" {
			logErr(tagStream(a, streamName, m))
			a.addDrainer(streamName, d)
			break
		} else {
			time.Sleep(4 * time.Second)
		}

		debugLog("kinesis: status for stream %s: %s", streamName, streamStatus)
	}
}

func tagStream(a *KinesisAdapter, streamName string, m *router.Message) error {
	if tagKey := os.Getenv("KINESIS_STREAM_TAG_KEY"); tagKey != "" {
		tmpl, err := compileTmpl("KINESIS_STREAM_TAG_VALUE")
		if err != nil {
			return err
		}

		tagValue, err := executeTmpl(tmpl, m)
		if err != nil {
			return err
		}

		tags := map[string]*string{
			tagKey: aws.String(tagValue),
		}

		params := &kinesis.AddTagsToStreamInput{
			StreamName: aws.String(streamName),
			Tags:       tags,
		}

		_, err = a.Client.AddTagsToStream(params)
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>//
// dswalgo.go - an implementation of the Day-Stout-Warren algorithm (DSW), a method of rebalancing the ordinary Binary Search Trees
//
// see more at: http://en.wikipedia.org/wiki/Day-Stout-Warren_algorithm

package forest

import (
//    "fmt"
)

// Rebalance the BST.
func Balance(tree *BinTree) {

	if tree.Root == nil {
		return
	}

	root := Tree2Vine(tree.Root)
	//    traverseVine(root) // DEBUG
	tree.Root = Vine2Tree(root, tree.Len)
	updateParents(tree)
}

// Converts a BST into a vine (sorted linked list) using left pointers.
func Tree2Vine(root *Node) *Node {

	var prev *Node = nil
	var cur *Node = root
	var temp *Node = nil

	for cur != nil {

		if cur.right == nil {
			// if there's no right child, we don't need to do anything
			prev = cur
			cur = cur.left
		} else {
			// otherwise we need to make left rotation: right child is inserted between current and previous (parent) node
			temp = cur.right
			cur.right = temp.left
			temp.left = cur
			cur = temp
			if prev != nil { // prev can be empty, when prev is root...
				prev.left = temp
			}

			if cur.Data > root.Data { // define new vine root
				root = cur
			}
		}
	}
	return root
}

// Calculate the number of leaves in the bottom level of the balanced tree
func numOfLeaves(size int) int {

	leaves, next := size+1, 0
	for {
		next = leaves & (leaves - 1)
		if next == 0 {
			break
		}
		leaves = next
	}
	return size + 1 - leaves
}

// Transform the given vine into a balanced tree.
func Vine2Tree(root *Node, size int) *Node {

	// calculate the number of leaves in the bottom level of the balanced tree
	leaves := numOfLeaves(size)

	// now do the compression
	// the first compression iteration is to reduce the compression to general case; only when leaves > 0 (!)
	if leaves > 0 {
		root = compress(root, leaves)
	}
	vine := size - leaves // number of nodes in main vine

	for vine > 1 {
		vine /= 2
		root = compress(root, int(vine))
	}
	return root
}

// Vine-to-balanced-tree compress helper function.
func compress(root *Node, count int) *Node {

	red := root
	black := red.left

	root = black // new root
	root.parent = nil

	for ; count != 0; count -= 1 {
		red.left = black.right
		black.right = red
		red = black.left
		if count != 1 { // the last count this step must be omitted; otherwise we lose an element...
			black.left = red.left
		}
		black = red.left
	}

	return root
}

// Update the parent pointers after the tree's been rebalanced.
func updateParents(bt *BinTree) {

	var cur *Node = bt.Root
	var prev *Node = nil
	var next *Node = nil

	cur.parent = nil // make sure root's parent does not point anywhere...
	for cur != nil {

		switch {
		case prev == cur.parent: // we are in parent node, we try to go left, then right, then back to parent
			if cur.left != nil {
				next = cur.left
				next.parent = cur
			} else if cur.right != nil {
				next = cur.right
				next.parent = cur
			} else {
				next = cur.parent
			}
		case prev == cur.left: // we are in left element: we try to go right, then back to parent
			if cur.right != nil {
				next = cur.right
				next.parent = cur
			} else {
				next = cur.parent
			}
		default: // we are in right element, go back to parent
			next = cur.parent
		}
		prev = cur
		cur = next
	}
}

/*
func traverseVine(root *Node) {
    fmt.Print("Traversing vine: ")
    for cur := root; cur != nil; cur = cur.left {
        fmt.Printf("%d ", cur.Data)
    }
    fmt.Println()
}
*/
<commit_msg>Code has cleaned and golint-ed.<commit_after>package forest

//
// dswalgo.go - an implementation of the Day-Stout-Warren algorithm (DSW), a method of rebalancing the ordinary Binary Search Trees
//
// see more at: http://en.wikipedia.org/wiki/Day-Stout-Warren_algorithm

import (
//    "fmt"
)

// Balance rebalances the BST.
func Balance(tree *BinTree) {

	if tree.Root == nil {
		return
	}

	root := Tree2Vine(tree.Root)
	//    traverseVine(root) // DEBUG
	tree.Root = Vine2Tree(root, tree.Len)
	updateParents(tree)
}

// Tree2Vine converts a BST into a vine (sorted linked list) using left pointers.
func Tree2Vine(root *Node) *Node {

	var prev *Node
	var temp *Node
	var cur = root

	for cur != nil {

		if cur.right == nil {
			// if there's no right child, we don't need to do anything
			prev = cur
			cur = cur.left
		} else {
			// otherwise we need to make left rotation: right child is inserted between current and previous (parent) node
			temp = cur.right
			cur.right = temp.left
			temp.left = cur
			cur = temp
			if prev != nil { // prev can be empty, when prev is root...
				prev.left = temp
			}

			if cur.Data > root.Data { // define new vine root
				root = cur
			}
		}
	}
	return root
}

// Calculates the number of leaves in the bottom level of the balanced tree
func numOfLeaves(size int) int {

	leaves, next := size+1, 0
	for {
		next = leaves & (leaves - 1)
		if next == 0 {
			break
		}
		leaves = next
	}
	return size + 1 - leaves
}

// Vine2Tree transforms the given vine back into a balanced tree.
func Vine2Tree(root *Node, size int) *Node {

	// calculate the number of leaves in the bottom level of the balanced tree
	leaves := numOfLeaves(size)

	// now do the compression
	// the first compression iteration is to reduce the compression to general case; only when leaves > 0 (!)
	if leaves > 0 {
		root = compress(root, leaves)
	}
	vine := size - leaves // number of nodes in main vine

	for vine > 1 {
		vine /= 2
		root = compress(root, int(vine))
	}
	return root
}

// Vine-to-balanced-tree compress helper function.
func compress(root *Node, count int) *Node {

	red := root
	black := red.left

	root = black // new root
	root.parent = nil

	for ; count != 0; count-- {
		red.left = black.right
		black.right = red
		red = black.left
		if count != 1 { // the last count this step must be omitted; otherwise we lose an element...
			black.left = red.left
		}
		black = red.left
	}

	return root
}

// Update the parent pointers after the tree's been rebalanced.
func updateParents(bt *BinTree) {

	var cur = bt.Root
	var prev *Node
	var next *Node

	cur.parent = nil // make sure root's parent does not point anywhere...
	for cur != nil {

		switch {
		case prev == cur.parent: // we are in parent node, we try to go left, then right, then back to parent
			if cur.left != nil {
				next = cur.left
				next.parent = cur
			} else if cur.right != nil {
				next = cur.right
				next.parent = cur
			} else {
				next = cur.parent
			}
		case prev == cur.left: // we are in left element: we try to go right, then back to parent
			if cur.right != nil {
				next = cur.right
				next.parent = cur
			} else {
				next = cur.parent
			}
		default: // we are in right element, go back to parent
			next = cur.parent
		}
		prev = cur
		cur = next
	}
}

/*
func traverseVine(root *Node) {
    fmt.Print("Traversing vine: ")
    for cur := root; cur != nil; cur = cur.left {
        fmt.Printf("%d ", cur.Data)
    }
    fmt.Println()
}
*/
<|endoftext|>


<commit_before>//usr/bin/env go run $0 $@; exit
//
// Copyright 2015 The elastic.go authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Author: Robin Hahling <robin.hahling@gw-computing.net>

// elastic.go is a command line tool to query the Elasticsearch REST API.
package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"strings"

	"github.com/gilliek/go-xterm256/xterm256"
	"github.com/hokaccha/go-prettyjson"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "elastic"
	app.Usage = "A command line tool to query the Elasticsearch REST API"
	app.Version = "1.0.1"
	app.Author = "Robin Hahling"
	app.Email = "robin.hahling@gw-computing.net"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "baseurl",
			Value: "http://localhost:9200/",
			Usage: "Base API URL",
		},
		cli.BoolFlag{
			Name:  "trace",
			Usage: "Trace URLs called",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:      "cluster",
			ShortName: "c",
			Usage:     "Get cluster information ",
			Subcommands: []cli.Command{
				{
					Name:      "health",
					ShortName: "he",
					Usage:     "Get cluster health",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdCluster(c, "health"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
				{
					// TODO can we get metrics args to this thing?
					// https://www.elastic.co/guide/en/elasticsearch/reference/5.6/cluster-state.html
					Name:      "state",
					ShortName: "s",
					Usage:     "Get cluster state",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdCluster(c, "state"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
				{
					Name:      "stats",
					ShortName: "t",
					Usage:     "Get cluster stats",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdCluster(c, "stats"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
			},
		},
		{
			Name:      "index",
			ShortName: "i",
			Usage:     "Get index information",
			Subcommands: []cli.Command{
				{
					Name:      "docs-count",
					ShortName: "dc",
					Usage:     "Get index documents count",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						for _, idx := range filteredDocsCountIndexes(list) {
							fmt.Println(idx)
						}
					},
				},
				{
					Name:      "list",
					ShortName: "l",
					Usage:     "List all indexes",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						for _, idx := range filteredListIndexes(list) {
							fmt.Println(idx)
						}
					},
				},
				{
					Name:      "size",
					ShortName: "si",
					Usage:     "Get index size",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						for _, idx := range filteredSizeIndexes(list) {
							fmt.Println(idx)
						}
					},
				},
				{
					Name:      "status",
					ShortName: "st",
					Usage:     "Get index status",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						for _, idx := range filteredStatusIndexes(list) {
							fmt.Println(idx)
						}
					},
				},
				{
					Name:      "verbose",
					ShortName: "v",
					Usage:     "List indexes information with many stats",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(list)
					},
				},
			},
		},
		{
			Name:      "node",
			ShortName: "n",
			Usage:     "Get cluster nodes information",
			Subcommands: []cli.Command{
				{
					Name:      "list",
					ShortName: "l",
					Usage:     "List nodes information",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdNode(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
				{
					Name:      "stats",
					ShortName: "s",
					Usage:     "List node stats",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdNode(c, "stats"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
			},
		},
		{
			Name:      "query",
			ShortName: "q",
			Usage:     "Perform any ES API GET query",
			Action: func(c *cli.Context) {
				var out string
				var err error
				if strings.Contains(c.Args().First(), "_cat/") {
					out, err = getRaw(cmdQuery(c), c)
				} else {
					out, err = getJSON(cmdQuery(c), c)
				}
				if err != nil {
					fatal(err)
				}
				fmt.Println(out)
			},
		},
		{
			Name:      "stats",
			ShortName: "s",
			Usage:     "Get statistics",
			Subcommands: []cli.Command{
				{
					Name:      "size",
					ShortName: "s",
					Usage:     "Get index sizes",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdStats(c, "size"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
			},
		},
	}

	app.Run(os.Args)
}

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

func getJSON(route string, c *cli.Context) (string, error) {
	r, err := httpGet(route, isTraceEnabled(c))
	if err != nil {
		return "", err
	}
	defer r.Body.Close()

	if r.StatusCode != 200 {
		return "", fmt.Errorf("unexpected status code: %s", r.Status)
	}

	mediatype, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
	if err != nil {
		return "", err
	}
	if mediatype == "" {
		return "", errors.New("mediatype not set")
	}
	if mediatype != "application/json" {
		return "", fmt.Errorf("mediatype is '%s', 'application/json' expected", mediatype)
	}

	var b interface{}
	if err := json.NewDecoder(r.Body).Decode(&b); err != nil {
		return "", err
	}
	out, err := prettyjson.Marshal(b)
	return string(out), err
}

func getRaw(route string, c *cli.Context) (string, error) {
	r, err := httpGet(route, isTraceEnabled(c))

	if err != nil {
		return "", err
	}
	defer r.Body.Close()

	if r.StatusCode != 200 {
		return "", fmt.Errorf("unexpected status code: %s", r.Status)
	}

	out, err := ioutil.ReadAll(r.Body)
	return string(out), err
}

// processing functions
func filteredDocsCountIndexes(list string) []string {
	var out []string
	scanner := bufio.NewScanner(strings.NewReader(list))
	for scanner.Scan() {
		elmts := strings.Fields(scanner.Text())
		if len(elmts) < 6 {
			continue
		}
		out = append(out, fmt.Sprintf("%10s %s", colorizeStatus(elmts[5]), elmts[2]))
	}
	return out
}

func filteredListIndexes(list string) []string {
	var out []string
	scanner := bufio.NewScanner(strings.NewReader(list))
	for scanner.Scan() {
		elmts := strings.Fields(scanner.Text())
		if len(elmts) < 3 {
			continue
		}
		out = append(out, elmts[2])
	}
	return out
}

func filteredStatusIndexes(list string) []string {
	var out []string
	scanner := bufio.NewScanner(strings.NewReader(list))
	for scanner.Scan() {
		elmts := strings.Fields(scanner.Text())
		if len(elmts) < 3 {
			continue
		}
		out = append(out, fmt.Sprintf("%22s %s", colorizeStatus(elmts[0]), elmts[2]))
	}
	return out
}

func filteredSizeIndexes(list string) []string {
	var out []string
	scanner := bufio.NewScanner(strings.NewReader(list))
	for scanner.Scan() {
		elmts := strings.Fields(scanner.Text())
		if len(elmts) < 8 {
			continue
		}
		out = append(out, fmt.Sprintf("%10s %s", elmts[7], elmts[2]))
	}
	return out
}

func colorizeStatus(status string) string {
	var color xterm256.Color
	switch status {
	case "red":
		color = xterm256.Red
	case "green":
		color = xterm256.Green
	case "yellow":
		color = xterm256.Yellow
	default:
		return status
	}
	return xterm256.Sprint(color, status)
}

// command-line commands from now on
func cmdCluster(c *cli.Context, subCmd string) string {
	route := "_cluster/"
	url := c.GlobalString("baseurl")

	var arg string
	switch subCmd {
	case "health":
		arg = "health"
	case "state":
		arg = "state"
	case "stats":
		arg = "stats"
	default:
		arg = ""
	}
	return url + route + arg
}

func cmdIndex(c *cli.Context, subCmd string) string {
	var route string
	url := c.GlobalString("baseurl")
	switch subCmd {
	case "list":
		route = "_cat/indices?v"
	default:
		route = ""
	}
	return url + route
}

func cmdNode(c *cli.Context, subCmd string) string {
	var route string
	url := c.GlobalString("baseurl")
	switch subCmd {
	case "list":
		route = "_nodes/_all/host,ip"
	case "stats":
		route = "_nodes/_all/stats"
	default:
		route = ""
	}
	return url + route
}

func cmdQuery(c *cli.Context) string {
	route := c.Args().First()
	url := c.GlobalString("baseurl")
	return url + route
}

func cmdStats(c *cli.Context, subCmd string) string {
	var route string
	url := c.GlobalString("baseurl")
	switch subCmd {
	case "size":
		route = "_stats/index,store"
	default:
		route = ""
	}
	return url + route
}

func httpGet(route string, trace bool) (*http.Response, error) {
	if trace {
		fmt.Fprintf(os.Stderr, "GET: %s", route)
	}
	r, err := http.Get(route)

	return r, err
}

func isTraceEnabled(c *cli.Context) bool {
	return c.GlobalBool("trace")
}
<commit_msg>Allow filter args for cluster and node commands<commit_after>//usr/bin/env go run $0 $@; exit
//
// Copyright 2015 The elastic.go authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Author: Robin Hahling <robin.hahling@gw-computing.net>

// elastic.go is a command line tool to query the Elasticsearch REST API.
package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"strings"

	"github.com/gilliek/go-xterm256/xterm256"
	"github.com/hokaccha/go-prettyjson"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "elastic"
	app.Usage = "A command line tool to query the Elasticsearch REST API"
	app.Version = "1.0.1"
	app.Author = "Robin Hahling"
	app.Email = "robin.hahling@gw-computing.net"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "baseurl",
			Value: "http://localhost:9200/",
			Usage: "Base API URL",
		},
		cli.BoolFlag{
			Name:  "trace",
			Usage: "Trace URLs called",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:      "cluster",
			ShortName: "c",
			Usage:     "Get cluster information ",
			Subcommands: []cli.Command{
				{
					Name:      "health",
					ShortName: "he",
					Usage:     "Get cluster health",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdCluster(c, "health"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
				{
					Name:      "state",
					ShortName: "s",
					Usage:     "Get cluster state (allows filter args)",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdCluster(c, "state"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
				{
					Name:      "stats",
					ShortName: "t",
					Usage:     "Get cluster stats",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdCluster(c, "stats"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
			},
		},
		{
			Name:      "index",
			ShortName: "i",
			Usage:     "Get index information",
			Subcommands: []cli.Command{
				{
					Name:      "docs-count",
					ShortName: "dc",
					Usage:     "Get index documents count",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						for _, idx := range filteredDocsCountIndexes(list) {
							fmt.Println(idx)
						}
					},
				},
				{
					Name:      "list",
					ShortName: "l",
					Usage:     "List all indexes",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						for _, idx := range filteredListIndexes(list) {
							fmt.Println(idx)
						}
					},
				},
				{
					Name:      "size",
					ShortName: "si",
					Usage:     "Get index size",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						for _, idx := range filteredSizeIndexes(list) {
							fmt.Println(idx)
						}
					},
				},
				{
					Name:      "status",
					ShortName: "st",
					Usage:     "Get index status",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						for _, idx := range filteredStatusIndexes(list) {
							fmt.Println(idx)
						}
					},
				},
				{
					Name:      "verbose",
					ShortName: "v",
					Usage:     "List indexes information with many stats",
					Action: func(c *cli.Context) {
						list, err := getRaw(cmdIndex(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(list)
					},
				},
			},
		},
		{
			Name:      "node",
			ShortName: "n",
			Usage:     "Get cluster nodes information",
			Subcommands: []cli.Command{
				{
					Name:      "list",
					ShortName: "l",
					Usage:     "List nodes information",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdNode(c, "list"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
				{
					Name:      "stats",
					ShortName: "s",
					Usage:     "List node stats (allows filter args)",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdNode(c, "stats"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
			},
		},
		{
			Name:      "query",
			ShortName: "q",
			Usage:     "Perform any ES API GET query",
			Action: func(c *cli.Context) {
				var out string
				var err error
				if strings.Contains(c.Args().First(), "_cat/") {
					out, err = getRaw(cmdQuery(c), c)
				} else {
					out, err = getJSON(cmdQuery(c), c)
				}
				if err != nil {
					fatal(err)
				}
				fmt.Println(out)
			},
		},
		{
			Name:      "stats",
			ShortName: "s",
			Usage:     "Get statistics",
			Subcommands: []cli.Command{
				{
					Name:      "size",
					ShortName: "s",
					Usage:     "Get index sizes",
					Action: func(c *cli.Context) {
						out, err := getJSON(cmdStats(c, "size"), c)
						if err != nil {
							fatal(err)
						}
						fmt.Println(out)
					},
				},
			},
		},
	}

	app.Run(os.Args)
}

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

func getJSON(route string, c *cli.Context) (string, error) {
	r, err := httpGet(route, isTraceEnabled(c))
	if err != nil {
		return "", err
	}
	defer r.Body.Close()

	if r.StatusCode != 200 {
		return "", fmt.Errorf("unexpected status code: %s", r.Status)
	}

	mediatype, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
	if err != nil {
		return "", err
	}
	if mediatype == "" {
		return "", errors.New("mediatype not set")
	}
	if mediatype != "application/json" {
		return "", fmt.Errorf("mediatype is '%s', 'application/json' expected", mediatype)
	}

	var b interface{}
	if err := json.NewDecoder(r.Body).Decode(&b); err != nil {
		return "", err
	}
	out, err := prettyjson.Marshal(b)
	return string(out), err
}

func getRaw(route string, c *cli.Context) (string, error) {
	r, err := httpGet(route, isTraceEnabled(c))

	if err != nil {
		return "", err
	}
	defer r.Body.Close()

	if r.StatusCode != 200 {
		return "", fmt.Errorf("unexpected status code: %s", r.Status)
	}

	out, err := ioutil.ReadAll(r.Body)
	return string(out), err
}

// processing functions
func filteredDocsCountIndexes(list string) []string {
	var out []string
	scanner := bufio.NewScanner(strings.NewReader(list))
	for scanner.Scan() {
		elmts := strings.Fields(scanner.Text())
		if len(elmts) < 6 {
			continue
		}
		out = append(out, fmt.Sprintf("%10s %s", colorizeStatus(elmts[5]), elmts[2]))
	}
	return out
}

func filteredListIndexes(list string) []string {
	var out []string
	scanner := bufio.NewScanner(strings.NewReader(list))
	for scanner.Scan() {
		elmts := strings.Fields(scanner.Text())
		if len(elmts) < 3 {
			continue
		}
		out = append(out, elmts[2])
	}
	return out
}

func filteredStatusIndexes(list string) []string {
	var out []string
	scanner := bufio.NewScanner(strings.NewReader(list))
	for scanner.Scan() {
		elmts := strings.Fields(scanner.Text())
		if len(elmts) < 3 {
			continue
		}
		out = append(out, fmt.Sprintf("%22s %s", colorizeStatus(elmts[0]), elmts[2]))
	}
	return out
}

func filteredSizeIndexes(list string) []string {
	var out []string
	scanner := bufio.NewScanner(strings.NewReader(list))
	for scanner.Scan() {
		elmts := strings.Fields(scanner.Text())
		if len(elmts) < 8 {
			continue
		}
		out = append(out, fmt.Sprintf("%10s %s", elmts[7], elmts[2]))
	}
	return out
}

func colorizeStatus(status string) string {
	var color xterm256.Color
	switch status {
	case "red":
		color = xterm256.Red
	case "green":
		color = xterm256.Green
	case "yellow":
		color = xterm256.Yellow
	default:
		return status
	}
	return xterm256.Sprint(color, status)
}

// command-line commands from now on
func cmdCluster(c *cli.Context, subCmd string) string {
	route := "_cluster/"
	url := c.GlobalString("baseurl")

	var arg string
	switch subCmd {
	case "health":
		arg = "health"
	case "state":
		arg = "state/" + strings.Join(c.Args(), ",")
	case "stats":
		arg = "stats/"
	default:
		arg = ""
	}
	return url + route + arg
}

func cmdIndex(c *cli.Context, subCmd string) string {
	var route string
	url := c.GlobalString("baseurl")
	switch subCmd {
	case "list":
		route = "_cat/indices?v"
	default:
		route = ""
	}
	return url + route
}

func cmdNode(c *cli.Context, subCmd string) string {
	var route string
	url := c.GlobalString("baseurl")
	switch subCmd {
	case "list":
		route = "_nodes/_all/host,ip"
	case "stats":
		route = "_nodes/_all/stats/" + strings.Join(c.Args(), ",")
	default:
		route = ""
	}
	return url + route
}

func cmdQuery(c *cli.Context) string {
	route := c.Args().First()
	url := c.GlobalString("baseurl")
	return url + route
}

func cmdStats(c *cli.Context, subCmd string) string {
	var route string
	url := c.GlobalString("baseurl")
	switch subCmd {
	case "size":
		route = "_stats/index,store"
	default:
		route = ""
	}
	return url + route
}

func httpGet(route string, trace bool) (*http.Response, error) {
	if trace {
		fmt.Fprintf(os.Stderr, "GET: %s", route)
	}
	r, err := http.Get(route)

	return r, err
}

func isTraceEnabled(c *cli.Context) bool {
	return c.GlobalBool("trace")
}
<|endoftext|>


<commit_before>package figtree

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"unicode"

	"github.com/fatih/camelcase"
	"github.com/pkg/errors"

	yaml "gopkg.in/coryb/yaml.v2"
	logging "gopkg.in/op/go-logging.v1"
)

var log = logging.MustGetLogger("figtree")

type FigTree struct {
	Defaults  interface{}
	EnvPrefix string
	stop      bool
}

func NewFigTree() *FigTree {
	return &FigTree{
		EnvPrefix: "FIGTREE",
	}
}

func LoadAllConfigs(configFile string, options interface{}) error {
	return NewFigTree().LoadAllConfigs(configFile, options)
}

func LoadConfig(configFile string, options interface{}) error {
	return NewFigTree().LoadConfig(configFile, options)
}

func (f *FigTree) LoadAllConfigs(configFile string, options interface{}) error {
	// reset from any previous config parsing runs
	f.stop = false
	// assert options is a pointer

	paths := FindParentPaths(configFile)
	paths = append([]string{fmt.Sprintf("/etc/%s", configFile)}, paths...)

	// iterate paths in reverse
	for i := len(paths) - 1; i >= 0; i-- {
		file := paths[i]
		err := f.LoadConfig(file, options)
		if err != nil {
			return err
		}
		if f.stop {
			break
		}
	}

	// apply defaults at the end to set any undefined fields
	if f.Defaults != nil {
		m := &merger{sourceFile: "default"}
		m.mergeStructs(
			reflect.ValueOf(options),
			reflect.ValueOf(f.Defaults),
		)
		f.populateEnv(options)
	}
	return nil
}

func (f *FigTree) LoadConfig(file string, options interface{}) (err error) {
	f.populateEnv(options)
	basePath, err := os.Getwd()
	if err != nil {
		return err
	}

	rel, err := filepath.Rel(basePath, file)
	if err != nil {
		rel = file
	}
	m := &merger{sourceFile: rel}
	type tmpOpts struct {
		Config ConfigOptions
	}

	if stat, err := os.Stat(file); err == nil {
		tmp := reflect.New(reflect.ValueOf(options).Elem().Type()).Interface()
		if stat.Mode()&0111 == 0 {
			log.Debugf("Loading config %s", file)
			// first parse out any config processing option
			if data, err := ioutil.ReadFile(file); err == nil {
				err := yaml.Unmarshal(data, m)
				if err != nil {
					return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
				}

				err = yaml.Unmarshal(data, tmp)
				if err != nil {
					return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
				}
				// if reflect.ValueOf(tmp).Kind() == reflect.Map {
				// 	tmp, _ = util.YamlFixup(tmp)
				// }
			}
		} else {
			log.Debugf("Found Executable Config file: %s", file)
			// it is executable, so run it and try to parse the output
			cmd := exec.Command(file)
			stdout := bytes.NewBufferString("")
			cmd.Stdout = stdout
			cmd.Stderr = bytes.NewBufferString("")
			if err := cmd.Run(); err != nil {
				return errors.Wrap(err, fmt.Sprintf("%s is exectuable, but it failed to execute:\n%s", file, cmd.Stderr))
			}
			// first parse out any config processing option
			err := yaml.Unmarshal(stdout.Bytes(), m)
			if err != nil {
				return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
			}
			err = yaml.Unmarshal(stdout.Bytes(), tmp)
			if err != nil {
				return errors.Wrap(err, fmt.Sprintf("Failed to parse STDOUT from executable config file %s", file))
			}
		}
		m.setSource(reflect.ValueOf(tmp))
		m.mergeStructs(
			reflect.ValueOf(options),
			reflect.ValueOf(tmp),
		)
		if m.Config.Stop {
			f.stop = true
			return nil
		}
		f.populateEnv(options)
	}
	return nil
}

type ConfigOptions struct {
	Overwrite []string `json:"overwrite,omitempty" yaml:"overwrite,omitempty"`
	Stop      bool     `json:"stop,omitempty" yaml:"stop,omitempty"`
	// Merge     bool     `json:"merge,omitempty" yaml:"merge,omitempty"`
}

type merger struct {
	sourceFile string
	Config     ConfigOptions `json:"config,omitempty" yaml:"config,omitempty"`
}

func yamlFieldName(sf reflect.StructField) string {
	if tag, ok := sf.Tag.Lookup("yaml"); ok {
		// with yaml:"foobar,omitempty"
		// we just want to the "foobar" part
		parts := strings.Split(tag, ",")
		return parts[0]
	}
	return sf.Name
}

func (m *merger) mustOverwrite(name string) bool {
	for _, prop := range m.Config.Overwrite {
		if name == prop {
			return true
		}
	}
	return false
}

func isEmpty(v reflect.Value) bool {
	return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}

func isSame(v1, v2 reflect.Value) bool {
	return reflect.DeepEqual(v1.Interface(), v2.Interface())
}

// recursively set the Source attribute of the Options
func (m *merger) setSource(v reflect.Value) {
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	switch v.Kind() {
	case reflect.Map:
		for _, key := range v.MapKeys() {
			keyval := v.MapIndex(key)
			if keyval.Kind() == reflect.Struct && keyval.FieldByName("Source").IsValid() {
				// map values are immutable, so we need to copy the value
				// update the value, then re-insert the value to the map
				newval := reflect.New(keyval.Type())
				newval.Elem().Set(keyval)
				m.setSource(newval)
				v.SetMapIndex(key, newval.Elem())
			}
		}
	case reflect.Struct:
		if v.CanAddr() {
			if option, ok := v.Addr().Interface().(Option); ok {
				if option.IsDefined() {
					option.SetSource(m.sourceFile)
				}
				return
			}
		}
		for i := 0; i < v.NumField(); i++ {
			m.setSource(v.Field(i))
		}
	case reflect.Array:
		fallthrough
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			m.setSource(v.Index(i))
		}
	}
}

func (m *merger) mergeStructs(ov, nv reflect.Value) {
	if ov.Kind() == reflect.Ptr {
		ov = ov.Elem()
	}
	if nv.Kind() == reflect.Ptr {
		nv = nv.Elem()
	}
	if ov.Kind() == reflect.Map && nv.Kind() == reflect.Map {
		m.mergeMaps(ov, nv)
		return
	}
	if !ov.IsValid() || !nv.IsValid() {
		return
	}
	for i := 0; i < nv.NumField(); i++ {
		fieldName := yamlFieldName(ov.Type().Field(i))

		if (isEmpty(ov.Field(i)) || m.mustOverwrite(fieldName)) && !isSame(ov.Field(i), nv.Field(i)) {
			log.Debugf("Setting %s to %#v", nv.Type().Field(i).Name, nv.Field(i).Interface())
			ov.Field(i).Set(nv.Field(i))
		} else {
			switch ov.Field(i).Kind() {
			case reflect.Map:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					m.mergeMaps(ov.Field(i), nv.Field(i))
				}
			case reflect.Slice:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					if ov.Field(i).CanSet() {
						if ov.Field(i).Len() == 0 {
							ov.Field(i).Set(nv.Field(i))
						} else {
							log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
							ov.Field(i).Set(m.mergeArrays(ov.Field(i), nv.Field(i)))
						}
					}

				}
			case reflect.Array:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					ov.Field(i).Set(m.mergeArrays(ov.Field(i), nv.Field(i)))
				}
			case reflect.Struct:
				// only merge structs if they are not an Option type:
				if _, ok := ov.Field(i).Addr().Interface().(Option); !ok {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					m.mergeStructs(ov.Field(i), nv.Field(i))
				}
			}
		}
	}
}

func (m *merger) mergeMaps(ov, nv reflect.Value) {
	for _, key := range nv.MapKeys() {
		if !ov.MapIndex(key).IsValid() {
			log.Debugf("Setting %v to %#v", key.Interface(), nv.MapIndex(key).Interface())
			ov.SetMapIndex(key, nv.MapIndex(key))
		} else {
			ovi := reflect.ValueOf(ov.MapIndex(key).Interface())
			nvi := reflect.ValueOf(nv.MapIndex(key).Interface())
			switch ovi.Kind() {
			case reflect.Map:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				m.mergeMaps(ovi, nvi)
			case reflect.Slice:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				ov.SetMapIndex(key, m.mergeArrays(ovi, nvi))
			case reflect.Array:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				ov.SetMapIndex(key, m.mergeArrays(ovi, nvi))
			}
		}
	}
}

func (m *merger) mergeArrays(ov, nv reflect.Value) reflect.Value {
Outer:
	for ni := 0; ni < nv.Len(); ni++ {
		niv := nv.Index(ni)
		for oi := 0; oi < ov.Len(); oi++ {
			oiv := ov.Index(oi)
			if reflect.DeepEqual(niv.Interface(), oiv.Interface()) {
				continue Outer
			}
		}
		log.Debugf("Appending %v to %v", niv.Interface(), ov)
		ov = reflect.Append(ov, niv)
	}
	return ov
}

func (f *FigTree) populateEnv(data interface{}) {
	options := reflect.ValueOf(data)
	if options.Kind() == reflect.Ptr {
		options = reflect.ValueOf(options.Elem().Interface())
	}
	if options.Kind() == reflect.Struct {
		for i := 0; i < options.NumField(); i++ {
			name := strings.Join(camelcase.Split(options.Type().Field(i).Name), "_")
			envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))

			envName = strings.Map(func(r rune) rune {
				if unicode.IsDigit(r) || unicode.IsLetter(r) {
					return r
				}
				return '_'
			}, envName)
			var val string
			switch t := options.Field(i).Interface().(type) {
			case string:
				val = t
			case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:
				val = fmt.Sprintf("%v", t)
			default:
				switch options.Field(i).Kind() {
				case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
					if options.Field(i).IsNil() {
						continue
					}
				}
				if t == nil {
					continue
				}
				type definable interface {
					IsDefined() bool
				}
				if def, ok := t.(definable); ok {
					// skip fields that are not defined
					if !def.IsDefined() {
						continue
					}
				}
				type gettable interface {
					GetValue() interface{}
				}
				if get, ok := t.(gettable); ok {
					val = fmt.Sprintf("%v", get.GetValue())
				} else {
					if b, err := json.Marshal(t); err == nil {
						val = strings.TrimSpace(string(b))
						if val == "null" {
							val = ""
						}
					}
				}
			}
			os.Setenv(envName, val)
		}
	}
}
<commit_msg>fix for "panic: reflect.Value.Interface: cannot return value obtained from unexported field or method"<commit_after>package figtree

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"unicode"

	"github.com/fatih/camelcase"
	"github.com/pkg/errors"

	yaml "gopkg.in/coryb/yaml.v2"
	logging "gopkg.in/op/go-logging.v1"
)

var log = logging.MustGetLogger("figtree")

type FigTree struct {
	Defaults  interface{}
	EnvPrefix string
	stop      bool
}

func NewFigTree() *FigTree {
	return &FigTree{
		EnvPrefix: "FIGTREE",
	}
}

func LoadAllConfigs(configFile string, options interface{}) error {
	return NewFigTree().LoadAllConfigs(configFile, options)
}

func LoadConfig(configFile string, options interface{}) error {
	return NewFigTree().LoadConfig(configFile, options)
}

func (f *FigTree) LoadAllConfigs(configFile string, options interface{}) error {
	// reset from any previous config parsing runs
	f.stop = false
	// assert options is a pointer

	paths := FindParentPaths(configFile)
	paths = append([]string{fmt.Sprintf("/etc/%s", configFile)}, paths...)

	// iterate paths in reverse
	for i := len(paths) - 1; i >= 0; i-- {
		file := paths[i]
		err := f.LoadConfig(file, options)
		if err != nil {
			return err
		}
		if f.stop {
			break
		}
	}

	// apply defaults at the end to set any undefined fields
	if f.Defaults != nil {
		m := &merger{sourceFile: "default"}
		m.mergeStructs(
			reflect.ValueOf(options),
			reflect.ValueOf(f.Defaults),
		)
		f.populateEnv(options)
	}
	return nil
}

func (f *FigTree) LoadConfig(file string, options interface{}) (err error) {
	f.populateEnv(options)
	basePath, err := os.Getwd()
	if err != nil {
		return err
	}

	rel, err := filepath.Rel(basePath, file)
	if err != nil {
		rel = file
	}
	m := &merger{sourceFile: rel}
	type tmpOpts struct {
		Config ConfigOptions
	}

	if stat, err := os.Stat(file); err == nil {
		tmp := reflect.New(reflect.ValueOf(options).Elem().Type()).Interface()
		if stat.Mode()&0111 == 0 {
			log.Debugf("Loading config %s", file)
			// first parse out any config processing option
			if data, err := ioutil.ReadFile(file); err == nil {
				err := yaml.Unmarshal(data, m)
				if err != nil {
					return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
				}

				err = yaml.Unmarshal(data, tmp)
				if err != nil {
					return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
				}
				// if reflect.ValueOf(tmp).Kind() == reflect.Map {
				// 	tmp, _ = util.YamlFixup(tmp)
				// }
			}
		} else {
			log.Debugf("Found Executable Config file: %s", file)
			// it is executable, so run it and try to parse the output
			cmd := exec.Command(file)
			stdout := bytes.NewBufferString("")
			cmd.Stdout = stdout
			cmd.Stderr = bytes.NewBufferString("")
			if err := cmd.Run(); err != nil {
				return errors.Wrap(err, fmt.Sprintf("%s is exectuable, but it failed to execute:\n%s", file, cmd.Stderr))
			}
			// first parse out any config processing option
			err := yaml.Unmarshal(stdout.Bytes(), m)
			if err != nil {
				return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
			}
			err = yaml.Unmarshal(stdout.Bytes(), tmp)
			if err != nil {
				return errors.Wrap(err, fmt.Sprintf("Failed to parse STDOUT from executable config file %s", file))
			}
		}
		m.setSource(reflect.ValueOf(tmp))
		m.mergeStructs(
			reflect.ValueOf(options),
			reflect.ValueOf(tmp),
		)
		if m.Config.Stop {
			f.stop = true
			return nil
		}
		f.populateEnv(options)
	}
	return nil
}

type ConfigOptions struct {
	Overwrite []string `json:"overwrite,omitempty" yaml:"overwrite,omitempty"`
	Stop      bool     `json:"stop,omitempty" yaml:"stop,omitempty"`
	// Merge     bool     `json:"merge,omitempty" yaml:"merge,omitempty"`
}

type merger struct {
	sourceFile string
	Config     ConfigOptions `json:"config,omitempty" yaml:"config,omitempty"`
}

func yamlFieldName(sf reflect.StructField) string {
	if tag, ok := sf.Tag.Lookup("yaml"); ok {
		// with yaml:"foobar,omitempty"
		// we just want to the "foobar" part
		parts := strings.Split(tag, ",")
		return parts[0]
	}
	return sf.Name
}

func (m *merger) mustOverwrite(name string) bool {
	for _, prop := range m.Config.Overwrite {
		if name == prop {
			return true
		}
	}
	return false
}

func isEmpty(v reflect.Value) bool {
	return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}

func isSame(v1, v2 reflect.Value) bool {
	return reflect.DeepEqual(v1.Interface(), v2.Interface())
}

// recursively set the Source attribute of the Options
func (m *merger) setSource(v reflect.Value) {
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	switch v.Kind() {
	case reflect.Map:
		for _, key := range v.MapKeys() {
			keyval := v.MapIndex(key)
			if keyval.Kind() == reflect.Struct && keyval.FieldByName("Source").IsValid() {
				// map values are immutable, so we need to copy the value
				// update the value, then re-insert the value to the map
				newval := reflect.New(keyval.Type())
				newval.Elem().Set(keyval)
				m.setSource(newval)
				v.SetMapIndex(key, newval.Elem())
			}
		}
	case reflect.Struct:
		if v.CanAddr() {
			if option, ok := v.Addr().Interface().(Option); ok {
				if option.IsDefined() {
					option.SetSource(m.sourceFile)
				}
				return
			}
		}
		for i := 0; i < v.NumField(); i++ {
			m.setSource(v.Field(i))
		}
	case reflect.Array:
		fallthrough
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			m.setSource(v.Index(i))
		}
	}
}

func (m *merger) mergeStructs(ov, nv reflect.Value) {
	if ov.Kind() == reflect.Ptr {
		ov = ov.Elem()
	}
	if nv.Kind() == reflect.Ptr {
		nv = nv.Elem()
	}
	if ov.Kind() == reflect.Map && nv.Kind() == reflect.Map {
		m.mergeMaps(ov, nv)
		return
	}
	if !ov.IsValid() || !nv.IsValid() {
		return
	}
	for i := 0; i < nv.NumField(); i++ {
		fieldName := yamlFieldName(ov.Type().Field(i))

		if (isEmpty(ov.Field(i)) || m.mustOverwrite(fieldName)) && !isSame(ov.Field(i), nv.Field(i)) {
			log.Debugf("Setting %s to %#v", nv.Type().Field(i).Name, nv.Field(i).Interface())
			ov.Field(i).Set(nv.Field(i))
		} else {
			switch ov.Field(i).Kind() {
			case reflect.Map:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					m.mergeMaps(ov.Field(i), nv.Field(i))
				}
			case reflect.Slice:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					if ov.Field(i).CanSet() {
						if ov.Field(i).Len() == 0 {
							ov.Field(i).Set(nv.Field(i))
						} else {
							log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
							ov.Field(i).Set(m.mergeArrays(ov.Field(i), nv.Field(i)))
						}
					}

				}
			case reflect.Array:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					ov.Field(i).Set(m.mergeArrays(ov.Field(i), nv.Field(i)))
				}
			case reflect.Struct:
				// only merge structs if they are not an Option type:
				if _, ok := ov.Field(i).Addr().Interface().(Option); !ok {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					m.mergeStructs(ov.Field(i), nv.Field(i))
				}
			}
		}
	}
}

func (m *merger) mergeMaps(ov, nv reflect.Value) {
	for _, key := range nv.MapKeys() {
		if !ov.MapIndex(key).IsValid() {
			log.Debugf("Setting %v to %#v", key.Interface(), nv.MapIndex(key).Interface())
			ov.SetMapIndex(key, nv.MapIndex(key))
		} else {
			ovi := reflect.ValueOf(ov.MapIndex(key).Interface())
			nvi := reflect.ValueOf(nv.MapIndex(key).Interface())
			switch ovi.Kind() {
			case reflect.Map:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				m.mergeMaps(ovi, nvi)
			case reflect.Slice:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				ov.SetMapIndex(key, m.mergeArrays(ovi, nvi))
			case reflect.Array:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				ov.SetMapIndex(key, m.mergeArrays(ovi, nvi))
			}
		}
	}
}

func (m *merger) mergeArrays(ov, nv reflect.Value) reflect.Value {
Outer:
	for ni := 0; ni < nv.Len(); ni++ {
		niv := nv.Index(ni)
		for oi := 0; oi < ov.Len(); oi++ {
			oiv := ov.Index(oi)
			if reflect.DeepEqual(niv.Interface(), oiv.Interface()) {
				continue Outer
			}
		}
		log.Debugf("Appending %v to %v", niv.Interface(), ov)
		ov = reflect.Append(ov, niv)
	}
	return ov
}

func (f *FigTree) populateEnv(data interface{}) {
	options := reflect.ValueOf(data)
	if options.Kind() == reflect.Ptr {
		options = reflect.ValueOf(options.Elem().Interface())
	}
	if options.Kind() == reflect.Struct {
		for i := 0; i < options.NumField(); i++ {
			name := strings.Join(camelcase.Split(options.Type().Field(i).Name), "_")
			envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))

			envName = strings.Map(func(r rune) rune {
				if unicode.IsDigit(r) || unicode.IsLetter(r) {
					return r
				}
				return '_'
			}, envName)
			var val string
			structField := options.Type().Field(i)
			// PkgPath is empty for upper case (exported) field names.
			if structField.PkgPath != "" {
				// unexported field, skipping
				continue
			}
			switch t := options.Field(i).Interface().(type) {
			case string:
				val = t
			case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:
				val = fmt.Sprintf("%v", t)
			default:
				switch options.Field(i).Kind() {
				case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
					if options.Field(i).IsNil() {
						continue
					}
				}
				if t == nil {
					continue
				}
				type definable interface {
					IsDefined() bool
				}
				if def, ok := t.(definable); ok {
					// skip fields that are not defined
					if !def.IsDefined() {
						continue
					}
				}
				type gettable interface {
					GetValue() interface{}
				}
				if get, ok := t.(gettable); ok {
					val = fmt.Sprintf("%v", get.GetValue())
				} else {
					if b, err := json.Marshal(t); err == nil {
						val = strings.TrimSpace(string(b))
						if val == "null" {
							val = ""
						}
					}
				}
			}
			os.Setenv(envName, val)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/alexjohnj/flasher/tbutils"
	"github.com/codegangsta/cli"
	"github.com/nsf/termbox-go"
	"log"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "flasher"
	app.Version = "0.2.1"
	app.Author = "Alex Jackson"
	app.Email = "alex@alexj.org"

	app.Commands = []cli.Command{
		{
			Name:      "flash",
			ShortName: "f",
			Usage:     "flasher flash [flashcard-file.json]",
			Action:    cliFlash,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "no-shuffle, n",
					Usage: "Presents flashcards in the order they are written in the source JSON file.",
				},
			},
		},
		{
			Name:      "info",
			ShortName: "i",
			Usage:     "flasher info [flashcard-file.json]",
			Action:    cliInfo,
		},
	}
	app.Run(os.Args)
}

func cliFlash(c *cli.Context) {
	// Load flashcards

	if len(c.Args()) != 1 {
		log.Printf("Incorrect usage\n")
		cli.ShowCommandHelp(c, "flash")
		os.Exit(1)
	}

	flashcardStack := new(cardStack)
	err := flashcardStack.loadFlashcardStack(c.Args()[0])

	if err != nil {
		log.Fatal(err)
	}

	if !c.Bool("no-shuffle") {
		flashcardStack.shuffle()
	}

	// Init termbox
	err = termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()
	drawAll(flashcardStack)

	//Main Run loop
mainloop:
	for {
		switch event := termbox.PollEvent(); event.Type {
		case termbox.EventKey:
			switch event.Key {
			case termbox.KeyEsc, termbox.KeyCtrlC:
				break mainloop
			case termbox.KeyEnter, termbox.KeyArrowRight:
				flashcardStack.advanceStack()
				drawAll(flashcardStack)
			case termbox.KeyBackspace2, termbox.KeyArrowLeft:
				flashcardStack.revertStack()
				drawAll(flashcardStack)
			}
		case termbox.EventResize:
			drawAll(flashcardStack)
		}
		drawAll(flashcardStack)
	}
}

func cliInfo(c *cli.Context) {
	if len(c.Args()) != 1 {
		log.Printf("Incorrect usage\n")
		cli.ShowCommandHelp(c, "info")
		os.Exit(1)
	}

	flashcardStack := new(cardStack)
	err := flashcardStack.loadFlashcardStack(c.Args()[0])

	if err != nil {
		log.Fatalf("%s is an invalid file: %s", c.Args()[0], err.Error())
	}

	fmt.Printf("Deck Name: %s\nAuthor: %s\nNumber of Cards: %d\n", flashcardStack.Title, flashcardStack.Author, len(flashcardStack.Flashcards))
}

func drawAll(stack *cardStack) {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	w, h := termbox.Size()

	// Draw termbox border
	termbox.SetCell(0, 0, '+', termbox.ColorDefault, termbox.ColorDefault)
	termbox.SetCell(w-1, 0, '+', termbox.ColorDefault, termbox.ColorDefault)
	termbox.SetCell(0, h-1, '+', termbox.ColorDefault, termbox.ColorDefault)
	termbox.SetCell(w-1, h-1, '+', termbox.ColorDefault, termbox.ColorDefault)

	for x := 1; x < w-1; x++ {
		termbox.SetCell(x, 0, '-', termbox.ColorDefault, termbox.ColorDefault)
		termbox.SetCell(x, h-1, '-', termbox.ColorDefault, termbox.ColorDefault)
	}

	// Draw the Stack's title
	titleXCoord := tbutils.CalculateXCenterCoord(stack.Title)
	tbutils.DrawText(titleXCoord, 1, stack.Title)

	// Draw the current card
	currentQuestion := stack.getCurrentFlashcard()
	currentQuestion.drawQuestion()
	if stack.ShowAnswer {
		currentQuestion.drawAnswer()
		// Draw the Q/A divider
		for x := 0; x < w; x++ {
			termbox.SetCell(x, (3 * h / 8), '-', termbox.ColorBlue, termbox.ColorDefault)
		}
	}

	// Draw the current index
	indexStr := fmt.Sprintf("(%d/%d)", stack.StackIndex+1, len(stack.Flashcards))
	indexXCoord, indexYCoord := tbutils.CalculateXCenterCoord(indexStr), h-1
	tbutils.DrawText(indexXCoord, indexYCoord, indexStr)

	// Write out the back buffer
	termbox.Flush()
}
<commit_msg>Updated dev version number<commit_after>package main

import (
	"fmt"
	"github.com/alexjohnj/flasher/tbutils"
	"github.com/codegangsta/cli"
	"github.com/nsf/termbox-go"
	"log"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "flasher"
	app.Version = "0.3.0-DEV"
	app.Author = "Alex Jackson"
	app.Email = "alex@alexj.org"

	app.Commands = []cli.Command{
		{
			Name:      "flash",
			ShortName: "f",
			Usage:     "flasher flash [flashcard-file.json]",
			Action:    cliFlash,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "no-shuffle, n",
					Usage: "Presents flashcards in the order they are written in the source JSON file.",
				},
			},
		},
		{
			Name:      "info",
			ShortName: "i",
			Usage:     "flasher info [flashcard-file.json]",
			Action:    cliInfo,
		},
	}
	app.Run(os.Args)
}

func cliFlash(c *cli.Context) {
	// Load flashcards

	if len(c.Args()) != 1 {
		log.Printf("Incorrect usage\n")
		cli.ShowCommandHelp(c, "flash")
		os.Exit(1)
	}

	flashcardStack := new(cardStack)
	err := flashcardStack.loadFlashcardStack(c.Args()[0])

	if err != nil {
		log.Fatal(err)
	}

	if !c.Bool("no-shuffle") {
		flashcardStack.shuffle()
	}

	// Init termbox
	err = termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()
	drawAll(flashcardStack)

	//Main Run loop
mainloop:
	for {
		switch event := termbox.PollEvent(); event.Type {
		case termbox.EventKey:
			switch event.Key {
			case termbox.KeyEsc, termbox.KeyCtrlC:
				break mainloop
			case termbox.KeyEnter, termbox.KeyArrowRight:
				flashcardStack.advanceStack()
				drawAll(flashcardStack)
			case termbox.KeyBackspace2, termbox.KeyArrowLeft:
				flashcardStack.revertStack()
				drawAll(flashcardStack)
			}
		case termbox.EventResize:
			drawAll(flashcardStack)
		}
		drawAll(flashcardStack)
	}
}

func cliInfo(c *cli.Context) {
	if len(c.Args()) != 1 {
		log.Printf("Incorrect usage\n")
		cli.ShowCommandHelp(c, "info")
		os.Exit(1)
	}

	flashcardStack := new(cardStack)
	err := flashcardStack.loadFlashcardStack(c.Args()[0])

	if err != nil {
		log.Fatalf("%s is an invalid file: %s", c.Args()[0], err.Error())
	}

	fmt.Printf("Deck Name: %s\nAuthor: %s\nNumber of Cards: %d\n", flashcardStack.Title, flashcardStack.Author, len(flashcardStack.Flashcards))
}

func drawAll(stack *cardStack) {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	w, h := termbox.Size()

	// Draw termbox border
	termbox.SetCell(0, 0, '+', termbox.ColorDefault, termbox.ColorDefault)
	termbox.SetCell(w-1, 0, '+', termbox.ColorDefault, termbox.ColorDefault)
	termbox.SetCell(0, h-1, '+', termbox.ColorDefault, termbox.ColorDefault)
	termbox.SetCell(w-1, h-1, '+', termbox.ColorDefault, termbox.ColorDefault)

	for x := 1; x < w-1; x++ {
		termbox.SetCell(x, 0, '-', termbox.ColorDefault, termbox.ColorDefault)
		termbox.SetCell(x, h-1, '-', termbox.ColorDefault, termbox.ColorDefault)
	}

	// Draw the Stack's title
	titleXCoord := tbutils.CalculateXCenterCoord(stack.Title)
	tbutils.DrawText(titleXCoord, 1, stack.Title)

	// Draw the current card
	currentQuestion := stack.getCurrentFlashcard()
	currentQuestion.drawQuestion()
	if stack.ShowAnswer {
		currentQuestion.drawAnswer()
		// Draw the Q/A divider
		for x := 0; x < w; x++ {
			termbox.SetCell(x, (3 * h / 8), '-', termbox.ColorBlue, termbox.ColorDefault)
		}
	}

	// Draw the current index
	indexStr := fmt.Sprintf("(%d/%d)", stack.StackIndex+1, len(stack.Flashcards))
	indexXCoord, indexYCoord := tbutils.CalculateXCenterCoord(indexStr), h-1
	tbutils.DrawText(indexXCoord, indexYCoord, indexStr)

	// Write out the back buffer
	termbox.Flush()
}
<|endoftext|>


<commit_before>package fscache

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
)

type Cache struct {
	mu    sync.Mutex
	dir   string
	files map[string]*cachedFile
}

// New creates a new Cache based on directory dir.
// Dir is created if it does not exist, and the files
// in it are loaded into the cache using their filename as their key.
func New(dir string) (*Cache, error) {
	err := os.MkdirAll(dir, 0666)
	if err != nil {
		return nil, err
	}
	c := &Cache{
		dir:   dir,
		files: make(map[string]*cachedFile),
	}
	return c, c.load()
}

func (c *Cache) load() error {
	c.mu.Lock()
	defer c.mu.Unlock()

	files, err := ioutil.ReadDir(c.dir)
	if err != nil {
		return err
	}
	for _, f := range files {
		c.files[f.Name()] = oldFile(filepath.Join(c.dir, f.Name()))
	}
	return nil
}

// Get manages access to the streams in the cache.
// If the key does not exist, ok = false, r will be nil and you can start
// writing to the stream via w which must be closed once you finish streaming to it.
// If ok = true, then the stream has started. w will be nil, and r will
// allow you to read from the stream. Get is safe for concurrent calls, and
// multiple concurrent readers are allowed. The stream readers will only block when waiting
// for more data to be written to the stream, or the stream to be closed (signified by io.EOF).
func (c *Cache) Get(key string) (r io.ReadCloser, w io.WriteCloser, ok bool, err error) {
	c.mu.Lock()
	defer c.mu.Unlock()

	f, ok := c.files[key]
	if !ok {
		f, err = newFile(filepath.Join(c.dir, key))
		w = f
		c.files[key] = f
	} else {
		r, err = f.next()
	}

	return r, w, ok, err
}

// Clean will empty the cache and delete the cache folder.
// Clean is not safe to call while streams are being read/written.
func (c *Cache) Clean() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.files = make(map[string]*cachedFile)
	return os.RemoveAll(c.dir)
}

type cachedFile struct {
	name string
	grp  sync.WaitGroup
	w    *os.File
	b    *broadcaster
}

func newFile(key string) (*cachedFile, error) {
	f, err := os.Create(key)
	return &cachedFile{
		name: key,
		w:    f,
		b:    newBroadcaster(),
	}, err
}

func oldFile(key string) *cachedFile {
	b := newBroadcaster()
	b.Close()
	return &cachedFile{
		name: key,
		b:    b,
	}
}

func (f *cachedFile) next() (r io.ReadCloser, err error) {
	r, err = os.Open(f.name)
	if err == nil {
		f.grp.Add(1)
	}
	return &cacheReader{
		grp: &f.grp,
		r:   r,
		b:   f.b,
	}, err
}

func (f *cachedFile) Write(p []byte) (int, error) {
	defer f.b.Broadcast()
	f.b.Lock()
	defer f.b.Unlock()
	return f.w.Write(p)
}

func (f *cachedFile) Close() error {
	defer f.b.Close()
	return f.w.Close()
}

type cacheReader struct {
	r   io.ReadCloser
	grp *sync.WaitGroup
	b   *broadcaster
}

func (r *cacheReader) Read(p []byte) (n int, err error) {
	r.b.RLock()
	defer r.b.RUnlock()

	for {

		n, err = r.r.Read(p)

		if r.b.IsOpen() { // file is still being written to

			if n != 0 && err == nil { // successful read
				return n, nil
			} else if err == io.EOF { // no data read, wait for some
				r.b.RUnlock()
				r.b.Wait()
				r.b.RLock()
			} else if err != nil { // non-nil, non-eof error
				return n, err
			}

		} else { // file is closed, just return
			return n, err
		}

	}

	return n, err
}

func (r *cacheReader) Close() error {
	defer r.grp.Done()
	return r.r.Close()
}
<commit_msg>added Remove(), its still stop-the-world though...<commit_after>package fscache

import (
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
)

type Cache struct {
	mu    sync.Mutex
	dir   string
	files map[string]*cachedFile
}

// New creates a new Cache based on directory dir.
// Dir is created if it does not exist, and the files
// in it are loaded into the cache using their filename as their key.
func New(dir string) (*Cache, error) {
	err := os.MkdirAll(dir, 0666)
	if err != nil {
		return nil, err
	}
	c := &Cache{
		dir:   dir,
		files: make(map[string]*cachedFile),
	}
	return c, c.load()
}

func (c *Cache) load() error {
	c.mu.Lock()
	defer c.mu.Unlock()

	files, err := ioutil.ReadDir(c.dir)
	if err != nil {
		return err
	}
	for _, f := range files {
		c.files[f.Name()] = oldFile(filepath.Join(c.dir, f.Name()))
	}
	return nil
}

// Get manages access to the streams in the cache.
// If the key does not exist, ok = false, r will be nil and you can start
// writing to the stream via w which must be closed once you finish streaming to it.
// If ok = true, then the stream has started. w will be nil, and r will
// allow you to read from the stream. Get is safe for concurrent calls, and
// multiple concurrent readers are allowed. The stream readers will only block when waiting
// for more data to be written to the stream, or the stream to be closed (signified by io.EOF).
func (c *Cache) Get(key string) (r io.ReadCloser, w io.WriteCloser, ok bool, err error) {
	c.mu.Lock()
	defer c.mu.Unlock()

	f, ok := c.files[key]
	if !ok {
		f, err = newFile(filepath.Join(c.dir, key))
		f.grp.Add(1)
		w = f
		c.files[key] = f
	} else {
		r, err = f.next()
	}

	return r, w, ok, err
}

// Remove will delete the specified stream after waiting for all
// activity on it to stop (writer/readers closed).
// Note that Remove also blocks calls to Get to prevent
// the key from being requested while awaiting deletion.
func (c *Cache) Remove(key string) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	f, ok := c.files[key]
	delete(c.files, key)

	if ok {
		f.grp.Wait()
		return os.Remove(f.name)
	}
	return nil
}

// Clean will empty the cache and delete the cache folder.
// Clean is not safe to call while streams are being read/written.
func (c *Cache) Clean() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.files = make(map[string]*cachedFile)
	return os.RemoveAll(c.dir)
}

type cachedFile struct {
	name string
	grp  sync.WaitGroup
	w    *os.File
	b    *broadcaster
}

func newFile(key string) (*cachedFile, error) {
	f, err := os.Create(key)
	if err != nil {
		return nil, err
	}
	return &cachedFile{
		name: f.Name(),
		w:    f,
		b:    newBroadcaster(),
	}, nil
}

func oldFile(key string) *cachedFile {
	b := newBroadcaster()
	b.Close()
	return &cachedFile{
		name: key,
		b:    b,
	}
}

func (f *cachedFile) next() (r io.ReadCloser, err error) {
	r, err = os.Open(f.name)
	if err == nil {
		f.grp.Add(1)
	}
	return &cacheReader{
		grp: &f.grp,
		r:   r,
		b:   f.b,
	}, err
}

func (f *cachedFile) Write(p []byte) (int, error) {
	defer f.b.Broadcast()
	f.b.Lock()
	defer f.b.Unlock()
	return f.w.Write(p)
}

func (f *cachedFile) Close() error {
	defer f.grp.Done()
	defer f.b.Close()
	return f.w.Close()
}

type cacheReader struct {
	r   io.ReadCloser
	grp *sync.WaitGroup
	b   *broadcaster
}

func (r *cacheReader) Read(p []byte) (n int, err error) {
	r.b.RLock()
	defer r.b.RUnlock()

	for {

		n, err = r.r.Read(p)

		if r.b.IsOpen() { // file is still being written to

			if n != 0 && err == nil { // successful read
				return n, nil
			} else if err == io.EOF { // no data read, wait for some
				r.b.RUnlock()
				r.b.Wait()
				r.b.RLock()
			} else if err != nil { // non-nil, non-eof error
				return n, err
			}

		} else { // file is closed, just return
			return n, err
		}

	}

	return n, err
}

func (r *cacheReader) Close() error {
	defer r.grp.Done()
	return r.r.Close()
}
<|endoftext|>