<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 graph_test

import (
	cryptorand "crypto/rand"
	"encoding/binary"
	"fmt"
	"log"
	"math/rand"
	"sync"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/internal/graph"
	. "github.com/jacobsa/ogletest"
)

func TestTraverseDAG(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Return a topological sort of the nodes of the DAG defined by the supplied
// edge map.
func topsort(edges map[string][]string) (nodes []string, err error) {
	// A DFS-based algorithm that detects cycles.
	// Cf. https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
	marked := make(map[string]struct{})
	tempMarked := make(map[string]struct{})
	unmarked := make(map[string]struct{})
	for n, _ := range edges {
		unmarked[n] = struct{}{}
	}

	var visit func(string) error
	visit = func(n string) (err error) {
		// Cycle?
		if _, ok := tempMarked[n]; ok {
			err = fmt.Errorf("Cycle containing %q detected", n)
			return
		}

		// Already visited?
		if _, ok := marked[n]; ok {
			return
		}

		delete(unmarked, n)
		tempMarked[n] = struct{}{}
		for _, m := range edges[n] {
			err = visit(m)
			if err != nil {
				return
			}
		}

		marked[n] = struct{}{}
		delete(tempMarked, n)
		nodes = append([]string{n}, nodes...)

		return
	}

	// Visit nodes until there are no unmarked ones left.
	for len(unmarked) > 0 {
		var someNode string
		for n, _ := range unmarked {
			someNode = n
			break
		}

		err = visit(someNode)
		if err != nil {
			return
		}
	}

	return
}

// Compute the the reachability partial order for the DAG defined by the
// supplied edges. Don't include self-reachability.
func reachabilityRelation(
	edges map[string][]string) (r map[string][]string, err error) {
	r = make(map[string][]string)

	var visit func(string)
	visit = func(n string) {
		// Have we already computed the result for n?
		if _, ok := r[n]; ok {
			return
		}

		// The set of things reachable from n is the set of things reachable from
		// its successors, plus those successors.
		set := make(map[string]struct{})
		for _, successor := range edges[n] {
			set[successor] = struct{}{}

			visit(successor)
			for _, m := range r[successor] {
				set[m] = struct{}{}
			}
		}

		for m, _ := range set {
			r[n] = append(r[n], m)
		}
	}

	for n, _ := range edges {
		visit(n)
	}

	return
}

// Return the relation composed of pairs (Y, X) for each pair (X, Y) in the
// input relation.
func invertRelation(r map[string][]string) (inverted map[string][]string) {
	inverted = make(map[string][]string)
	for k, vs := range r {
		for _, v := range vs {
			inverted[v] = append(inverted[v], k)
		}
	}

	return
}

// Create a rand.Rand seeded with a good source.
func makeRandSource() (src *rand.Rand) {
	// Read a seed from a good source.
	var seed int64
	err := binary.Read(cryptorand.Reader, binary.LittleEndian, &seed)
	if err != nil {
		log.Fatalln(err)
	}

	src = rand.New(rand.NewSource(seed))
	return
}

// Create a SuccessorFinder that consults the supplied map of edges.
func successorFinderForEdges(
	edges map[string][]string) (sf graph.SuccessorFinder) {
	sf = &successorFinder{
		F: func(ctx context.Context, n string) (nodes []string, err error) {
			nodes = edges[n]
			return
		},
	}

	return
}

// A graph.Visitor for string nodes that calls through to a canned function.
type visitor struct {
	F func(context.Context, string) error
}

func (v *visitor) Visit(
	ctx context.Context,
	untyped graph.Node) (err error) {
	err = v.F(ctx, untyped.(string))
	return
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const traverseDAGParallelism = 8

type TraverseDAGTest struct {
	ctx context.Context
}

var _ SetUpInterface = &TraverseDAGTest{}

func init() { RegisterTestSuite(&TraverseDAGTest{}) }

func (t *TraverseDAGTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
}

// Run the graph described by the given edges through TraverseDAG, inserting
// sleeps to attempt to shake out races, and make sure we can't catch it
// violating any of its promises.
func (t *TraverseDAGTest) runTest(edges map[string][]string) {
	// Sort the nodes into a valid order and stick them in a channel.
	nodes, err := topsort(edges)
	AssertEq(nil, err)

	nodeChan := make(chan graph.Node, len(nodes))
	for _, n := range nodes {
		nodeChan <- n
	}
	close(nodeChan)

	// Compute the reachability relation for the DAG, and invert it.
	reachable, err := reachabilityRelation(edges)
	AssertEq(nil, err)
	inverseReachable := invertRelation(reachable)

	// Set up a visit function that ensures that a visit hasn't happened out of
	// order, sleeps for awhile, then marks the node as visited.
	randSrc := makeRandSource()

	var mu sync.Mutex
	visited := make(map[string]struct{}) // GUARDED_BY(mu)

	visit := func(ctx context.Context, n string) (err error) {
		mu.Lock()
		defer mu.Unlock()

		// We should have already finished visiting all of the nodes from which
		// this node is reachable.
		for _, p := range inverseReachable[n] {
			_, ok := visited[p]
			if !ok {
				err = fmt.Errorf("Visited %q before finished visiting %q", n, p)
				return
			}
		}

		// Wait a random amount of time, then mark the node as visited and return.
		mu.Unlock()
		time.Sleep(time.Duration(randSrc.Int63n(int64(20 * time.Millisecond))))
		mu.Lock()

		visited[n] = struct{}{}
		return
	}

	// Call.
	err = graph.TraverseDAG(
		t.ctx,
		nodeChan,
		successorFinderForEdges(edges),
		&visitor{F: visit},
		traverseDAGParallelism)

	AssertEq(nil, err)

	// Make sure everything was visited.
	for _, n := range nodes {
		_, ok := visited[n]
		AssertTrue(ok, "n: %q", n)
	}
}

// Generate a tree with a certain depth, where the number of children for each
// node is random. The root node is "root".
func randomTree(depth int) (edges map[string][]string) {
	edges = make(map[string][]string)
	randSrc := makeRandSource()

	nextID := 0
	nextLevel := []string{"root"}

	for depthI := 0; depthI < depth; depthI++ {
		thisLevel := nextLevel
		nextLevel = nil

		for _, parent := range thisLevel {
			// Ensure that there is an entry, even if there are no children.
			edges[parent] = []string{}

			// Add children.
			numChildren := int(randSrc.Int31n(6))
			for childI := 0; childI < numChildren; childI++ {
				child := fmt.Sprintf("%v", nextID)
				nextID++

				nextLevel = append(nextLevel, child)
				edges[parent] = append(edges[parent], child)
			}
		}
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *TraverseDAGTest) EmptyGraph() {
	edges := map[string][]string{}
	t.runTest(edges)
}

func (t *TraverseDAGTest) SingleNodeConnectedComponents() {
	// Graph structure:
	//
	//     A  B  C  D
	//
	edges := map[string][]string{
		"A": {},
		"B": {},
		"C": {},
		"D": {},
	}

	t.runTest(edges)
}

func (t *TraverseDAGTest) SimpleRootedTree() {
	// Graph structure:
	//
	//        A
	//      / |
	//     B  C
	//      / | \
	//     D  E  F
	//      / |  |
	//     G  H  I
	//           | \
	//           J  K
	//
	edges := map[string][]string{
		"A": {"B", "C"},
		"B": {},
		"C": {"D", "E", "F"},
		"D": {},
		"E": {"G", "H"},
		"F": {"I"},
		"G": {},
		"H": {},
		"I": {"J", "K"},
		"J": {},
		"K": {},
	}

	t.runTest(edges)
}

func (t *TraverseDAGTest) SimpleDAG() {
	// Graph structure:
	//
	//        A
	//      /  \
	//     B    C
	//      \  /|
	//        D |
	//         \|
	//          E
	//
	edges := map[string][]string{
		"A": {"B", "C"},
		"B": {"D"},
		"C": {"D", "E"},
		"D": {"E"},
		"E": {},
	}

	t.runTest(edges)
}

func (t *TraverseDAGTest) MultipleConnectedComponents() {
	// Graph structure:
	//
	//        A       E
	//      /  \      |\
	//     B    C     F G
	//      \  /
	//        D
	//
	edges := map[string][]string{
		"A": {"B", "C"},
		"B": {"D"},
		"C": {"D"},
		"D": {},
		"E": {"F", "G"},
		"F": {},
		"G": {},
	}

	t.runTest(edges)
}

func (t *TraverseDAGTest) LargeRootedTree() {
	const depth = 6
	edges := randomTree(depth)
	t.runTest(edges)
}

func (t *TraverseDAGTest) LargeRootedTree_Inverted() {
	AssertTrue(false, "TODO")
}

func (t *TraverseDAGTest) SuccessorFinderReturnsError() {
	AssertTrue(false, "TODO")
}

func (t *TraverseDAGTest) VisitorReturnsError() {
	AssertTrue(false, "TODO")
}
<commit_msg>TraverseDAGTest.LargeRootedTree_Inverted<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 graph_test

import (
	cryptorand "crypto/rand"
	"encoding/binary"
	"fmt"
	"log"
	"math/rand"
	"sync"
	"testing"
	"time"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/internal/graph"
	. "github.com/jacobsa/ogletest"
)

func TestTraverseDAG(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// Return a topological sort of the nodes of the DAG defined by the supplied
// edge map.
func topsort(edges map[string][]string) (nodes []string, err error) {
	// A DFS-based algorithm that detects cycles.
	// Cf. https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
	marked := make(map[string]struct{})
	tempMarked := make(map[string]struct{})
	unmarked := make(map[string]struct{})
	for n, _ := range edges {
		unmarked[n] = struct{}{}
	}

	var visit func(string) error
	visit = func(n string) (err error) {
		// Cycle?
		if _, ok := tempMarked[n]; ok {
			err = fmt.Errorf("Cycle containing %q detected", n)
			return
		}

		// Already visited?
		if _, ok := marked[n]; ok {
			return
		}

		delete(unmarked, n)
		tempMarked[n] = struct{}{}
		for _, m := range edges[n] {
			err = visit(m)
			if err != nil {
				return
			}
		}

		marked[n] = struct{}{}
		delete(tempMarked, n)
		nodes = append([]string{n}, nodes...)

		return
	}

	// Visit nodes until there are no unmarked ones left.
	for len(unmarked) > 0 {
		var someNode string
		for n, _ := range unmarked {
			someNode = n
			break
		}

		err = visit(someNode)
		if err != nil {
			return
		}
	}

	return
}

// Compute the the reachability partial order for the DAG defined by the
// supplied edges. Don't include self-reachability.
func reachabilityRelation(
	edges map[string][]string) (r map[string][]string, err error) {
	r = make(map[string][]string)

	var visit func(string)
	visit = func(n string) {
		// Have we already computed the result for n?
		if _, ok := r[n]; ok {
			return
		}

		// The set of things reachable from n is the set of things reachable from
		// its successors, plus those successors.
		set := make(map[string]struct{})
		for _, successor := range edges[n] {
			set[successor] = struct{}{}

			visit(successor)
			for _, m := range r[successor] {
				set[m] = struct{}{}
			}
		}

		for m, _ := range set {
			r[n] = append(r[n], m)
		}
	}

	for n, _ := range edges {
		visit(n)
	}

	return
}

// Return the relation composed of pairs (Y, X) for each pair (X, Y) in the
// input relation.
func invertRelation(r map[string][]string) (inverted map[string][]string) {
	inverted = make(map[string][]string)
	for k, vs := range r {
		for _, v := range vs {
			inverted[v] = append(inverted[v], k)
		}
	}

	// Ensure that everything has an entry, even if empty.
	for k, _ := range r {
		if _, ok := inverted[k]; !ok {
			inverted[k] = nil
		}
	}

	return
}

// Create a rand.Rand seeded with a good source.
func makeRandSource() (src *rand.Rand) {
	// Read a seed from a good source.
	var seed int64
	err := binary.Read(cryptorand.Reader, binary.LittleEndian, &seed)
	if err != nil {
		log.Fatalln(err)
	}

	src = rand.New(rand.NewSource(seed))
	return
}

// Create a SuccessorFinder that consults the supplied map of edges.
func successorFinderForEdges(
	edges map[string][]string) (sf graph.SuccessorFinder) {
	sf = &successorFinder{
		F: func(ctx context.Context, n string) (nodes []string, err error) {
			nodes = edges[n]
			return
		},
	}

	return
}

// A graph.Visitor for string nodes that calls through to a canned function.
type visitor struct {
	F func(context.Context, string) error
}

func (v *visitor) Visit(
	ctx context.Context,
	untyped graph.Node) (err error) {
	err = v.F(ctx, untyped.(string))
	return
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

const traverseDAGParallelism = 8

type TraverseDAGTest struct {
	ctx context.Context
}

var _ SetUpInterface = &TraverseDAGTest{}

func init() { RegisterTestSuite(&TraverseDAGTest{}) }

func (t *TraverseDAGTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
}

// Run the graph described by the given edges through TraverseDAG, inserting
// sleeps to attempt to shake out races, and make sure we can't catch it
// violating any of its promises.
func (t *TraverseDAGTest) runTest(edges map[string][]string) {
	// Sort the nodes into a valid order and stick them in a channel.
	nodes, err := topsort(edges)
	AssertEq(nil, err)

	nodeChan := make(chan graph.Node, len(nodes))
	for _, n := range nodes {
		nodeChan <- n
	}
	close(nodeChan)

	// Compute the reachability relation for the DAG, and invert it.
	reachable, err := reachabilityRelation(edges)
	AssertEq(nil, err)
	inverseReachable := invertRelation(reachable)

	// Set up a visit function that ensures that a visit hasn't happened out of
	// order, sleeps for awhile, then marks the node as visited.
	randSrc := makeRandSource()

	var mu sync.Mutex
	visited := make(map[string]struct{}) // GUARDED_BY(mu)

	visit := func(ctx context.Context, n string) (err error) {
		mu.Lock()
		defer mu.Unlock()

		// We should have already finished visiting all of the nodes from which
		// this node is reachable.
		for _, p := range inverseReachable[n] {
			_, ok := visited[p]
			if !ok {
				err = fmt.Errorf("Visited %q before finished visiting %q", n, p)
				return
			}
		}

		// Wait a random amount of time, then mark the node as visited and return.
		mu.Unlock()
		time.Sleep(time.Duration(randSrc.Int63n(int64(20 * time.Millisecond))))
		mu.Lock()

		visited[n] = struct{}{}
		return
	}

	// Call.
	err = graph.TraverseDAG(
		t.ctx,
		nodeChan,
		successorFinderForEdges(edges),
		&visitor{F: visit},
		traverseDAGParallelism)

	AssertEq(nil, err)

	// Make sure everything was visited.
	for _, n := range nodes {
		_, ok := visited[n]
		AssertTrue(ok, "n: %q", n)
	}
}

// Generate a tree with a certain depth, where the number of children for each
// node is random. The root node is "root".
func randomTree(depth int) (edges map[string][]string) {
	edges = make(map[string][]string)
	randSrc := makeRandSource()

	nextID := 0
	nextLevel := []string{"root"}

	for depthI := 0; depthI < depth; depthI++ {
		thisLevel := nextLevel
		nextLevel = nil

		for _, parent := range thisLevel {
			// Ensure that there is an entry, even if there are no children.
			edges[parent] = []string{}

			// Add children.
			numChildren := int(randSrc.Int31n(6))
			for childI := 0; childI < numChildren; childI++ {
				child := fmt.Sprintf("%v", nextID)
				nextID++

				nextLevel = append(nextLevel, child)
				edges[parent] = append(edges[parent], child)
			}
		}
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *TraverseDAGTest) EmptyGraph() {
	edges := map[string][]string{}
	t.runTest(edges)
}

func (t *TraverseDAGTest) SingleNodeConnectedComponents() {
	// Graph structure:
	//
	//     A  B  C  D
	//
	edges := map[string][]string{
		"A": {},
		"B": {},
		"C": {},
		"D": {},
	}

	t.runTest(edges)
}

func (t *TraverseDAGTest) SimpleRootedTree() {
	// Graph structure:
	//
	//        A
	//      / |
	//     B  C
	//      / | \
	//     D  E  F
	//      / |  |
	//     G  H  I
	//           | \
	//           J  K
	//
	edges := map[string][]string{
		"A": {"B", "C"},
		"B": {},
		"C": {"D", "E", "F"},
		"D": {},
		"E": {"G", "H"},
		"F": {"I"},
		"G": {},
		"H": {},
		"I": {"J", "K"},
		"J": {},
		"K": {},
	}

	t.runTest(edges)
}

func (t *TraverseDAGTest) SimpleDAG() {
	// Graph structure:
	//
	//        A
	//      /  \
	//     B    C
	//      \  /|
	//        D |
	//         \|
	//          E
	//
	edges := map[string][]string{
		"A": {"B", "C"},
		"B": {"D"},
		"C": {"D", "E"},
		"D": {"E"},
		"E": {},
	}

	t.runTest(edges)
}

func (t *TraverseDAGTest) MultipleConnectedComponents() {
	// Graph structure:
	//
	//        A       E
	//      /  \      |\
	//     B    C     F G
	//      \  /
	//        D
	//
	edges := map[string][]string{
		"A": {"B", "C"},
		"B": {"D"},
		"C": {"D"},
		"D": {},
		"E": {"F", "G"},
		"F": {},
		"G": {},
	}

	t.runTest(edges)
}

func (t *TraverseDAGTest) LargeRootedTree() {
	const depth = 6
	edges := randomTree(depth)
	t.runTest(edges)
}

func (t *TraverseDAGTest) LargeRootedTree_Inverted() {
	const depth = 6
	edges := invertRelation(randomTree(depth))
	t.runTest(edges)
}

func (t *TraverseDAGTest) SuccessorFinderReturnsError() {
	AssertTrue(false, "TODO")
}

func (t *TraverseDAGTest) VisitorReturnsError() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"fmt"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"reflect"
)

var spd = spew.ConfigState{Indent: "\t", DisableMethods: true}

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type parserMessage int

const (
	warningShortUnderline parserMessage = iota
	errorUnexpectedSectionTitle
	errorUnexpectedSectionTitleOrTransition
)

var parserErrors = [...]string{
	"errorUnexpectedSectionTitle",
	"errorUnexpectedSectionTitleOrTransition",
}

func (p parserMessage) String() string {
	return parserErrors[p]
}

func (p parserMessage) Message() (s string) {
	switch p {
	case warningShortUnderline:
		s = "Title underline too short."
	case errorUnexpectedSectionTitle:
		s = "Unexpected section title."
	case errorUnexpectedSectionTitleOrTransition:
		s = "Unexpected section title or transition."
	}
	return
}

func (p parserMessage) Level() (s systemMessageLevel) {
	switch p {
	case warningShortUnderline:
		s = levelWarning
	case errorUnexpectedSectionTitle:
		s = levelSevere
	case errorUnexpectedSectionTitleOrTransition:
		s = levelSevere
	}
	return
}

type sectionLevels []*SectionNode

func (s *sectionLevels) String() string {
	var out string
	for _, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			sec.Level, sec.UnderLine.Rune, sec.OverLine != nil, sec.Length)
	}
	return out
}

// Returns nil if not found
func (s *sectionLevels) FindByRune(adornChar rune) *SectionNode {
	for _, sec := range *s {
		if sec.UnderLine.Rune == adornChar {
			return sec
		}
	}
	return nil
}

// If exists == true, a section node with the same text and underline has been found in
// sectionLevels, sec is the matching SectionNode. If exists == false, then the sec return value is
// the similarly leveled SectionNode. If exists == false and sec == nil, then the SectionNode added
// to sectionLevels is a new Node.
func (s *sectionLevels) Add(section *SectionNode) (exists bool, sec *SectionNode) {
	sec = s.FindByRune(section.UnderLine.Rune)
	if sec != nil {
		if sec.Text == section.Text {
			return true, sec
		} else if sec.Text != section.Text {
			section.Level = sec.Level
		}
	} else {
		section.Level = len(*s) + 1
	}
	exists = false
	*s = append(*s, section)
	return
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{
		Name:          name,
		Nodes:         newList(),
		nodeTarget:    newList(),
		sectionLevels: new(sectionLevels),
		indentWidth:   indentWidth,
	}
}

const (
	tokenZero   = 3
	indentWidth = 4 // Default indent width
)

type Tree struct {
	Name             string
	Nodes            *NodeList // The root node list
	nodeTarget       *NodeList // Used by the parser to add nodes to a target NodeList
	Errors           []error
	text             string
	lex              *lexer
	tokenBackupCount int
	tokenPeekCount   int
	token            [7]*item
	sectionLevels    *sectionLevels // Encountered section levels
	id               int            // The unique id of the node in the tree
	indentWidth      int
	indentLevel      int
}

func (t *Tree) errorf(format string, args ...interface{}) {
	format = fmt.Sprintf("go-rst: %s:%d: %s\n", t.Name, t.lex.lineNumber(), format)
	t.Errors = append(t.Errors, fmt.Errorf(format, args...))
}

func (t *Tree) error(err error) {
	t.errorf("%s\n", err)
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.lex = lex
}

// stopParse terminates parsing.
func (t *Tree) stopParse() {
	t.Nodes = nil
	t.nodeTarget = nil
	t.lex = nil
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.nodeTarget = t.Nodes

	for t.peek(1).Type != itemEOF {
		var n Node

		token := t.next()
		log.Infof("Got token: %#+v\n", token)

		switch token.Type {
		case itemSectionAdornment:
			n = t.section(token)
		case itemParagraph:
			n = newParagraph(token, &t.id)
		case itemSpace:
			n = t.indent(token)
			if n == nil {
				continue
			}
		case itemTitle, itemBlankLine:
			// itemTitle is consumed when evaluating itemSectionAdornment
			continue
		default:
			t.errorf("%q Not implemented!", token.Type)
			continue
		}

		t.nodeTarget.append(n)

		switch n.NodeType() {
		case NodeSection, NodeBlockQuote:
			// Set the loop to append items to the NodeList of the new section
			t.nodeTarget = reflect.ValueOf(n).Elem().FieldByName("NodeList").Addr().Interface().(*NodeList)
		}
	}

	log.Debugln("End")
}

func (t *Tree) backup() *item {
	t.tokenBackupCount++
	// log.Debugln("t.tokenBackupCount:", t.tokenPeekCount)
	for i := len(t.token) - 1; i > 0; i-- {
		t.token[i] = t.token[i-1]
		t.token[i-1] = nil
	}
	// log.Debugf("\n##### backup() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero-t.tokenBackupCount]
}

func (t *Tree) peekBack(pos int) *item {
	return t.token[tokenZero-pos]
}

func (t *Tree) peek(pos int) *item {
	// log.Debugln("t.tokenPeekCount:", t.tokenPeekCount, "Pos:", pos)
	for i := 0; i < pos; i++ {
		t.tokenPeekCount++
		if t.token[tokenZero+t.tokenPeekCount] == nil {
			t.token[tokenZero+t.tokenPeekCount] = t.lex.nextItem()
		}
	}
	// log.Debugf("\n##### peek() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero+t.tokenPeekCount]
}

// skip shifts the pointers left in t.token, pos is the amount to shift
func (t *Tree) skip(num int) {
	for i := num; i > 0; i-- {
		for x := 0; x < len(t.token)-1; x++ {
			t.token[x] = t.token[x+1]
			t.token[x+1] = nil
		}
	}
}

func (t *Tree) next() *item {
	// log.Debugln("t.tokenPeekCount:", t.tokenPeekCount)
	if t.tokenPeekCount > 0 {
		t.skip(t.tokenPeekCount)
	} else {
		t.skip(1)
		t.token[tokenZero] = t.lex.nextItem()
	}
	t.tokenBackupCount, t.tokenPeekCount = 0, 0
	// log.Debugf("\n##### next() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero]
}

func (t *Tree) section(i *item) Node {
	log.Debugln("Start")
	var overAdorn, title, underAdorn *item
	var overline bool

	peekBack := t.peekBack(1)
	if peekBack != nil {
		if peekBack.Type == itemSpace {
			// Looking back past the white space
			if t.peekBack(2).Type == itemTitle {
				return t.systemMessage(errorUnexpectedSectionTitle)
			}
			return t.systemMessage(errorUnexpectedSectionTitleOrTransition)
		} else if peekBack.Type == itemTitle {
			if t.peekBack(2) != nil && t.peekBack(2).Type == itemSectionAdornment {
				// The overline of the section
				overline = true
				overAdorn = peekBack
			}
		}
	}

	title = t.peekBack(1)
	underAdorn = i

	// TODO: Change these into proper error messages!
	// Check adornment for proper syntax
	if underAdorn.Type == itemSpace {
		t.backup() // Put the parser back on the title
		return t.systemMessage(errorUnexpectedSectionTitle)
	} else if title.Length != underAdorn.Length {
		t.errorf("Section under line not equal to title length!")
	} else if overline && title.Length != overAdorn.Length {
		t.errorf("Section over line not equal to title length!")
	} else if overline && overAdorn.Text != underAdorn.Text {
		t.errorf("Section title over line does not match section title under line.")
	}

	sec := newSection(title, overAdorn, underAdorn, &t.id)
	exists, eSec := t.sectionLevels.Add(sec)
	if exists && eSec != nil {
		t.errorf("SectionNode using Text \"%s\" and Rune '%s' was previously parsed!",
			sec.Text, string(sec.UnderLine.Rune))
	} else if !exists && eSec != nil {
		// There is a matching level in sectionLevels
		t.nodeTarget = &(*t.sectionLevels)[sec.Level-2].NodeList
	}

	log.Debugln("End")
	return sec
}

func (t *Tree) systemMessage(err parserMessage) Node {
	var lbText string
	var lbTextLen int

	s := newSystemMessage(&item{
		Type: itemSystemMessage,
		Line: t.token[tokenZero].Line,
	},
		err.Level(), &t.id)

	msg := newParagraph(&item{
		Text:   err.Message(),
		Length: len(err.Message()),
	}, &t.id)

	switch err {
	case errorUnexpectedSectionTitle:
		log.Debugln("FOUND errorUnexpectedSectionTitle")
		lbText = t.token[1].Text.(string) + "\n" + t.token[3].Text.(string)
		lbTextLen = len(lbText) + 1
	case errorUnexpectedSectionTitleOrTransition:
		log.Debugln("FOUND errorUnexpectedSectionTitleOrTransition")
		lbText = t.token[tokenZero].Text.(string)
		lbTextLen = len(lbText)
	}

	lb := newLiteralBlock(&item{
		Type:   itemLiteralBlock,
		Text:   lbText,
		Length: lbTextLen, // Add one to account for the backslash
	}, &t.id)

	s.NodeList = append(s.NodeList, msg, lb)
	return s
}

func (t *Tree) indent(i *item) Node {
	level := i.Length / t.indentWidth
	if t.peekBack(1).Type == itemBlankLine {
		if t.indentLevel == level {
			// Append to the current blockquote NodeList
			return nil
		}
		t.indentLevel = level
		return newBlockQuote(&item{Type: itemBlockquote, Line: i.Line}, level, &t.id)
	}
	return nil
}
<commit_msg>parse.go: Add short underline warning<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"fmt"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"reflect"
)

var spd = spew.ConfigState{Indent: "\t", DisableMethods: true}

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type parserMessage int

const (
	warningShortUnderline parserMessage = iota
	errorUnexpectedSectionTitle
	errorUnexpectedSectionTitleOrTransition
)

var parserErrors = [...]string{
	"warningShortUnderline",
	"errorUnexpectedSectionTitle",
	"errorUnexpectedSectionTitleOrTransition",
}

func (p parserMessage) String() string {
	return parserErrors[p]
}

func (p parserMessage) Message() (s string) {
	switch p {
	case warningShortUnderline:
		s = "Title underline too short."
	case errorUnexpectedSectionTitle:
		s = "Unexpected section title."
	case errorUnexpectedSectionTitleOrTransition:
		s = "Unexpected section title or transition."
	}
	return
}

func (p parserMessage) Level() (s systemMessageLevel) {
	switch p {
	case warningShortUnderline:
		s = levelWarning
	case errorUnexpectedSectionTitle:
		s = levelSevere
	case errorUnexpectedSectionTitleOrTransition:
		s = levelSevere
	}
	return
}

type sectionLevels []*SectionNode

func (s *sectionLevels) String() string {
	var out string
	for _, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			sec.Level, sec.UnderLine.Rune, sec.OverLine != nil, sec.Length)
	}
	return out
}

// Returns nil if not found
func (s *sectionLevels) FindByRune(adornChar rune) *SectionNode {
	for _, sec := range *s {
		if sec.UnderLine.Rune == adornChar {
			return sec
		}
	}
	return nil
}

// If exists == true, a section node with the same text and underline has been found in
// sectionLevels, sec is the matching SectionNode. If exists == false, then the sec return value is
// the similarly leveled SectionNode. If exists == false and sec == nil, then the SectionNode added
// to sectionLevels is a new Node.
func (s *sectionLevels) Add(section *SectionNode) (exists bool, sec *SectionNode) {
	sec = s.FindByRune(section.UnderLine.Rune)
	if sec != nil {
		if sec.Text == section.Text {
			return true, sec
		} else if sec.Text != section.Text {
			section.Level = sec.Level
		}
	} else {
		section.Level = len(*s) + 1
	}
	exists = false
	*s = append(*s, section)
	return
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{
		Name:          name,
		Nodes:         newList(),
		nodeTarget:    newList(),
		sectionLevels: new(sectionLevels),
		indentWidth:   indentWidth,
	}
}

const (
	tokenZero   = 3
	indentWidth = 4 // Default indent width
)

type Tree struct {
	Name             string
	Nodes            *NodeList // The root node list
	nodeTarget       *NodeList // Used by the parser to add nodes to a target NodeList
	Errors           []error
	text             string
	lex              *lexer
	tokenBackupCount int
	tokenPeekCount   int
	token            [7]*item
	sectionLevels    *sectionLevels // Encountered section levels
	id               int            // The unique id of the node in the tree
	indentWidth      int
	indentLevel      int
}

func (t *Tree) errorf(format string, args ...interface{}) {
	format = fmt.Sprintf("go-rst: %s:%d: %s\n", t.Name, t.lex.lineNumber(), format)
	t.Errors = append(t.Errors, fmt.Errorf(format, args...))
}

func (t *Tree) error(err error) {
	t.errorf("%s\n", err)
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.lex = lex
}

// stopParse terminates parsing.
func (t *Tree) stopParse() {
	t.Nodes = nil
	t.nodeTarget = nil
	t.lex = nil
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.nodeTarget = t.Nodes

	for t.peek(1).Type != itemEOF {
		var n Node

		token := t.next()
		log.Infof("Got token: %#+v\n", token)

		switch token.Type {
		case itemSectionAdornment:
			n = t.section(token)
		case itemParagraph:
			n = newParagraph(token, &t.id)
		case itemSpace:
			n = t.indent(token)
			if n == nil {
				continue
			}
		case itemTitle, itemBlankLine:
			// itemTitle is consumed when evaluating itemSectionAdornment
			continue
		default:
			t.errorf("%q Not implemented!", token.Type)
			continue
		}

		t.nodeTarget.append(n)

		switch n.NodeType() {
		case NodeSection, NodeBlockQuote:
			// Set the loop to append items to the NodeList of the new section
			t.nodeTarget = reflect.ValueOf(n).Elem().FieldByName("NodeList").Addr().Interface().(*NodeList)
		}
	}

	log.Debugln("End")
}

func (t *Tree) backup() *item {
	t.tokenBackupCount++
	// log.Debugln("t.tokenBackupCount:", t.tokenPeekCount)
	for i := len(t.token) - 1; i > 0; i-- {
		t.token[i] = t.token[i-1]
		t.token[i-1] = nil
	}
	// log.Debugf("\n##### backup() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero-t.tokenBackupCount]
}

func (t *Tree) peekBack(pos int) *item {
	return t.token[tokenZero-pos]
}

func (t *Tree) peek(pos int) *item {
	// log.Debugln("t.tokenPeekCount:", t.tokenPeekCount, "Pos:", pos)
	for i := 0; i < pos; i++ {
		t.tokenPeekCount++
		if t.token[tokenZero+t.tokenPeekCount] == nil {
			t.token[tokenZero+t.tokenPeekCount] = t.lex.nextItem()
		}
	}
	// log.Debugf("\n##### peek() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero+t.tokenPeekCount]
}

// skip shifts the pointers left in t.token, pos is the amount to shift
func (t *Tree) skip(num int) {
	for i := num; i > 0; i-- {
		for x := 0; x < len(t.token)-1; x++ {
			t.token[x] = t.token[x+1]
			t.token[x+1] = nil
		}
	}
}

func (t *Tree) next() *item {
	// log.Debugln("t.tokenPeekCount:", t.tokenPeekCount)
	if t.tokenPeekCount > 0 {
		t.skip(t.tokenPeekCount)
	} else {
		t.skip(1)
		t.token[tokenZero] = t.lex.nextItem()
	}
	t.tokenBackupCount, t.tokenPeekCount = 0, 0
	// log.Debugf("\n##### next() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero]
}

func (t *Tree) section(i *item) Node {
	log.Debugln("Start")
	var overAdorn, title, underAdorn *item
	var overline bool
	var sysMessage Node

	peekBack := t.peekBack(1)
	if peekBack != nil {
		if peekBack.Type == itemSpace {
			// Looking back past the white space
			if t.peekBack(2).Type == itemTitle {
				return t.systemMessage(errorUnexpectedSectionTitle)
			}
			return t.systemMessage(errorUnexpectedSectionTitleOrTransition)
		} else if peekBack.Type == itemTitle {
			if t.peekBack(2) != nil && t.peekBack(2).Type == itemSectionAdornment {
				// The overline of the section
				overline = true
				overAdorn = peekBack
			}
		}
	}

	title = t.peekBack(1)
	underAdorn = i

	// TODO: Change these into proper error messages!
	// Check adornment for proper syntax
	if underAdorn.Type == itemSpace {
		t.backup() // Put the parser back on the title
		return t.systemMessage(errorUnexpectedSectionTitle)
	} else if overline && title.Length != overAdorn.Length {
		t.errorf("Section over line not equal to title length!")
	} else if overline && overAdorn.Text != underAdorn.Text {
		t.errorf("Section title over line does not match section title under line.")
	}

	sec := newSection(title, overAdorn, underAdorn, &t.id)
	exists, eSec := t.sectionLevels.Add(sec)
	if exists && eSec != nil {
		t.errorf("SectionNode using Text \"%s\" and Rune '%s' was previously parsed!",
			sec.Text, string(sec.UnderLine.Rune))
	} else if !exists && eSec != nil {
		// There is a matching level in sectionLevels
		t.nodeTarget = &(*t.sectionLevels)[sec.Level-2].NodeList
	}

	// System messages have to be applied after the section is created in order to preserve
	// a consecutive id number.
	if title.Length != underAdorn.Length {
		sysMessage = t.systemMessage(warningShortUnderline)
		sec.NodeList = append(sec.NodeList, sysMessage)
	}

	log.Debugln("End")
	return sec
}

func (t *Tree) systemMessage(err parserMessage) Node {
	var lbText string
	var lbTextLen int
	var backToken int

	s := newSystemMessage(&item{
		Type: itemSystemMessage,
		Line: t.token[tokenZero].Line,
	},
		err.Level(), &t.id)

	msg := newParagraph(&item{
		Text:   err.Message(),
		Length: len(err.Message()),
	}, &t.id)

	switch err {
	case warningShortUnderline, errorUnexpectedSectionTitle:
		log.Debugln("FOUND", err)
		backToken = tokenZero - 1
		if t.peekBack(1).Type == itemSpace {
			backToken = tokenZero - 2
		}
		lbText = t.token[backToken].Text.(string) + "\n" + t.token[tokenZero].Text.(string)
		lbTextLen = len(lbText) + 1
	case errorUnexpectedSectionTitleOrTransition:
		log.Debugln("FOUND errorUnexpectedSectionTitleOrTransition")
		lbText = t.token[tokenZero].Text.(string)
		lbTextLen = len(lbText)
	}

	lb := newLiteralBlock(&item{
		Type:   itemLiteralBlock,
		Text:   lbText,
		Length: lbTextLen, // Add one to account for the backslash
	}, &t.id)

	s.NodeList = append(s.NodeList, msg, lb)
	return s
}

func (t *Tree) indent(i *item) Node {
	level := i.Length / t.indentWidth
	if t.peekBack(1).Type == itemBlankLine {
		if t.indentLevel == level {
			// Append to the current blockquote NodeList
			return nil
		}
		t.indentLevel = level
		return newBlockQuote(&item{Type: itemBlockquote, Line: i.Line}, level, &t.id)
	}
	return nil
}
<|endoftext|>


<commit_before>package pcap

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"time"
)

// LinkType describes the contents of each packet in a pcap.
type LinkType uint32

// Some of the more commonly used LinkTypes.
const (
	LinkEthernet LinkType = 1
	LinkRaw      LinkType = 101
)

// Reader extracts packets from a pcap file.
type Reader struct {
	LinkType LinkType

	r     io.Reader
	order binary.ByteOrder
	tmult int64
}

// Packet is one raw packet and its metadata.
type Packet struct {
	Timestamp time.Time
	Length    int
	Bytes     []byte
}

// NewReader returns a new Reader that decodes pcap data from r.
func NewReader(r io.Reader) (*Reader, error) {
	ret := &Reader{
		r:     bufio.NewReader(r),
		order: binary.LittleEndian,
	}

	header := struct {
		Magic uint32
		Major uint16
		Minor uint16
		// Timezone correction and time accuracy - both 0 in practice.
		Ignored uint64
		Snaplen uint32
		Type    uint32
	}{}

	bs := make([]byte, binary.Size(header))
	if _, err := io.ReadFull(ret.r, bs); err != nil {
		return nil, fmt.Errorf("reading pcap header: %s", err)
	}

	// Annoyingly, the header encodings are defined in terms of "same"
	// or "opposite" endian, rather than in absolute terms, so reading
	// the magic alone (as is intended) doesn't let us figure out what
	// endianness to use. However, we can cheat and look at the
	// major/minor version numbers instead. Try little-endian first,
	// since that's more common these days.
	if err := binary.Read(bytes.NewBuffer(bs), ret.order, &header); err != nil {
		return nil, err
	}
	if header.Major == 0x200 && header.Minor == 0x400 {
		// Byte order was wrong, read again
		ret.order = binary.BigEndian
		if err := binary.Read(bytes.NewBuffer(bs), ret.order, &header); err != nil {
			return nil, err
		}
	}
	switch header.Magic {
	case 0xa1b2c3d4:
		// Timestamps are (sec, usec)
		ret.tmult = 1000
	case 0xa1b23c4d:
		// Timestamps are (sec, nsec)
		ret.tmult = 1
	default:
		return nil, errors.New("bad magic")
	}

	if header.Major != 2 || header.Minor != 4 {
		return nil, fmt.Errorf("Unknown pcap version %d.%d", header.Major, header.Minor)
	}

	ret.LinkType = LinkType(header.Type)

	return ret, nil
}

// Next returns the next packet in r.
func (r *Reader) Next() (*Packet, error) {
	hdr := struct {
		Sec     uint32
		SubSec  uint32
		Len     uint32
		OrigLen uint32
	}{}

	if err := binary.Read(r.r, r.order, &hdr); err != nil {
		return nil, err
	}

	bs := make([]byte, hdr.Len)
	if _, err := io.ReadFull(r.r, bs); err != nil {
		return nil, err
	}

	return &Packet{
		Timestamp: time.Unix(int64(hdr.Sec), r.tmult*int64(hdr.SubSec)),
		Length:    int(hdr.OrigLen),
		Bytes:     bs,
	}, nil
}
<commit_msg>Add brief package documentation.<commit_after>// Package pcap implements reading and writing the "classic" libpcap format.
package pcap

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"time"
)

// LinkType describes the contents of each packet in a pcap.
type LinkType uint32

// Some of the more commonly used LinkTypes.
const (
	LinkEthernet LinkType = 1
	LinkRaw      LinkType = 101
)

// Reader extracts packets from a pcap file.
type Reader struct {
	LinkType LinkType

	r     io.Reader
	order binary.ByteOrder
	tmult int64
}

// Packet is one raw packet and its metadata.
type Packet struct {
	Timestamp time.Time
	Length    int
	Bytes     []byte
}

// NewReader returns a new Reader that decodes pcap data from r.
func NewReader(r io.Reader) (*Reader, error) {
	ret := &Reader{
		r:     bufio.NewReader(r),
		order: binary.LittleEndian,
	}

	header := struct {
		Magic uint32
		Major uint16
		Minor uint16
		// Timezone correction and time accuracy - both 0 in practice.
		Ignored uint64
		Snaplen uint32
		Type    uint32
	}{}

	bs := make([]byte, binary.Size(header))
	if _, err := io.ReadFull(ret.r, bs); err != nil {
		return nil, fmt.Errorf("reading pcap header: %s", err)
	}

	// Annoyingly, the header encodings are defined in terms of "same"
	// or "opposite" endian, rather than in absolute terms, so reading
	// the magic alone (as is intended) doesn't let us figure out what
	// endianness to use. However, we can cheat and look at the
	// major/minor version numbers instead. Try little-endian first,
	// since that's more common these days.
	if err := binary.Read(bytes.NewBuffer(bs), ret.order, &header); err != nil {
		return nil, err
	}
	if header.Major == 0x200 && header.Minor == 0x400 {
		// Byte order was wrong, read again
		ret.order = binary.BigEndian
		if err := binary.Read(bytes.NewBuffer(bs), ret.order, &header); err != nil {
			return nil, err
		}
	}
	switch header.Magic {
	case 0xa1b2c3d4:
		// Timestamps are (sec, usec)
		ret.tmult = 1000
	case 0xa1b23c4d:
		// Timestamps are (sec, nsec)
		ret.tmult = 1
	default:
		return nil, errors.New("bad magic")
	}

	if header.Major != 2 || header.Minor != 4 {
		return nil, fmt.Errorf("Unknown pcap version %d.%d", header.Major, header.Minor)
	}

	ret.LinkType = LinkType(header.Type)

	return ret, nil
}

// Next returns the next packet in r.
func (r *Reader) Next() (*Packet, error) {
	hdr := struct {
		Sec     uint32
		SubSec  uint32
		Len     uint32
		OrigLen uint32
	}{}

	if err := binary.Read(r.r, r.order, &hdr); err != nil {
		return nil, err
	}

	bs := make([]byte, hdr.Len)
	if _, err := io.ReadFull(r.r, bs); err != nil {
		return nil, err
	}

	return &Packet{
		Timestamp: time.Unix(int64(hdr.Sec), r.tmult*int64(hdr.SubSec)),
		Length:    int(hdr.OrigLen),
		Bytes:     bs,
	}, nil
}
<|endoftext|>


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

package pcapgo

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
)

// Reader wraps an underlying io.Reader to read packet data in PCAP
// format.  See http://wiki.wireshark.org/Development/LibpcapFileFormat
// for information on the file format.
//
// We currenty read v2.4 file format with nanosecond and microsecdond
// timestamp resolution in little-endian and big-endian encoding.
type Reader struct {
	r              io.Reader
	byteOrder      binary.ByteOrder
	nanoSecsFactor uint32
	versionMajor   uint16
	versionMinor   uint16
	// timezone
	// sigfigs
	snaplen  uint32
	linkType layers.LinkType
	// reusable buffer
	buf []byte
}

const magicNanoseconds = 0xA1B23C4D
const magicMicrosecondsBigendian = 0xD4C3B2A1
const magicNanosecondsBigendian = 0x4D3CB2A1

// NewReader returns a new reader object, for reading packet data from
// the given reader. The reader must be open and header data is
// read from it at this point.
// If the file format is not supported an error is returned
//
//  // Create new reader:
//  f, _ := os.Open("/tmp/file.pcap")
//  defer f.Close()
//  r, err := NewReader(f)
//  data, ci, err := r.ReadPacketData()
func NewReader(r io.Reader) (*Reader, error) {
	ret := Reader{r: r}
	if err := ret.readHeader(); err != nil {
		return nil, err
	}
	return &ret, nil
}

func (r *Reader) readHeader() error {
	buf := make([]byte, 24)
	if n, err := io.ReadFull(r.r, buf); err != nil {
		return err
	} else if n < 24 {
		return errors.New("Not enough data for read")
	}
	if magic := binary.LittleEndian.Uint32(buf[0:4]); magic == magicNanoseconds {
		r.byteOrder = binary.LittleEndian
		r.nanoSecsFactor = 1
	} else if magic == magicNanosecondsBigendian {
		r.byteOrder = binary.BigEndian
		r.nanoSecsFactor = 1
	} else if magic == magicMicroseconds {
		r.byteOrder = binary.LittleEndian
		r.nanoSecsFactor = 1000
	} else if magic == magicMicrosecondsBigendian {
		r.byteOrder = binary.BigEndian
		r.nanoSecsFactor = 1000
	} else {
		return errors.New(fmt.Sprintf("Unknown maigc %x", magic))
	}
	if r.versionMajor = r.byteOrder.Uint16(buf[4:6]); r.versionMajor != versionMajor {
		return errors.New(fmt.Sprintf("Unknown major version %d", r.versionMajor))
	}
	if r.versionMinor = r.byteOrder.Uint16(buf[6:8]); r.versionMinor != versionMinor {
		return errors.New(fmt.Sprintf("Unknown minor version %d", r.versionMinor))
	}
	// ignore timezone 8:12 and sigfigs 12:16
	r.snaplen = r.byteOrder.Uint32(buf[16:20])
	r.buf = make([]byte, r.snaplen+16)
	r.linkType = layers.LinkType(r.byteOrder.Uint32(buf[20:24]))
	return nil
}

// Read next packet from file
func (r *Reader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
	if ci, err = r.readPacketHeader(); err != nil {
		return
	}

	var n int
	if 16+ci.CaptureLength > len(r.buf) {
		return
	}
	data = r.buf[16 : 16+ci.CaptureLength]
	if n, err = io.ReadFull(r.r, data); err != nil {
		return
	} else if n < ci.CaptureLength {
		err = io.ErrUnexpectedEOF
	}
	return
}

func (r *Reader) readPacketHeader() (ci gopacket.CaptureInfo, err error) {
	var n int
	if n, err = io.ReadFull(r.r, r.buf[0:16]); err != nil {
		return
	} else if n < 16 {
		err = io.ErrUnexpectedEOF
		return
	}
	ci.Timestamp = time.Unix(int64(r.byteOrder.Uint32(r.buf[0:4])), int64(r.byteOrder.Uint32(r.buf[4:8])*r.nanoSecsFactor)).UTC()
	ci.CaptureLength = int(r.byteOrder.Uint32(r.buf[8:12]))
	ci.Length = int(r.byteOrder.Uint32(r.buf[12:16]))
	return
}

// LinkType returns network, as a layers.LinkType.
func (r *Reader) LinkType() layers.LinkType {
	return r.linkType
}

// Reader formater
func (r *Reader) String() string {
	return fmt.Sprintf("PcapFile  maj: %x min: %x snaplen: %d linktype: %s", r.versionMajor, r.versionMinor, r.snaplen, r.linkType)
}
<commit_msg>Add error for malformed packets received from pcapgo<commit_after>// Copyright 2014 Damjan Cvetko. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

package pcapgo

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
)

// Reader wraps an underlying io.Reader to read packet data in PCAP
// format.  See http://wiki.wireshark.org/Development/LibpcapFileFormat
// for information on the file format.
//
// We currenty read v2.4 file format with nanosecond and microsecdond
// timestamp resolution in little-endian and big-endian encoding.
type Reader struct {
	r              io.Reader
	byteOrder      binary.ByteOrder
	nanoSecsFactor uint32
	versionMajor   uint16
	versionMinor   uint16
	// timezone
	// sigfigs
	snaplen  uint32
	linkType layers.LinkType
	// reusable buffer
	buf []byte
}

const magicNanoseconds = 0xA1B23C4D
const magicMicrosecondsBigendian = 0xD4C3B2A1
const magicNanosecondsBigendian = 0x4D3CB2A1

// NewReader returns a new reader object, for reading packet data from
// the given reader. The reader must be open and header data is
// read from it at this point.
// If the file format is not supported an error is returned
//
//  // Create new reader:
//  f, _ := os.Open("/tmp/file.pcap")
//  defer f.Close()
//  r, err := NewReader(f)
//  data, ci, err := r.ReadPacketData()
func NewReader(r io.Reader) (*Reader, error) {
	ret := Reader{r: r}
	if err := ret.readHeader(); err != nil {
		return nil, err
	}
	return &ret, nil
}

func (r *Reader) readHeader() error {
	buf := make([]byte, 24)
	if n, err := io.ReadFull(r.r, buf); err != nil {
		return err
	} else if n < 24 {
		return errors.New("Not enough data for read")
	}
	if magic := binary.LittleEndian.Uint32(buf[0:4]); magic == magicNanoseconds {
		r.byteOrder = binary.LittleEndian
		r.nanoSecsFactor = 1
	} else if magic == magicNanosecondsBigendian {
		r.byteOrder = binary.BigEndian
		r.nanoSecsFactor = 1
	} else if magic == magicMicroseconds {
		r.byteOrder = binary.LittleEndian
		r.nanoSecsFactor = 1000
	} else if magic == magicMicrosecondsBigendian {
		r.byteOrder = binary.BigEndian
		r.nanoSecsFactor = 1000
	} else {
		return errors.New(fmt.Sprintf("Unknown maigc %x", magic))
	}
	if r.versionMajor = r.byteOrder.Uint16(buf[4:6]); r.versionMajor != versionMajor {
		return errors.New(fmt.Sprintf("Unknown major version %d", r.versionMajor))
	}
	if r.versionMinor = r.byteOrder.Uint16(buf[6:8]); r.versionMinor != versionMinor {
		return errors.New(fmt.Sprintf("Unknown minor version %d", r.versionMinor))
	}
	// ignore timezone 8:12 and sigfigs 12:16
	r.snaplen = r.byteOrder.Uint32(buf[16:20])
	r.buf = make([]byte, r.snaplen+16)
	r.linkType = layers.LinkType(r.byteOrder.Uint32(buf[20:24]))
	return nil
}

// Read next packet from file
func (r *Reader) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
	if ci, err = r.readPacketHeader(); err != nil {
		return
	}

	var n int
	if 16+ci.CaptureLength > len(r.buf) {
		return
	}
	data = r.buf[16 : 16+ci.CaptureLength]
	if n, err = io.ReadFull(r.r, data); err != nil {
		err = fmt.Errorf("capture length with header exceeds buffer size: %d > %d", 16+ci.CaptureLength, len(r.buf))
		return
	} else if n < ci.CaptureLength {
		err = io.ErrUnexpectedEOF
	}
	return
}

func (r *Reader) readPacketHeader() (ci gopacket.CaptureInfo, err error) {
	var n int
	if n, err = io.ReadFull(r.r, r.buf[0:16]); err != nil {
		return
	} else if n < 16 {
		err = io.ErrUnexpectedEOF
		return
	}
	ci.Timestamp = time.Unix(int64(r.byteOrder.Uint32(r.buf[0:4])), int64(r.byteOrder.Uint32(r.buf[4:8])*r.nanoSecsFactor)).UTC()
	ci.CaptureLength = int(r.byteOrder.Uint32(r.buf[8:12]))
	ci.Length = int(r.byteOrder.Uint32(r.buf[12:16]))
	return
}

// LinkType returns network, as a layers.LinkType.
func (r *Reader) LinkType() layers.LinkType {
	return r.linkType
}

// Reader formater
func (r *Reader) String() string {
	return fmt.Sprintf("PcapFile  maj: %x min: %x snaplen: %d linktype: %s", r.versionMajor, r.versionMinor, r.snaplen, r.linkType)
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  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 main

import (
	"io/ioutil"
	"os"
	"testing"
)

func TestOpenPIndex(t *testing.T) {
	pindex, err := OpenPIndex(nil, "not-a-bleve-file")
	if pindex != nil || err == nil {
		t.Errorf("expected OpenPIndex to fail on a bad file")
	}
}

func TestNewPIndex(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "",
		"sourceType", "sourceName", "sourceUUID", "sourceParams", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to work")
	}
	err = pindex.Close(true)
	if err != nil {
		t.Errorf("expected Close to work")
	}
}

func TestNewPIndexEmptyJSON(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "{}",
		"sourceType", "sourceName", "sourceUUID", "sourceParams", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to fail with empty json map")
	}
}

func TestNewPIndexBadMapping(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "} hey this isn't json :-(",
		"sourceType", "sourceName", "sourceUUID", "sourceParams", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex != nil || err == nil {
		t.Errorf("expected NewPIndex to fail with bad json")
	}
}

func TestNewPIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	restart := func() {
		t.Errorf("not expecting a restart")
	}

	indexSchema := ""

	pindexImpl, dest, err := NewPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE",
		indexSchema, emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on unknown impl type")
	}

	pindexImpl, dest, err = OpenPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE", emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on unknown impl type")
	}

	pindexImpl, dest, err = NewPIndexImpl("bleve", indexSchema, emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on existing dir")
	}
}

func TestBlackholePIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	restart := func() {
		t.Errorf("not expecting a restart")
	}

	pindex, dest, err := NewBlackHolePIndexImpl("blackhole", "", emptyDir, restart)
	if err != nil || pindex == nil || dest == nil {
		t.Errorf("expected NewBlackHolePIndexImpl to work")
	}

	pindex, dest, err = OpenBlackHolePIndexImpl("blackhole", emptyDir, restart)
	if err != nil || pindex == nil || dest == nil {
		t.Errorf("expected OpenBlackHolePIndexImpl to work")
	}

	if pindex.Close() != nil ||
		dest.OnDataUpdate("", nil, 0, nil) != nil ||
		dest.OnDataDelete("", nil, 0) != nil ||
		dest.OnSnapshotStart("", 0, 0) != nil ||
		dest.SetOpaque("", nil) != nil ||
		dest.Rollback("", 0) != nil {
		t.Errorf("expected no errors from a blackhole pindex impl")
	}

	v, lastSeq, err := dest.GetOpaque("")
	if err != nil || v != nil || lastSeq != 0 {
		t.Errorf("expected nothing from blackhole.GetOpaque()")
	}
}
<commit_msg>more blackhole tests<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  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 main

import (
	"io/ioutil"
	"os"
	"testing"
)

func TestOpenPIndex(t *testing.T) {
	pindex, err := OpenPIndex(nil, "not-a-bleve-file")
	if pindex != nil || err == nil {
		t.Errorf("expected OpenPIndex to fail on a bad file")
	}
}

func TestNewPIndex(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "",
		"sourceType", "sourceName", "sourceUUID", "sourceParams", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to work")
	}
	err = pindex.Close(true)
	if err != nil {
		t.Errorf("expected Close to work")
	}
}

func TestNewPIndexEmptyJSON(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "{}",
		"sourceType", "sourceName", "sourceUUID", "sourceParams", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex == nil || err != nil {
		t.Errorf("expected NewPIndex to fail with empty json map")
	}
}

func TestNewPIndexBadMapping(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	pindex, err := NewPIndex(nil, "fake", "uuid",
		"bleve", "indexName", "indexUUID", "} hey this isn't json :-(",
		"sourceType", "sourceName", "sourceUUID", "sourceParams", "sourcePartitions",
		PIndexPath(emptyDir, "fake"))
	if pindex != nil || err == nil {
		t.Errorf("expected NewPIndex to fail with bad json")
	}
}

func TestNewPIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	restart := func() {
		t.Errorf("not expecting a restart")
	}

	indexSchema := ""

	pindexImpl, dest, err := NewPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE",
		indexSchema, emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on unknown impl type")
	}

	pindexImpl, dest, err = OpenPIndexImpl("AN UNKNOWN PINDEX IMPL TYPE", emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on unknown impl type")
	}

	pindexImpl, dest, err = NewPIndexImpl("bleve", indexSchema, emptyDir, restart)
	if err == nil || pindexImpl != nil || dest != nil {
		t.Errorf("expected err on existing dir")
	}
}

func TestBlackholePIndexImpl(t *testing.T) {
	emptyDir, _ := ioutil.TempDir("./tmp", "test")
	defer os.RemoveAll(emptyDir)

	restart := func() {
		t.Errorf("not expecting a restart")
	}

	pindex, dest, err := OpenBlackHolePIndexImpl("blackhole", emptyDir, restart)
	if err == nil || pindex != nil || dest != nil {
		t.Errorf("expected OpenBlackHolePIndexImpl to error on emptyDir")
	}

	pindex, dest, err = NewBlackHolePIndexImpl("blackhole", "", emptyDir, restart)
	if err != nil || pindex == nil || dest == nil {
		t.Errorf("expected NewBlackHolePIndexImpl to work")
	}

	pindex, dest, err = OpenBlackHolePIndexImpl("blackhole", emptyDir, restart)
	if err != nil || pindex == nil || dest == nil {
		t.Errorf("expected OpenBlackHolePIndexImpl to work")
	}

	if pindex.Close() != nil ||
		dest.OnDataUpdate("", nil, 0, nil) != nil ||
		dest.OnDataDelete("", nil, 0) != nil ||
		dest.OnSnapshotStart("", 0, 0) != nil ||
		dest.SetOpaque("", nil) != nil ||
		dest.Rollback("", 0) != nil {
		t.Errorf("expected no errors from a blackhole pindex impl")
	}

	v, lastSeq, err := dest.GetOpaque("")
	if err != nil || v != nil || lastSeq != 0 {
		t.Errorf("expected nothing from blackhole.GetOpaque()")
	}

	bt := pindexImplTypes["blackhole"]
	if bt == nil {
		t.Errorf("expected blackhole in pindexImplTypes")
	}
	if bt.New == nil || bt.Open == nil {
		t.Errorf("blackhole should have open and new funcs")
	}
	count, err := bt.Count(nil, "", "")
	if err == nil || count != 0 {
		t.Errorf("expected blackhole count to err")
	}
	err = bt.Query(nil, "", "", nil, nil)
	if err == nil {
		t.Errorf("expected blackhole query to err")
	}
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/Unknwon/macaron"
	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/middleware"
	m "github.com/grafana/grafana/pkg/models"
	"github.com/macaron-contrib/binding"
)

// Register adds http routes
func Register(r *macaron.Macaron) {
	reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
	reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
	reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
	regOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
	quota := middleware.Quota
	bind := binding.Bind

	// not logged in views
	r.Get("/", reqSignedIn, Index)
	r.Get("/logout", Logout)
	r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), wrap(LoginPost))
	r.Get("/login/:name", quota("session"), OAuthLogin)
	r.Get("/login", LoginView)
	r.Get("/invite/:code", Index)

	// authed views
	r.Get("/profile/", reqSignedIn, Index)
	r.Get("/org/", reqSignedIn, Index)
	r.Get("/org/new", reqSignedIn, Index)
	r.Get("/datasources/", reqSignedIn, Index)
	r.Get("/datasources/edit/*", reqSignedIn, Index)
	r.Get("/org/users/", reqSignedIn, Index)
	r.Get("/org/apikeys/", reqSignedIn, Index)
	r.Get("/dashboard/import/", reqSignedIn, Index)
	r.Get("/admin/settings", reqGrafanaAdmin, Index)
	r.Get("/admin/users", reqGrafanaAdmin, Index)
	r.Get("/admin/users/create", reqGrafanaAdmin, Index)
	r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/dashboard/*", reqSignedIn, Index)

	// sign up
	r.Get("/signup", Index)
	r.Get("/api/user/signup/options", wrap(GetSignUpOptions))
	r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), wrap(SignUp))
	r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), wrap(SignUpStep2))

	// invited
	r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode))
	r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), wrap(CompleteInvite))

	// reset password
	r.Get("/user/password/send-reset-email", Index)
	r.Get("/user/password/reset", Index)

	r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), wrap(SendResetPasswordEmail))
	r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), wrap(ResetPassword))

	// dashboard snapshots
	r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)
	r.Get("/dashboard/snapshot/*", Index)

	r.Get("/api/snapshots/:key", GetDashboardSnapshot)
	r.Get("/api/snapshots-delete/:key", DeleteDashboardSnapshot)

	// api renew session based on remember cookie
	r.Get("/api/login/ping", quota("session"), LoginApiPing)

	// authed api
	r.Group("/api", func() {

		// user (signed in)
		r.Group("/user", func() {
			r.Get("/", wrap(GetSignedInUser))
			r.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
			r.Post("/using/:id", wrap(UserSetUsingOrg))
			r.Get("/orgs", wrap(GetSignedInUserOrgList))
			r.Post("/stars/dashboard/:id", wrap(StarDashboard))
			r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))
			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
			r.Get("/quotas", wrap(GetUserQuotas))
		})

		// users (admin permission required)
		r.Group("/users", func() {
			r.Get("/", wrap(SearchUsers))
			r.Get("/:id", wrap(GetUserById))
			r.Get("/:id/orgs", wrap(GetUserOrgList))
			r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
		}, reqGrafanaAdmin)

		// org information available to all users.
		r.Group("/org", func() {
			r.Get("/", wrap(GetOrgCurrent))
			r.Get("/quotas", wrap(GetOrgQuotas))
		})

		// current org
		r.Group("/org", func() {
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrgCurrent))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddressCurrent))
			r.Post("/users", quota("user"), bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
			r.Get("/users", wrap(GetOrgUsersForCurrentOrg))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg))
			r.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg))

			// invites
			r.Get("/invites", wrap(GetPendingOrgInvites))
			r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
			r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
		}, regOrgAdmin)

		// create new org
		r.Post("/orgs", quota("org"), bind(m.CreateOrgCommand{}), wrap(CreateOrg))

		// search all orgs
		r.Get("/orgs", reqGrafanaAdmin, wrap(SearchOrgs))

		// orgs (admin routes)
		r.Group("/orgs/:orgId", func() {
			r.Get("/", wrap(GetOrgById))
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrg))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddress))
			r.Delete("/", wrap(DeleteOrgById))
			r.Get("/users", wrap(GetOrgUsers))
			r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser))
			r.Delete("/users/:userId", wrap(RemoveOrgUser))
			r.Get("/quotas", wrap(GetOrgQuotas))
			r.Put("/quotas/:target", bind(m.UpdateOrgQuotaCmd{}), wrap(UpdateOrgQuota))
		}, reqGrafanaAdmin)

		// auth api keys
		r.Group("/auth/keys", func() {
			r.Get("/", wrap(GetApiKeys))
			r.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
			r.Delete("/:id", wrap(DeleteApiKey))
		}, regOrgAdmin)

		// Data sources
		r.Group("/datasources", func() {
			r.Get("/", GetDataSources)
			r.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
			r.Put("/:id", bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
			r.Delete("/:id", DeleteDataSource)
			r.Get("/:id", GetDataSourceById)
			r.Get("/plugins", GetDataSourcePlugins)
		}, regOrgAdmin)

		r.Get("/frontend/settings/", GetFrontendSettings)
		r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
		r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)

		// Dashboard
		r.Group("/dashboards", func() {
			r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
			r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), PostDashboard)
			r.Get("/file/:file", GetDashboardFromJsonFile)
			r.Get("/home", GetHomeDashboard)
			r.Get("/tags", GetDashboardTags)
		})

		// Search
		r.Get("/search/", Search)

		// metrics
		r.Get("/metrics/test", GetTestMetrics)

	}, reqSignedIn)

	// admin api
	r.Group("/api/admin", func() {
		r.Get("/settings", AdminGetSettings)
		r.Post("/users", bind(dtos.AdminCreateUserForm{}), AdminCreateUser)
		r.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), AdminUpdateUserPassword)
		r.Put("/users/:id/permissions", bind(dtos.AdminUpdateUserPermissionsForm{}), AdminUpdateUserPermissions)
		r.Delete("/users/:id", AdminDeleteUser)
		r.Get("/users/:id/quotas", wrap(GetUserQuotas))
		r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota))
	}, reqGrafanaAdmin)

	// rendering
	r.Get("/render/*", reqSignedIn, RenderToPng)

	r.NotFound(NotFoundHandler)
}
<commit_msg>fix(http route): fixed dashboard-solo route to not return 404, fixes #2979<commit_after>package api

import (
	"github.com/Unknwon/macaron"
	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/middleware"
	m "github.com/grafana/grafana/pkg/models"
	"github.com/macaron-contrib/binding"
)

// Register adds http routes
func Register(r *macaron.Macaron) {
	reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
	reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
	reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
	regOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
	quota := middleware.Quota
	bind := binding.Bind

	// not logged in views
	r.Get("/", reqSignedIn, Index)
	r.Get("/logout", Logout)
	r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), wrap(LoginPost))
	r.Get("/login/:name", quota("session"), OAuthLogin)
	r.Get("/login", LoginView)
	r.Get("/invite/:code", Index)

	// authed views
	r.Get("/profile/", reqSignedIn, Index)
	r.Get("/org/", reqSignedIn, Index)
	r.Get("/org/new", reqSignedIn, Index)
	r.Get("/datasources/", reqSignedIn, Index)
	r.Get("/datasources/edit/*", reqSignedIn, Index)
	r.Get("/org/users/", reqSignedIn, Index)
	r.Get("/org/apikeys/", reqSignedIn, Index)
	r.Get("/dashboard/import/", reqSignedIn, Index)
	r.Get("/admin/settings", reqGrafanaAdmin, Index)
	r.Get("/admin/users", reqGrafanaAdmin, Index)
	r.Get("/admin/users/create", reqGrafanaAdmin, Index)
	r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)

	r.Get("/dashboard/*", reqSignedIn, Index)
	r.Get("/dashboard-solo/*", reqSignedIn, Index)

	// sign up
	r.Get("/signup", Index)
	r.Get("/api/user/signup/options", wrap(GetSignUpOptions))
	r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), wrap(SignUp))
	r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), wrap(SignUpStep2))

	// invited
	r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode))
	r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), wrap(CompleteInvite))

	// reset password
	r.Get("/user/password/send-reset-email", Index)
	r.Get("/user/password/reset", Index)

	r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), wrap(SendResetPasswordEmail))
	r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), wrap(ResetPassword))

	// dashboard snapshots
	r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)
	r.Get("/dashboard/snapshot/*", Index)

	r.Get("/api/snapshots/:key", GetDashboardSnapshot)
	r.Get("/api/snapshots-delete/:key", DeleteDashboardSnapshot)

	// api renew session based on remember cookie
	r.Get("/api/login/ping", quota("session"), LoginApiPing)

	// authed api
	r.Group("/api", func() {

		// user (signed in)
		r.Group("/user", func() {
			r.Get("/", wrap(GetSignedInUser))
			r.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
			r.Post("/using/:id", wrap(UserSetUsingOrg))
			r.Get("/orgs", wrap(GetSignedInUserOrgList))
			r.Post("/stars/dashboard/:id", wrap(StarDashboard))
			r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))
			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
			r.Get("/quotas", wrap(GetUserQuotas))
		})

		// users (admin permission required)
		r.Group("/users", func() {
			r.Get("/", wrap(SearchUsers))
			r.Get("/:id", wrap(GetUserById))
			r.Get("/:id/orgs", wrap(GetUserOrgList))
			r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
		}, reqGrafanaAdmin)

		// org information available to all users.
		r.Group("/org", func() {
			r.Get("/", wrap(GetOrgCurrent))
			r.Get("/quotas", wrap(GetOrgQuotas))
		})

		// current org
		r.Group("/org", func() {
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrgCurrent))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddressCurrent))
			r.Post("/users", quota("user"), bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
			r.Get("/users", wrap(GetOrgUsersForCurrentOrg))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg))
			r.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg))

			// invites
			r.Get("/invites", wrap(GetPendingOrgInvites))
			r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
			r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
		}, regOrgAdmin)

		// create new org
		r.Post("/orgs", quota("org"), bind(m.CreateOrgCommand{}), wrap(CreateOrg))

		// search all orgs
		r.Get("/orgs", reqGrafanaAdmin, wrap(SearchOrgs))

		// orgs (admin routes)
		r.Group("/orgs/:orgId", func() {
			r.Get("/", wrap(GetOrgById))
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrg))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddress))
			r.Delete("/", wrap(DeleteOrgById))
			r.Get("/users", wrap(GetOrgUsers))
			r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser))
			r.Delete("/users/:userId", wrap(RemoveOrgUser))
			r.Get("/quotas", wrap(GetOrgQuotas))
			r.Put("/quotas/:target", bind(m.UpdateOrgQuotaCmd{}), wrap(UpdateOrgQuota))
		}, reqGrafanaAdmin)

		// auth api keys
		r.Group("/auth/keys", func() {
			r.Get("/", wrap(GetApiKeys))
			r.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
			r.Delete("/:id", wrap(DeleteApiKey))
		}, regOrgAdmin)

		// Data sources
		r.Group("/datasources", func() {
			r.Get("/", GetDataSources)
			r.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
			r.Put("/:id", bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
			r.Delete("/:id", DeleteDataSource)
			r.Get("/:id", GetDataSourceById)
			r.Get("/plugins", GetDataSourcePlugins)
		}, regOrgAdmin)

		r.Get("/frontend/settings/", GetFrontendSettings)
		r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
		r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)

		// Dashboard
		r.Group("/dashboards", func() {
			r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
			r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), PostDashboard)
			r.Get("/file/:file", GetDashboardFromJsonFile)
			r.Get("/home", GetHomeDashboard)
			r.Get("/tags", GetDashboardTags)
		})

		// Search
		r.Get("/search/", Search)

		// metrics
		r.Get("/metrics/test", GetTestMetrics)

	}, reqSignedIn)

	// admin api
	r.Group("/api/admin", func() {
		r.Get("/settings", AdminGetSettings)
		r.Post("/users", bind(dtos.AdminCreateUserForm{}), AdminCreateUser)
		r.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), AdminUpdateUserPassword)
		r.Put("/users/:id/permissions", bind(dtos.AdminUpdateUserPermissionsForm{}), AdminUpdateUserPermissions)
		r.Delete("/users/:id", AdminDeleteUser)
		r.Get("/users/:id/quotas", wrap(GetUserQuotas))
		r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota))
	}, reqGrafanaAdmin)

	// rendering
	r.Get("/render/*", reqSignedIn, RenderToPng)

	r.NotFound(NotFoundHandler)
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cve

import (
	"errors"
	"fmt"
	"regexp"

	cvss "github.com/spiegel-im-spiegel/go-cvss/v3/metric"
)

// CVE Information of a linked CVE vulnerability
type CVE struct {
	ID            string  `json:"id" yaml:"id"`                                 // CVE ID, eg CVE-2019-1010260
	Title         string  `json:"title" yaml:"title"`                           // Title of the vulnerability
	Description   string  `json:"description" yaml:"description"`               // Description text of the vulnerability
	TrackingIssue string  `json:"issue" yaml:"issue"`                           // Link to the vulnerability tracking issue (url, optional)
	CVSSVector    string  `json:"vector" yaml:"vector"`                         // Full CVSS vector string, CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H
	CVSSScore     float32 `json:"score" yaml:"score"`                           // Numeric CVSS score (eg 6.2)
	CVSSRating    string  `json:"rating" yaml:"rating"`                         // Severity bucket (eg Medium)
	CalcLink      string  `json:"calclink,omitempty" yaml:"calclink,omitempty"` // Link to the CVE calculator (automatic)
	LinkedPRs     []int   `json:"pullrequests"`                                 // List of linked PRs (to remove them from the release notes doc)
}

// ReadRawInterface populates the CVE data struct from the raw array
// as returned by the YAML parser
func (cve *CVE) ReadRawInterface(cvedata interface{}) error {
	if val, ok := cvedata.(map[interface{}]interface{})["id"].(string); ok {
		cve.ID = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["title"].(string); ok {
		cve.Title = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["issue"].(string); ok {
		cve.TrackingIssue = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["vector"].(string); ok {
		cve.CVSSVector = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["score"].(float64); ok {
		cve.CVSSScore = float32(val)
	}
	if val, ok := cvedata.(map[interface{}]interface{})["rating"].(string); ok {
		cve.CVSSRating = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["description"].(string); ok {
		cve.Description = val
	}
	// Linked PRs is a list of the PR IDs
	if val, ok := cvedata.(map[interface{}]interface{})["linkedPRs"].([]interface{}); ok {
		cve.LinkedPRs = []int{}
		for _, prid := range val {
			cve.LinkedPRs = append(cve.LinkedPRs, prid.(int))
		}
	}

	return nil
}

// Validate checks the data defined in a CVE map is complete and valid
func (cve *CVE) Validate() error {
	// Verify that rating is defined and a known string
	if cve.CVSSRating == "" {
		return errors.New("missing CVSS rating from CVE data")
	}

	// Check rating is a valid string
	if _, ok := map[string]bool{
		"None": true, "Low": true, "Medium": true, "High": true, "Critical": true,
	}[cve.CVSSRating]; !ok {
		return errors.New("invalid CVSS rating")
	}

	// Check vector string is not empty
	if cve.CVSSVector == "" {
		return errors.New("string CVSS vector missing from CVE data")
	}

	// Parse the vector string to make sure it is well formed
	bm, err := cvss.NewBase().Decode(cve.CVSSVector)
	if err != nil {
		return fmt.Errorf("parsing CVSS vector string: %w", err)
	}
	cve.CalcLink = fmt.Sprintf(
		"https://www.first.org/cvss/calculator/%s#%s", bm.Ver.String(), cve.CVSSVector,
	)

	if cve.CVSSScore == 0 {
		return errors.New("missing CVSS score from CVE data")
	}
	if cve.CVSSScore < 0 || cve.CVSSScore > 10 {
		return errors.New("out of range CVSS score, should be 0.0 - 10.0")
	}

	if err := ValidateID(cve.ID); err != nil {
		return fmt.Errorf("checking CVE ID: %w", err)
	}

	// Title and description must not be empty
	if cve.Title == "" {
		return errors.New("title missing from CVE data")
	}

	if cve.Description == "" {
		return errors.New("missing CVE description from CVE data")
	}

	return nil
}

// ValidateID checks if a CVE IS string is valid
func ValidateID(cveID string) error {
	if cveID == "" {
		return errors.New("empty CVE ID string")
	}

	// Verify that the CVE ID is well formed
	if !regexp.MustCompile(CVEIDRegExp).MatchString(cveID) {
		return errors.New("not well formed CVS ID")
	}

	return nil
}
<commit_msg>krel: Support Tempral CVE metrics<commit_after>/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cve

import (
	"errors"
	"fmt"
	"regexp"

	cvss "github.com/spiegel-im-spiegel/go-cvss/v3/metric"
)

// CVE Information of a linked CVE vulnerability
type CVE struct {
	ID            string  `json:"id" yaml:"id"`                                 // CVE ID, eg CVE-2019-1010260
	Title         string  `json:"title" yaml:"title"`                           // Title of the vulnerability
	Description   string  `json:"description" yaml:"description"`               // Description text of the vulnerability
	TrackingIssue string  `json:"issue" yaml:"issue"`                           // Link to the vulnerability tracking issue (url, optional)
	CVSSVector    string  `json:"vector" yaml:"vector"`                         // Full CVSS vector string, CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:U/C:H/I:H/A:H
	CVSSScore     float32 `json:"score" yaml:"score"`                           // Numeric CVSS score (eg 6.2)
	CVSSRating    string  `json:"rating" yaml:"rating"`                         // Severity bucket (eg Medium)
	CalcLink      string  `json:"calclink,omitempty" yaml:"calclink,omitempty"` // Link to the CVE calculator (automatic)
	LinkedPRs     []int   `json:"pullrequests"`                                 // List of linked PRs (to remove them from the release notes doc)
}

// ReadRawInterface populates the CVE data struct from the raw array
// as returned by the YAML parser
func (cve *CVE) ReadRawInterface(cvedata interface{}) error {
	if val, ok := cvedata.(map[interface{}]interface{})["id"].(string); ok {
		cve.ID = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["title"].(string); ok {
		cve.Title = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["issue"].(string); ok {
		cve.TrackingIssue = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["vector"].(string); ok {
		cve.CVSSVector = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["score"].(float64); ok {
		cve.CVSSScore = float32(val)
	}
	if val, ok := cvedata.(map[interface{}]interface{})["rating"].(string); ok {
		cve.CVSSRating = val
	}
	if val, ok := cvedata.(map[interface{}]interface{})["description"].(string); ok {
		cve.Description = val
	}
	// Linked PRs is a list of the PR IDs
	if val, ok := cvedata.(map[interface{}]interface{})["linkedPRs"].([]interface{}); ok {
		cve.LinkedPRs = []int{}
		for _, prid := range val {
			cve.LinkedPRs = append(cve.LinkedPRs, prid.(int))
		}
	}

	return nil
}

// Validate checks the data defined in a CVE map is complete and valid
func (cve *CVE) Validate() error {
	// Verify that rating is defined and a known string
	if cve.CVSSRating == "" {
		return errors.New("missing CVSS rating from CVE data")
	}

	// Check rating is a valid string
	if _, ok := map[string]bool{
		"None": true, "Low": true, "Medium": true, "High": true, "Critical": true,
	}[cve.CVSSRating]; !ok {
		return errors.New("invalid CVSS rating")
	}

	// Check vector string is not empty
	if cve.CVSSVector == "" {
		return errors.New("string CVSS vector missing from CVE data")
	}

	if len(cve.CVSSVector) == 44 {
		// Parse the vector string to make sure it is well formed
		bm, err := cvss.NewBase().Decode(cve.CVSSVector)
		if err != nil {
			return fmt.Errorf("parsing CVSS vector string: %w", err)
		}
		cve.CalcLink = fmt.Sprintf(
			"https://www.first.org/cvss/calculator/%s#%s", bm.Ver.String(), cve.CVSSVector,
		)
	} else {
		// Parse the vector string to make sure it is well formed
		bm, err := cvss.NewTemporal().Decode(cve.CVSSVector)
		if err != nil {
			return fmt.Errorf("parsing CVSS vector string: %w", err)
		}
		cve.CalcLink = fmt.Sprintf(
			"https://www.first.org/cvss/calculator/%s#%s", bm.Ver.String(), cve.CVSSVector,
		)
	}

	if cve.CVSSScore == 0 {
		return errors.New("missing CVSS score from CVE data")
	}
	if cve.CVSSScore < 0 || cve.CVSSScore > 10 {
		return errors.New("out of range CVSS score, should be 0.0 - 10.0")
	}

	if err := ValidateID(cve.ID); err != nil {
		return fmt.Errorf("checking CVE ID: %w", err)
	}

	// Title and description must not be empty
	if cve.Title == "" {
		return errors.New("title missing from CVE data")
	}

	if cve.Description == "" {
		return errors.New("missing CVE description from CVE data")
	}

	return nil
}

// ValidateID checks if a CVE IS string is valid
func ValidateID(cveID string) error {
	if cveID == "" {
		return errors.New("empty CVE ID string")
	}

	// Verify that the CVE ID is well formed
	if !regexp.MustCompile(CVEIDRegExp).MatchString(cveID) {
		return errors.New("not well formed CVS ID")
	}

	return nil
}
<|endoftext|>


<commit_before>package env

import (
	"os"
	"strings"

	"github.com/c4pt0r/cfg"
	errors "github.com/juju/errors"
	log "github.com/ngaut/logging"
	"github.com/ngaut/zkhelper"
)

type Env interface {
	ProductName() string
	DashboardAddr() string
	NewCoordConn() (zkhelper.Conn, error)
}

type RebornEnv struct {
	dashboardAddr   string
	productName     string
	coordinator     string
	coordinatorAddr string
}

func LoadRebornEnv(cfg *cfg.Cfg) Env {
	if cfg == nil {
		log.Fatal("config error")
	}

	productName, err := cfg.ReadString("product", "test")
	if err != nil {
		log.Fatal(err)
	}

	coordinatorAddr, err := cfg.ReadString("coordinator_addr", "localhost:2181")
	if err != nil {
		log.Fatal(err)
	}

	hostname, _ := os.Hostname()
	dashboardAddr, err := cfg.ReadString("dashboard_addr", hostname+":18087")
	if err != nil {
		log.Fatal(err)
	}

	coordinator, err := cfg.ReadString("coordinator", "zookeeper")
	if err != nil {
		log.Fatal(err)
	}

	return &RebornEnv{
		dashboardAddr:   dashboardAddr,
		productName:     productName,
		coordinator:     coordinator,
		coordinatorAddr: coordinatorAddr,
	}
}

func (e *RebornEnv) ProductName() string {
	return e.productName
}

func (e *RebornEnv) DashboardAddr() string {
	return e.dashboardAddr
}

func (e *RebornEnv) NewCoordConn() (zkhelper.Conn, error) {
	switch e.coordinator {
	case "zookeeper":
		return zkhelper.ConnectToZk(e.coordinatorAddr)
	case "etcd":
		addr := strings.TrimSpace(e.coordinatorAddr)
		if !strings.HasPrefix(addr, "http://") {
			addr = "http://" + addr
		}
		return zkhelper.NewEtcdConn(addr)
	}

	return nil, errors.Errorf("need coordinator in config file, %+v", e)
}
<commit_msg>pkg/evn: cleanup<commit_after>package env

import (
	"os"
	"strings"

	"github.com/c4pt0r/cfg"
	"github.com/juju/errors"
	log "github.com/ngaut/logging"
	"github.com/ngaut/zkhelper"
)

type Env interface {
	ProductName() string
	DashboardAddr() string
	NewCoordConn() (zkhelper.Conn, error)
}

type RebornEnv struct {
	dashboardAddr   string
	productName     string
	coordinator     string
	coordinatorAddr string
}

func LoadRebornEnv(cfg *cfg.Cfg) Env {
	if cfg == nil {
		log.Fatal("unexpected empty config")
	}

	productName, err := cfg.ReadString("product", "test")
	if err != nil {
		log.Fatal(err)
	}

	coordinatorAddr, err := cfg.ReadString("coordinator_addr", "localhost:2181")
	if err != nil {
		log.Fatal(err)
	}

	hostname, err := os.Hostname()
	if err != nil {
		log.Fatal(err)
	}

	dashboardAddr, err := cfg.ReadString("dashboard_addr", hostname+":18087")
	if err != nil {
		log.Fatal(err)
	}

	coordinator, err := cfg.ReadString("coordinator", "zookeeper")
	if err != nil {
		log.Fatal(err)
	}

	return &RebornEnv{
		dashboardAddr:   dashboardAddr,
		productName:     productName,
		coordinator:     coordinator,
		coordinatorAddr: coordinatorAddr,
	}
}

func (e *RebornEnv) ProductName() string {
	return e.productName
}

func (e *RebornEnv) DashboardAddr() string {
	return e.dashboardAddr
}

func (e *RebornEnv) NewCoordConn() (zkhelper.Conn, error) {
	switch e.coordinator {
	case "zookeeper":
		return zkhelper.ConnectToZk(e.coordinatorAddr)
	case "etcd":
		addr := strings.TrimSpace(e.coordinatorAddr)
		if !strings.HasPrefix(addr, "http://") {
			addr = "http://" + addr
		}
		return zkhelper.NewEtcdConn(addr)
	}

	return nil, errors.Errorf("need coordinator in config file, %+v", e)
}
<|endoftext|>


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

// +build linux,!arm,!arm64

package io

import (
	"encoding/binary"
	"io"
	"os"

	"github.com/u-root/u-root/pkg/ubinary"
)

var memPath = "/dev/mem"

func pathRead(path string, addr int64, data UintN) error {
	f, err := os.OpenFile(path, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err := f.Seek(addr, io.SeekCurrent); err != nil {
		return err
	}
	return binary.Read(f, ubinary.NativeEndian, data)
}

// Read reads data from physical memory at address addr. On x86 platforms,
// this uses the seek+read syscalls. On arm platforms, this uses mmap.
func Read(addr int64, data UintN) error {
	return pathRead(memPath, addr, data)
}

func pathWrite(path string, addr int64, data UintN) error {
	f, err := os.OpenFile(path, os.O_WRONLY, 0)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err := f.Seek(addr, io.SeekCurrent); err != nil {
		return err
	}
	return binary.Write(f, ubinary.NativeEndian, data)
}

// Write writes data to physical memory at address addr. On x86 platforms, this
// uses the seek+read syscalls. On arm platforms, this uses mmap.
func Write(addr int64, data UintN) error {
	return pathWrite(memPath, addr, data)
}
<commit_msg>Use io.SeekStart for io command<commit_after>// Copyright 2012-2019 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux,!arm,!arm64

package io

import (
	"encoding/binary"
	"io"
	"os"

	"github.com/u-root/u-root/pkg/ubinary"
)

var memPath = "/dev/mem"

func pathRead(path string, addr int64, data UintN) error {
	f, err := os.OpenFile(path, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err := f.Seek(addr, io.SeekStart); err != nil {
		return err
	}
	return binary.Read(f, ubinary.NativeEndian, data)
}

// Read reads data from physical memory at address addr. On x86 platforms,
// this uses the seek+read syscalls. On arm platforms, this uses mmap.
func Read(addr int64, data UintN) error {
	return pathRead(memPath, addr, data)
}

func pathWrite(path string, addr int64, data UintN) error {
	f, err := os.OpenFile(path, os.O_WRONLY, 0)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err := f.Seek(addr, io.SeekStart); err != nil {
		return err
	}
	return binary.Write(f, ubinary.NativeEndian, data)
}

// Write writes data to physical memory at address addr. On x86 platforms, this
// uses the seek+read syscalls. On arm platforms, this uses mmap.
func Write(addr int64, data UintN) error {
	return pathWrite(memPath, addr, data)
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/freetype-go/freetype"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/jpeg"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
)

var (
	imageQuality             = jpeg.Options{95}
	bgColor      color.Color = color.RGBA{170, 170, 170, 1}
	fontColor      color.Color = color.White
	fontSize                 = 30
	fontSpacing              = 1.5
)

/* ************************************************************************** */
// Copy from https://code.google.com/p/gorilla/source/browse/color/hex.go

// HexModel converts any color.Color to an Hex color.
var HexModel = color.ModelFunc(hexModel)

// Hex represents an RGB color in hexadecimal format.
//
// The length must be 3 or 6 characters, preceded or not by a '#'.
type Hex string

// RGBA returns the alpha-premultiplied red, green, blue and alpha values
// for the Hex.
func (c Hex) RGBA() (uint32, uint32, uint32, uint32) {
	r, g, b := HexToRGB(c)
	return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
}

// hexModel converts a color.Color to Hex.
func hexModel(c color.Color) color.Color {
	if _, ok := c.(Hex); ok {
		return c
	}
	r, g, b, _ := c.RGBA()
	return RGBToHex(uint8(r>>8), uint8(g>>8), uint8(b>>8))
}

// RGBToHex converts an RGB triple to an Hex string.
func RGBToHex(r, g, b uint8) Hex {
	return Hex(fmt.Sprintf("#%02X%02X%02X", r, g, b))
}

// HexToRGB converts an Hex string to a RGB triple.
func HexToRGB(h Hex) (uint8, uint8, uint8) {
	if len(h) > 0 && h[0] == '#' {
		h = h[1:]
	}
	if len(h) == 3 {
		h = h[:1] + h[:1] + h[1:2] + h[1:2] + h[2:] + h[2:]
	}
	if len(h) == 6 {
		if rgb, err := strconv.ParseUint(string(h), 16, 32); err == nil {
			return uint8(rgb >> 16), uint8((rgb >> 8) & 0xFF), uint8(rgb & 0xFF)
		}
	}
	return 0, 0, 0
}

/* ************************************************************************** */

func handler(w http.ResponseWriter, r *http.Request) {
	params := strings.Split(r.URL.Path[1:], "/")
	if len(params) == 3 {
		r, g, b := HexToRGB(Hex(params[2]))
		fontColor = color.RGBA{r, g, b, 255}
	}

	if len(params) == 2 {
		r, g, b := HexToRGB(Hex(params[1]))
		bgColor = color.RGBA{r, g, b, 255}
	}
	size := strings.Split(params[0], "x")
	if len(size) < 2 {
		return
	}
	width, err := strconv.Atoi(size[0])
	if err != nil {
		width = 0
	}
	height, err := strconv.Atoi(size[1])
	if err != nil {
		height = 0
	}

	m := image.NewRGBA(image.Rect(0, 0, width, height))
	draw.Draw(m, m.Bounds(), &image.Uniform{bgColor}, image.ZP, draw.Src)

	fontBytes, err := ioutil.ReadFile("/usr/share/fonts/TTF/luxisr.ttf")
	font, err := freetype.ParseFont(fontBytes)
	if err != nil {
		log.Println(err)
		return
	}
	c := freetype.NewContext()
	c.SetDPI(72)
	c.SetFont(font)
	c.SetFontSize(float64(fontSize))
	c.SetClip(m.Bounds())
	c.SetDst(m)
	src := image.NewUniform(fontColor)
	c.SetSrc(src)
	c.SetHinting(freetype.FullHinting)

	text := fmt.Sprintf("%d X %d", width, height)
	x0 := width/2 - len(text)*fontSize/3
	y0 := height / 2
	pt := freetype.Pt(x0, y0)
	c.DrawString(text, pt)
	w.Header().Set("Content-Type", "image/jpeg")
	w.Header().Set("Cache-control", "public, max-age=259200")
	jpeg.Encode(w, m, &imageQuality)
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Fixed bug on one  size params.<commit_after>package main

import (
	"code.google.com/p/freetype-go/freetype"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/jpeg"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
)

var (
	imageQuality             = jpeg.Options{95}
	bgColor      color.Color = color.RGBA{170, 170, 170, 1}
	fontColor    color.Color = color.White
	fontSize                 = 30
	fontSpacing              = 1.5
)

/* ************************************************************************** */
// Copy from https://code.google.com/p/gorilla/source/browse/color/hex.go

// HexModel converts any color.Color to an Hex color.
var HexModel = color.ModelFunc(hexModel)

// Hex represents an RGB color in hexadecimal format.
//
// The length must be 3 or 6 characters, preceded or not by a '#'.
type Hex string

// RGBA returns the alpha-premultiplied red, green, blue and alpha values
// for the Hex.
func (c Hex) RGBA() (uint32, uint32, uint32, uint32) {
	r, g, b := HexToRGB(c)
	return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
}

// hexModel converts a color.Color to Hex.
func hexModel(c color.Color) color.Color {
	if _, ok := c.(Hex); ok {
		return c
	}
	r, g, b, _ := c.RGBA()
	return RGBToHex(uint8(r>>8), uint8(g>>8), uint8(b>>8))
}

// RGBToHex converts an RGB triple to an Hex string.
func RGBToHex(r, g, b uint8) Hex {
	return Hex(fmt.Sprintf("#%02X%02X%02X", r, g, b))
}

// HexToRGB converts an Hex string to a RGB triple.
func HexToRGB(h Hex) (uint8, uint8, uint8) {
	if len(h) > 0 && h[0] == '#' {
		h = h[1:]
	}
	if len(h) == 3 {
		h = h[:1] + h[:1] + h[1:2] + h[1:2] + h[2:] + h[2:]
	}
	if len(h) == 6 {
		if rgb, err := strconv.ParseUint(string(h), 16, 32); err == nil {
			return uint8(rgb >> 16), uint8((rgb >> 8) & 0xFF), uint8(rgb & 0xFF)
		}
	}
	return 0, 0, 0
}

/* ************************************************************************** */

func handler(w http.ResponseWriter, r *http.Request) {
	params := strings.Split(r.URL.Path[1:], "/")
	if len(params) == 3 {
		r, g, b := HexToRGB(Hex(params[2]))
		fontColor = color.RGBA{r, g, b, 255}
	}

	if len(params) == 2 {
		r, g, b := HexToRGB(Hex(params[1]))
		bgColor = color.RGBA{r, g, b, 255}
	}

	size := strings.Split(params[0], "x")

	var width, height int

	if len(size) == 1 {
		width, _ = strconv.Atoi(size[0])
		height = width
	} else {
		width, _ = strconv.Atoi(size[0])
		height, _ = strconv.Atoi(size[1])
	}

	m := image.NewRGBA(image.Rect(0, 0, width, height))
	draw.Draw(m, m.Bounds(), &image.Uniform{bgColor}, image.ZP, draw.Src)

	fontBytes, err := ioutil.ReadFile("/usr/share/fonts/TTF/luxisr.ttf")
	font, err := freetype.ParseFont(fontBytes)
	if err != nil {
		log.Println(err)
		return
	}
	c := freetype.NewContext()
	c.SetDPI(72)
	c.SetFont(font)
	c.SetFontSize(float64(fontSize))
	c.SetClip(m.Bounds())
	c.SetDst(m)
	src := image.NewUniform(fontColor)
	c.SetSrc(src)
	c.SetHinting(freetype.FullHinting)

	text := fmt.Sprintf("%d X %d", width, height)
	x0 := width/2 - len(text)*fontSize/3
	y0 := height / 2
	pt := freetype.Pt(x0, y0)
	c.DrawString(text, pt)
	w.Header().Set("Content-Type", "image/jpeg")
	w.Header().Set("Cache-control", "public, max-age=259200")
	jpeg.Encode(w, m, &imageQuality)
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>