<commit_before>package alfred

// A list of items to return to Alfred
type Items struct {
	Items []Item `json:"items"`
}

// An Alfred result item
type Item struct {
	UID          string `json:"uid,omitempty"`          // optional unique identifier for alfred to learn from
	Title        string `json:"title"`                  // title displayed in the result row
	Subtitle     string `json:"subtitle,omitempty"`     // optional subtitle displayed in the result row
	Arg          string `json:"arg,omitempty"`          // recommended string argument to pass through to output action
	Icon         *Icon  `json:"icon,omitempty"`         // optional icon argument
	Valid        bool   `json:"valid"`                  // valid means "actionable", false means "populate autocomplete text"
	Autocomplete string `json:"autocomplete,omitempty"` // recommended string to autocomplete with tab key
	// Type string // "default", "file", "file:skipcheck" to treat the result as a file
	// Mod Modifier // optional modifier keys object
	// Text string // optional text if copied to clipboard or displayed as large text
	// Quicklook string // optional url for quicklook
}

// A custom icon for an item
type Icon struct {
	Path string `json:"path"`           // the path to a file
	Type string `json:"type,omitempty"` // optional, "fileicon" for a path, "filetype" for a specific file
}
<commit_msg>Add Rerun option to alfred.Items for automatic rerun experiment<commit_after>package alfred

// Items is a list of items to return to Alfred
type Items struct {
	Items []Item  `json:"items"`
	Rerun float32 `json:"rerun,omitempty"`
}

// Item is an Alfred result item
type Item struct {
	UID          string `json:"uid,omitempty"`          // optional unique identifier for alfred to learn from
	Title        string `json:"title"`                  // title displayed in the result row
	Subtitle     string `json:"subtitle,omitempty"`     // optional subtitle displayed in the result row
	Arg          string `json:"arg,omitempty"`          // recommended string argument to pass through to output action
	Icon         *Icon  `json:"icon,omitempty"`         // optional icon argument
	Valid        bool   `json:"valid"`                  // valid means "actionable", false means "populate autocomplete text"
	Autocomplete string `json:"autocomplete,omitempty"` // recommended string to autocomplete with tab key
	// Type string // "default", "file", "file:skipcheck" to treat the result as a file
	// Mod Modifier // optional modifier keys object
	// Text string // optional text if copied to clipboard or displayed as large text
	// Quicklook string // optional url for quicklook
}

// Icon is a custom icon for an item
type Icon struct {
	Path string `json:"path"`           // the path to a file
	Type string `json:"type,omitempty"` // optional, "fileicon" for a path, "filetype" for a specific file
}
<|endoftext|>


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

package syntax

// Note to implementers:
// In this package, re is always a *Regexp and r is always a rune.

import (
	"bytes"
	"strconv"
	"strings"
	"unicode"
)

// A Regexp is a node in a regular expression syntax tree.
type Regexp struct {
	Op       Op // operator
	Flags    Flags
	Sub      []*Regexp  // subexpressions, if any
	Sub0     [1]*Regexp // storage for short Sub
	Rune     []rune     // matched runes, for OpLiteral, OpCharClass
	Rune0    [2]rune    // storage for short Rune
	Min, Max int        // min, max for OpRepeat
	Cap      int        // capturing index, for OpCapture
	Name     string     // capturing name, for OpCapture
}

// An Op is a single regular expression operator.
type Op uint8

// Operators are listed in precedence order, tightest binding to weakest.
// Character class operators are listed simplest to most complex
// (OpLiteral, OpCharClass, OpAnyCharNotNL, OpAnyChar).

const (
	OpNoMatch        Op = 1 + iota // matches no strings
	OpEmptyMatch                   // matches empty string
	OpLiteral                      // matches Runes sequence
	OpCharClass                    // matches Runes interpreted as range pair list
	OpAnyCharNotNL                 // matches any character
	OpAnyChar                      // matches any character
	OpBeginLine                    // matches empty string at beginning of line
	OpEndLine                      // matches empty string at end of line
	OpBeginText                    // matches empty string at beginning of text
	OpEndText                      // matches empty string at end of text
	OpWordBoundary                 // matches word boundary `\b`
	OpNoWordBoundary               // matches word non-boundary `\B`
	OpCapture                      // capturing subexpression with index Cap, optional name Name
	OpStar                         // matches Sub[0] zero or more times
	OpPlus                         // matches Sub[0] one or more times
	OpQuest                        // matches Sub[0] zero or one times
	OpRepeat                       // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit)
	OpConcat                       // matches concatenation of Subs
	OpAlternate                    // matches alternation of Subs
)

const opPseudo Op = 128 // where pseudo-ops start

// Equal returns true if x and y have identical structure.
func (x *Regexp) Equal(y *Regexp) bool {
	if x == nil || y == nil {
		return x == y
	}
	if x.Op != y.Op {
		return false
	}
	switch x.Op {
	case OpEndText:
		// The parse flags remember whether this is \z or \Z.
		if x.Flags&WasDollar != y.Flags&WasDollar {
			return false
		}

	case OpLiteral, OpCharClass:
		if len(x.Rune) != len(y.Rune) {
			return false
		}
		for i, r := range x.Rune {
			if r != y.Rune[i] {
				return false
			}
		}

	case OpAlternate, OpConcat:
		if len(x.Sub) != len(y.Sub) {
			return false
		}
		for i, sub := range x.Sub {
			if !sub.Equal(y.Sub[i]) {
				return false
			}
		}

	case OpStar, OpPlus, OpQuest:
		if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) {
			return false
		}

	case OpRepeat:
		if x.Flags&NonGreedy != y.Flags&NonGreedy || x.Min != y.Min || x.Max != y.Max || !x.Sub[0].Equal(y.Sub[0]) {
			return false
		}

	case OpCapture:
		if x.Cap != y.Cap || x.Name != y.Name || !x.Sub[0].Equal(y.Sub[0]) {
			return false
		}
	}
	return true
}

// writeRegexp writes the Perl syntax for the regular expression re to b.
func writeRegexp(b *bytes.Buffer, re *Regexp) {
	switch re.Op {
	default:
		b.WriteString("<invalid op" + strconv.Itoa(int(re.Op)) + ">")
	case OpNoMatch:
		b.WriteString(`[^\x00-\x{10FFFF}]`)
	case OpEmptyMatch:
		b.WriteString(`(?:)`)
	case OpLiteral:
		if re.Flags&FoldCase != 0 {
			b.WriteString(`(?i:`)
		}
		for _, r := range re.Rune {
			escape(b, r, false)
		}
		if re.Flags&FoldCase != 0 {
			b.WriteString(`)`)
		}
	case OpCharClass:
		if len(re.Rune)%2 != 0 {
			b.WriteString(`[invalid char class]`)
			break
		}
		b.WriteRune('[')
		if len(re.Rune) == 0 {
			b.WriteString(`^\x00-\x{10FFFF}`)
		} else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
			// Contains 0 and MaxRune.  Probably a negated class.
			// Print the gaps.
			b.WriteRune('^')
			for i := 1; i < len(re.Rune)-1; i += 2 {
				lo, hi := re.Rune[i]+1, re.Rune[i+1]-1
				escape(b, lo, lo == '-')
				if lo != hi {
					b.WriteRune('-')
					escape(b, hi, hi == '-')
				}
			}
		} else {
			for i := 0; i < len(re.Rune); i += 2 {
				lo, hi := re.Rune[i], re.Rune[i+1]
				escape(b, lo, lo == '-')
				if lo != hi {
					b.WriteRune('-')
					escape(b, hi, hi == '-')
				}
			}
		}
		b.WriteRune(']')
	case OpAnyCharNotNL:
		b.WriteString(`(?-s:.)`)
	case OpAnyChar:
		b.WriteString(`(?s:.)`)
	case OpBeginLine:
		b.WriteRune('^')
	case OpEndLine:
		b.WriteRune('$')
	case OpBeginText:
		b.WriteString(`\A`)
	case OpEndText:
		if re.Flags&WasDollar != 0 {
			b.WriteString(`(?-m:$)`)
		} else {
			b.WriteString(`\z`)
		}
	case OpWordBoundary:
		b.WriteString(`\b`)
	case OpNoWordBoundary:
		b.WriteString(`\B`)
	case OpCapture:
		if re.Name != "" {
			b.WriteString(`(?P<`)
			b.WriteString(re.Name)
			b.WriteRune('>')
		} else {
			b.WriteRune('(')
		}
		if re.Sub[0].Op != OpEmptyMatch {
			writeRegexp(b, re.Sub[0])
		}
		b.WriteRune(')')
	case OpStar, OpPlus, OpQuest, OpRepeat:
		if sub := re.Sub[0]; sub.Op > OpCapture || sub.Op == OpLiteral && len(sub.Rune) > 1 {
			b.WriteString(`(?:`)
			writeRegexp(b, sub)
			b.WriteString(`)`)
		} else {
			writeRegexp(b, sub)
		}
		switch re.Op {
		case OpStar:
			b.WriteRune('*')
		case OpPlus:
			b.WriteRune('+')
		case OpQuest:
			b.WriteRune('?')
		case OpRepeat:
			b.WriteRune('{')
			b.WriteString(strconv.Itoa(re.Min))
			if re.Max != re.Min {
				b.WriteRune(',')
				if re.Max >= 0 {
					b.WriteString(strconv.Itoa(re.Max))
				}
			}
			b.WriteRune('}')
		}
		if re.Flags&NonGreedy != 0 {
			b.WriteRune('?')
		}
	case OpConcat:
		for _, sub := range re.Sub {
			if sub.Op == OpAlternate {
				b.WriteString(`(?:`)
				writeRegexp(b, sub)
				b.WriteString(`)`)
			} else {
				writeRegexp(b, sub)
			}
		}
	case OpAlternate:
		for i, sub := range re.Sub {
			if i > 0 {
				b.WriteRune('|')
			}
			writeRegexp(b, sub)
		}
	}
}

func (re *Regexp) String() string {
	var b bytes.Buffer
	writeRegexp(&b, re)
	return b.String()
}

const meta = `\.+*?()|[]{}^$`

func escape(b *bytes.Buffer, r rune, force bool) {
	if unicode.IsPrint(r) {
		if strings.IndexRune(meta, r) >= 0 || force {
			b.WriteRune('\\')
		}
		b.WriteRune(r)
		return
	}

	switch r {
	case '\a':
		b.WriteString(`\a`)
	case '\f':
		b.WriteString(`\f`)
	case '\n':
		b.WriteString(`\n`)
	case '\r':
		b.WriteString(`\r`)
	case '\t':
		b.WriteString(`\t`)
	case '\v':
		b.WriteString(`\v`)
	default:
		if r < 0x100 {
			b.WriteString(`\x`)
			s := strconv.FormatInt(int64(r), 16)
			if len(s) == 1 {
				b.WriteRune('0')
			}
			b.WriteString(s)
			break
		}
		b.WriteString(`\x{`)
		b.WriteString(strconv.FormatInt(int64(r), 16))
		b.WriteString(`}`)
	}
}

// MaxCap walks the regexp to find the maximum capture index.
func (re *Regexp) MaxCap() int {
	m := 0
	if re.Op == OpCapture {
		m = re.Cap
	}
	for _, sub := range re.Sub {
		if n := sub.MaxCap(); m < n {
			m = n
		}
	}
	return m
}

// CapNames walks the regexp to find the names of capturing groups.
func (re *Regexp) CapNames() []string {
	names := make([]string, re.MaxCap()+1)
	re.capNames(names)
	return names
}

func (re *Regexp) capNames(names []string) {
	if re.Op == OpCapture {
		names[re.Cap] = re.Name
	}
	for _, sub := range re.Sub {
		sub.capNames(names)
	}
}
<commit_msg>regexp/syntax: Clarify comment of OpAnyCharNotNL.<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package syntax

// Note to implementers:
// In this package, re is always a *Regexp and r is always a rune.

import (
	"bytes"
	"strconv"
	"strings"
	"unicode"
)

// A Regexp is a node in a regular expression syntax tree.
type Regexp struct {
	Op       Op // operator
	Flags    Flags
	Sub      []*Regexp  // subexpressions, if any
	Sub0     [1]*Regexp // storage for short Sub
	Rune     []rune     // matched runes, for OpLiteral, OpCharClass
	Rune0    [2]rune    // storage for short Rune
	Min, Max int        // min, max for OpRepeat
	Cap      int        // capturing index, for OpCapture
	Name     string     // capturing name, for OpCapture
}

// An Op is a single regular expression operator.
type Op uint8

// Operators are listed in precedence order, tightest binding to weakest.
// Character class operators are listed simplest to most complex
// (OpLiteral, OpCharClass, OpAnyCharNotNL, OpAnyChar).

const (
	OpNoMatch        Op = 1 + iota // matches no strings
	OpEmptyMatch                   // matches empty string
	OpLiteral                      // matches Runes sequence
	OpCharClass                    // matches Runes interpreted as range pair list
	OpAnyCharNotNL                 // matches any character except newline
	OpAnyChar                      // matches any character
	OpBeginLine                    // matches empty string at beginning of line
	OpEndLine                      // matches empty string at end of line
	OpBeginText                    // matches empty string at beginning of text
	OpEndText                      // matches empty string at end of text
	OpWordBoundary                 // matches word boundary `\b`
	OpNoWordBoundary               // matches word non-boundary `\B`
	OpCapture                      // capturing subexpression with index Cap, optional name Name
	OpStar                         // matches Sub[0] zero or more times
	OpPlus                         // matches Sub[0] one or more times
	OpQuest                        // matches Sub[0] zero or one times
	OpRepeat                       // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit)
	OpConcat                       // matches concatenation of Subs
	OpAlternate                    // matches alternation of Subs
)

const opPseudo Op = 128 // where pseudo-ops start

// Equal returns true if x and y have identical structure.
func (x *Regexp) Equal(y *Regexp) bool {
	if x == nil || y == nil {
		return x == y
	}
	if x.Op != y.Op {
		return false
	}
	switch x.Op {
	case OpEndText:
		// The parse flags remember whether this is \z or \Z.
		if x.Flags&WasDollar != y.Flags&WasDollar {
			return false
		}

	case OpLiteral, OpCharClass:
		if len(x.Rune) != len(y.Rune) {
			return false
		}
		for i, r := range x.Rune {
			if r != y.Rune[i] {
				return false
			}
		}

	case OpAlternate, OpConcat:
		if len(x.Sub) != len(y.Sub) {
			return false
		}
		for i, sub := range x.Sub {
			if !sub.Equal(y.Sub[i]) {
				return false
			}
		}

	case OpStar, OpPlus, OpQuest:
		if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) {
			return false
		}

	case OpRepeat:
		if x.Flags&NonGreedy != y.Flags&NonGreedy || x.Min != y.Min || x.Max != y.Max || !x.Sub[0].Equal(y.Sub[0]) {
			return false
		}

	case OpCapture:
		if x.Cap != y.Cap || x.Name != y.Name || !x.Sub[0].Equal(y.Sub[0]) {
			return false
		}
	}
	return true
}

// writeRegexp writes the Perl syntax for the regular expression re to b.
func writeRegexp(b *bytes.Buffer, re *Regexp) {
	switch re.Op {
	default:
		b.WriteString("<invalid op" + strconv.Itoa(int(re.Op)) + ">")
	case OpNoMatch:
		b.WriteString(`[^\x00-\x{10FFFF}]`)
	case OpEmptyMatch:
		b.WriteString(`(?:)`)
	case OpLiteral:
		if re.Flags&FoldCase != 0 {
			b.WriteString(`(?i:`)
		}
		for _, r := range re.Rune {
			escape(b, r, false)
		}
		if re.Flags&FoldCase != 0 {
			b.WriteString(`)`)
		}
	case OpCharClass:
		if len(re.Rune)%2 != 0 {
			b.WriteString(`[invalid char class]`)
			break
		}
		b.WriteRune('[')
		if len(re.Rune) == 0 {
			b.WriteString(`^\x00-\x{10FFFF}`)
		} else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
			// Contains 0 and MaxRune.  Probably a negated class.
			// Print the gaps.
			b.WriteRune('^')
			for i := 1; i < len(re.Rune)-1; i += 2 {
				lo, hi := re.Rune[i]+1, re.Rune[i+1]-1
				escape(b, lo, lo == '-')
				if lo != hi {
					b.WriteRune('-')
					escape(b, hi, hi == '-')
				}
			}
		} else {
			for i := 0; i < len(re.Rune); i += 2 {
				lo, hi := re.Rune[i], re.Rune[i+1]
				escape(b, lo, lo == '-')
				if lo != hi {
					b.WriteRune('-')
					escape(b, hi, hi == '-')
				}
			}
		}
		b.WriteRune(']')
	case OpAnyCharNotNL:
		b.WriteString(`(?-s:.)`)
	case OpAnyChar:
		b.WriteString(`(?s:.)`)
	case OpBeginLine:
		b.WriteRune('^')
	case OpEndLine:
		b.WriteRune('$')
	case OpBeginText:
		b.WriteString(`\A`)
	case OpEndText:
		if re.Flags&WasDollar != 0 {
			b.WriteString(`(?-m:$)`)
		} else {
			b.WriteString(`\z`)
		}
	case OpWordBoundary:
		b.WriteString(`\b`)
	case OpNoWordBoundary:
		b.WriteString(`\B`)
	case OpCapture:
		if re.Name != "" {
			b.WriteString(`(?P<`)
			b.WriteString(re.Name)
			b.WriteRune('>')
		} else {
			b.WriteRune('(')
		}
		if re.Sub[0].Op != OpEmptyMatch {
			writeRegexp(b, re.Sub[0])
		}
		b.WriteRune(')')
	case OpStar, OpPlus, OpQuest, OpRepeat:
		if sub := re.Sub[0]; sub.Op > OpCapture || sub.Op == OpLiteral && len(sub.Rune) > 1 {
			b.WriteString(`(?:`)
			writeRegexp(b, sub)
			b.WriteString(`)`)
		} else {
			writeRegexp(b, sub)
		}
		switch re.Op {
		case OpStar:
			b.WriteRune('*')
		case OpPlus:
			b.WriteRune('+')
		case OpQuest:
			b.WriteRune('?')
		case OpRepeat:
			b.WriteRune('{')
			b.WriteString(strconv.Itoa(re.Min))
			if re.Max != re.Min {
				b.WriteRune(',')
				if re.Max >= 0 {
					b.WriteString(strconv.Itoa(re.Max))
				}
			}
			b.WriteRune('}')
		}
		if re.Flags&NonGreedy != 0 {
			b.WriteRune('?')
		}
	case OpConcat:
		for _, sub := range re.Sub {
			if sub.Op == OpAlternate {
				b.WriteString(`(?:`)
				writeRegexp(b, sub)
				b.WriteString(`)`)
			} else {
				writeRegexp(b, sub)
			}
		}
	case OpAlternate:
		for i, sub := range re.Sub {
			if i > 0 {
				b.WriteRune('|')
			}
			writeRegexp(b, sub)
		}
	}
}

func (re *Regexp) String() string {
	var b bytes.Buffer
	writeRegexp(&b, re)
	return b.String()
}

const meta = `\.+*?()|[]{}^$`

func escape(b *bytes.Buffer, r rune, force bool) {
	if unicode.IsPrint(r) {
		if strings.IndexRune(meta, r) >= 0 || force {
			b.WriteRune('\\')
		}
		b.WriteRune(r)
		return
	}

	switch r {
	case '\a':
		b.WriteString(`\a`)
	case '\f':
		b.WriteString(`\f`)
	case '\n':
		b.WriteString(`\n`)
	case '\r':
		b.WriteString(`\r`)
	case '\t':
		b.WriteString(`\t`)
	case '\v':
		b.WriteString(`\v`)
	default:
		if r < 0x100 {
			b.WriteString(`\x`)
			s := strconv.FormatInt(int64(r), 16)
			if len(s) == 1 {
				b.WriteRune('0')
			}
			b.WriteString(s)
			break
		}
		b.WriteString(`\x{`)
		b.WriteString(strconv.FormatInt(int64(r), 16))
		b.WriteString(`}`)
	}
}

// MaxCap walks the regexp to find the maximum capture index.
func (re *Regexp) MaxCap() int {
	m := 0
	if re.Op == OpCapture {
		m = re.Cap
	}
	for _, sub := range re.Sub {
		if n := sub.MaxCap(); m < n {
			m = n
		}
	}
	return m
}

// CapNames walks the regexp to find the names of capturing groups.
func (re *Regexp) CapNames() []string {
	names := make([]string, re.MaxCap()+1)
	re.capNames(names)
	return names
}

func (re *Regexp) capNames(names []string) {
	if re.Op == OpCapture {
		names[re.Cap] = re.Name
	}
	for _, sub := range re.Sub {
		sub.capNames(names)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Eleme Inc. All rights reserved.

package metric

// Metric with name and value
type Metric struct {
	Name   string  // metric name
	Stamp  uint64  // metric timestamp
	Value  float64 // metric value
	Score  float64 // metric anomaly score
	AvgOld float64 // previous average value
	AvgNew float64 // current average value
}

// New creates a Metric.
func New() *Metric {
	m := new(Metric)
	m.Stamp = 0
	m.Score = 0
	return m
}
<commit_msg>Use stamp as uint32 (able to be used for 90 years)<commit_after>// Copyright 2015 Eleme Inc. All rights reserved.

package metric

// Metric with name and value
type Metric struct {
	Name   string  // metric name
	Stamp  uint32  // metric timestamp (able to use for 90 years from now)
	Value  float64 // metric value
	Score  float64 // metric anomaly score
	AvgOld float64 // previous average value
	AvgNew float64 // current average value
}

// New creates a Metric.
func New() *Metric {
	m := new(Metric)
	m.Stamp = 0
	m.Score = 0
	return m
}
<|endoftext|>


<commit_before>package annotate

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strings"
	"testing"
	"text/template"
	"time"
	"unicode/utf8"
)

var saveExp = flag.Bool("exp", false, "overwrite all expected output files with actual output (returning a failure)")
var match = flag.String("m", "", "only run tests whose name contains this string")

func TestAnnotate(t *testing.T) {
	tests := map[string]struct {
		input   string
		anns    Annotations
		want    string
		wantErr error
	}{
		"empty and unannotated": {"", nil, "", nil},
		"unannotated":           {"a⌘b", nil, "a⌘b", nil},

		// The docs say "Annotating an empty byte array always returns an empty
		// byte array.", which is arbitrary but makes implementation easier.
		"empty annotated": {"", Annotations{{0, 0, []byte("["), []byte("]"), 0}}, "", nil},

		"zero-length annotations": {
			"aaaa",
			Annotations{
				{0, 0, []byte(""), []byte(""), 0},
				{0, 0, []byte(""), []byte(""), 0},
				{2, 2, []byte(""), []byte(""), 0},
			},
			"aaaa",
			nil,
		},
		"1 annotation": {"a", Annotations{{0, 1, []byte("["), []byte("]"), 0}}, "[a]", nil},
		"nested": {
			"abc",
			Annotations{
				{0, 3, []byte("["), []byte("]"), 0},
				{1, 2, []byte("<"), []byte(">"), 0},
			},
			"[ac]",
			nil,
		},
		"nested 1": {
			"abcd",
			Annotations{
				{0, 4, []byte("<1>"), []byte("</1>"), 0},
				{1, 3, []byte("<2>"), []byte("</2>"), 0},
				{2, 2, []byte("<3>"), []byte("</3>"), 0},
			},
			"<1>a<2>b<3></3>c</2>d</1>",
			nil,
		},
		"same range": {
			"ab",
			Annotations{
				{0, 2, []byte("["), []byte("]"), 0},
				{0, 2, []byte("<"), []byte(">"), 0},
			},
			"[<ab>]",
			nil,
		},
		"same range (with WantInner)": {
			"ab",
			Annotations{
				{0, 2, []byte("["), []byte("]"), 1},
				{0, 2, []byte("<"), []byte(">"), 0},
			},
			"<[ab]>",
			nil,
		},
		"unicode content": {
			"abcdef⌘vwxyz",
			Annotations{
				{6, 9, []byte(""), []byte(""), 0},
				{10, 12, []byte(""), []byte(""), 0},
				{0, 13, []byte("<c>"), []byte("</c>"), 0},
			},
			"<c>abcdef⌘vwxy</c>z",
			nil,
		},
		"remainder": {
			"xyz",
			Annotations{
				{0, 2, []byte(""), []byte(""), 0},
				{0, 1, []byte("<c>"), []byte("</c>"), 0},
			},
			"<c>x</c>yz",
			nil,
		},

		// Overlapping
		"overlap simple": {
			"abc",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{1, 3, []byte("<Y>"), []byte("</Y>"), 0},
			},
			// Without re-opening overlapped annotations, we'd get
			// "<X>a<Y>b</X>c</Y>".
			"<X>a<Y>b</Y></X><Y>c</Y>",
			nil,
		},
		"overlap simple double": {
			"abc",
			Annotations{
				{0, 2, []byte("<X1>"), []byte("</X1>"), 0},
				{0, 2, []byte("<X2>"), []byte("</X2>"), 0},
				{1, 3, []byte("<Y1>"), []byte("</Y1>"), 0},
				{1, 3, []byte("<Y2>"), []byte("</Y2>"), 0},
			},
			"<X1><X2>a<Y1><Y2>b</Y2></Y1></X2></X1><Y1><Y2>c</Y2></Y1>",
			nil,
		},
		"overlap triple complex": {
			"abcd",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{1, 3, []byte("<Y>"), []byte("</Y>"), 0},
				{2, 4, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<X>a<Y>b</Y></X><Y><Z>c</Z></Y><Z>d</Z>",
			nil,
		},
		"overlap same start": {
			"abcd",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{0, 3, []byte("<Y>"), []byte("</Y>"), 0},
				{1, 4, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<Y><X>a<Z>b</Z></X><Z>c</Z></Y><Z>d</Z>",
			nil,
		},
		"overlap (infinite loop regression #1)": {
			"abcde",
			Annotations{
				{0, 3, []byte("<X>"), []byte("</X>"), 0},
				{1, 5, []byte("<Y>"), []byte("</Y>"), 0},
				{1, 2, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<X>a<Y><Z>b</Z>c</Y></X><Y>de</Y>",
			nil,
		},

		// Errors
		"start oob": {"a", Annotations{{-1, 1, []byte("<"), []byte(">"), 0}}, "", ErrStartOutOfBounds},
		"start oob (multiple)": {
			"a",
			Annotations{
				{-3, 1, []byte("1"), []byte(""), 0},
				{-3, 1, []byte("2"), []byte(""), 0},
				{-1, 1, []byte("3"), []byte(""), 0},
			},
			"123a",
			ErrStartOutOfBounds,
		},
		"end oob": {"a", Annotations{{0, 3, []byte("<"), []byte(">"), 0}}, "", ErrEndOutOfBounds},
		"end oob (multiple)": {
			"ab",
			Annotations{
				{0, 3, []byte(""), []byte("1"), 0},
				{1, 3, []byte(""), []byte("2"), 0},
				{0, 5, []byte(""), []byte("3"), 0},
			},
			"ab213",
			ErrEndOutOfBounds,
		},
	}
	for label, test := range tests {
		if *match != "" && !strings.Contains(label, *match) {
			continue
		}

		sort.Sort(Annotations(test.anns))

		got, err := Annotate([]byte(test.input), test.anns, nil)
		if err != test.wantErr {
			if test.wantErr == nil {
				t.Errorf("%s: Annotate: %s", label, err)
			} else {
				t.Errorf("%s: Annotate: got error %v, want %v", label, err, test.wantErr)
			}
		}
		if string(got) != test.want {
			t.Errorf("%s: Annotate:\ngot  %q\nwant %q", label, got, test.want)
			continue
		}
	}
}

func TestAnnotate_Files(t *testing.T) {
	annsByFile := map[string]Annotations{
		"hello_world.txt": Annotations{
			{0, 5, []byte(""), []byte(""), 0},
			{7, 12, []byte(""), []byte(""), 0},
		},
		"adjacent.txt": Annotations{
			{0, 3, []byte(""), []byte(""), 0},
			{3, 6, []byte(""), []byte(""), 0},
		},
		"nested_0.txt": Annotations{
			{0, 4, []byte("<1>"), []byte("</1>"), 0},
			{1, 3, []byte("<2>"), []byte("</2>"), 0},
		},
		"nested_2.txt": Annotations{
			{0, 2, []byte("<1>"), []byte("</1>"), 0},
			{2, 4, []byte("<2>"), []byte("</2>"), 0},
			{4, 6, []byte("<3>"), []byte("</3>"), 0},
			{7, 8, []byte("<4>"), []byte("</4>"), 0},
		},
		"html.txt": Annotations{
			{193, 203, []byte("<1>"), []byte("</1>"), 0},
			{336, 339, []byte("<WOOF>"), []byte("</WOOF>"), 0},
		},
	}

	dir := "testdata"
	tests, err := ioutil.ReadDir(dir)
	if err != nil {
		t.Fatal(err)
	}

	for _, test := range tests {
		name := test.Name()
		if !strings.Contains(name, *match) {
			continue
		}
		if strings.HasSuffix(name, ".html") {
			continue
		}
		path := filepath.Join(dir, name)
		input, err := ioutil.ReadFile(path)
		if err != nil {
			t.Fatal(err)
			continue
		}

		anns := annsByFile[name]
		sort.Sort(anns)

		got, err := Annotate(input, anns, func(w io.Writer, b []byte) { template.HTMLEscape(w, b) })
		if err != nil {
			t.Errorf("%s: Annotate: %s", name, err)
			continue
		}

		expPath := path + ".html"
		if *saveExp {
			err = ioutil.WriteFile(expPath, got, 0700)
			if err != nil {
				t.Fatal(err)
			}
			continue
		}

		want, err := ioutil.ReadFile(expPath)
		if err != nil {
			t.Fatal(err)
		}

		want = bytes.TrimSpace(want)
		got = bytes.TrimSpace(got)

		if !bytes.Equal(want, got) {
			t.Errorf("%s: want %q, got %q", name, want, got)
			continue
		}
	}

	if *saveExp {
		t.Fatal("overwrote all expected output files with actual output (run tests again without -exp)")
	}
}

func makeFakeData(size1, size2 int) ([]byte, Annotations) {
	input := []byte(strings.Repeat(strings.Repeat("a", size1)+"⌘", size2))
	inputLength := utf8.RuneCount(input)
	n := len(input)/2 - (size1+1)/2
	anns := make(Annotations, n)
	for i := 0; i < n; i++ {
		if i%2 == 0 {
			anns[i] = &Annotation{Start: 2 * i, End: 2*i + 1}
		} else {
			anns[i] = &Annotation{Start: 2*i - 50, End: 2*i + 50}
			if anns[i].Start < 0 {
				anns[i].Start = 0
				anns[i].End = i
			}
			if anns[i].End >= inputLength {
				anns[i].End = inputLength
			}
		}
		anns[i].Left = []byte("L")  //[]byte(strings.Repeat("L", i%20))
		anns[i].Right = []byte("R") //[]byte(strings.Repeat("R", i%20))
		anns[i].WantInner = i % 5
	}
	sort.Sort(anns)
	return input, anns
}

func TestAnnotate_GeneratedData(t *testing.T) {
	input, anns := makeFakeData(1, 15)

	fail := func(err error) {
		annStrs := make([]string, len(anns))
		for i, a := range anns {
			annStrs[i] = fmt.Sprintf("%v", a)
		}
		t.Fatalf("Annotate: %s\n\nInput was:\n%q\n\nAnnotations:\n%s", err, input, strings.Join(annStrs, "\n"))
	}

	tm := time.NewTimer(time.Millisecond * 500)
	done := make(chan error)

	go func() {
		_, err := Annotate(input, anns, nil)
		done <- err
	}()

	select {
	case <-tm.C:
		fail(errors.New("timed out (is there an infinite loop?)"))
	case err := <-done:
		if err != nil {
			fail(err)
		}
	}
}

func BenchmarkAnnotate(b *testing.B) {
	input, anns := makeFakeData(99, 20)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := Annotate(input, anns, nil)
		if err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>Simplify code.<commit_after>package annotate

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strings"
	"testing"
	"text/template"
	"time"
	"unicode/utf8"
)

var saveExp = flag.Bool("exp", false, "overwrite all expected output files with actual output (returning a failure)")
var match = flag.String("m", "", "only run tests whose name contains this string")

func TestAnnotate(t *testing.T) {
	tests := map[string]struct {
		input   string
		anns    Annotations
		want    string
		wantErr error
	}{
		"empty and unannotated": {"", nil, "", nil},
		"unannotated":           {"a⌘b", nil, "a⌘b", nil},

		// The docs say "Annotating an empty byte array always returns an empty
		// byte array.", which is arbitrary but makes implementation easier.
		"empty annotated": {"", Annotations{{0, 0, []byte("["), []byte("]"), 0}}, "", nil},

		"zero-length annotations": {
			"aaaa",
			Annotations{
				{0, 0, []byte(""), []byte(""), 0},
				{0, 0, []byte(""), []byte(""), 0},
				{2, 2, []byte(""), []byte(""), 0},
			},
			"aaaa",
			nil,
		},
		"1 annotation": {"a", Annotations{{0, 1, []byte("["), []byte("]"), 0}}, "[a]", nil},
		"nested": {
			"abc",
			Annotations{
				{0, 3, []byte("["), []byte("]"), 0},
				{1, 2, []byte("<"), []byte(">"), 0},
			},
			"[ac]",
			nil,
		},
		"nested 1": {
			"abcd",
			Annotations{
				{0, 4, []byte("<1>"), []byte("</1>"), 0},
				{1, 3, []byte("<2>"), []byte("</2>"), 0},
				{2, 2, []byte("<3>"), []byte("</3>"), 0},
			},
			"<1>a<2>b<3></3>c</2>d</1>",
			nil,
		},
		"same range": {
			"ab",
			Annotations{
				{0, 2, []byte("["), []byte("]"), 0},
				{0, 2, []byte("<"), []byte(">"), 0},
			},
			"[<ab>]",
			nil,
		},
		"same range (with WantInner)": {
			"ab",
			Annotations{
				{0, 2, []byte("["), []byte("]"), 1},
				{0, 2, []byte("<"), []byte(">"), 0},
			},
			"<[ab]>",
			nil,
		},
		"unicode content": {
			"abcdef⌘vwxyz",
			Annotations{
				{6, 9, []byte(""), []byte(""), 0},
				{10, 12, []byte(""), []byte(""), 0},
				{0, 13, []byte("<c>"), []byte("</c>"), 0},
			},
			"<c>abcdef⌘vwxy</c>z",
			nil,
		},
		"remainder": {
			"xyz",
			Annotations{
				{0, 2, []byte(""), []byte(""), 0},
				{0, 1, []byte("<c>"), []byte("</c>"), 0},
			},
			"<c>x</c>yz",
			nil,
		},

		// Overlapping
		"overlap simple": {
			"abc",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{1, 3, []byte("<Y>"), []byte("</Y>"), 0},
			},
			// Without re-opening overlapped annotations, we'd get
			// "<X>a<Y>b</X>c</Y>".
			"<X>a<Y>b</Y></X><Y>c</Y>",
			nil,
		},
		"overlap simple double": {
			"abc",
			Annotations{
				{0, 2, []byte("<X1>"), []byte("</X1>"), 0},
				{0, 2, []byte("<X2>"), []byte("</X2>"), 0},
				{1, 3, []byte("<Y1>"), []byte("</Y1>"), 0},
				{1, 3, []byte("<Y2>"), []byte("</Y2>"), 0},
			},
			"<X1><X2>a<Y1><Y2>b</Y2></Y1></X2></X1><Y1><Y2>c</Y2></Y1>",
			nil,
		},
		"overlap triple complex": {
			"abcd",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{1, 3, []byte("<Y>"), []byte("</Y>"), 0},
				{2, 4, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<X>a<Y>b</Y></X><Y><Z>c</Z></Y><Z>d</Z>",
			nil,
		},
		"overlap same start": {
			"abcd",
			Annotations{
				{0, 2, []byte("<X>"), []byte("</X>"), 0},
				{0, 3, []byte("<Y>"), []byte("</Y>"), 0},
				{1, 4, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<Y><X>a<Z>b</Z></X><Z>c</Z></Y><Z>d</Z>",
			nil,
		},
		"overlap (infinite loop regression #1)": {
			"abcde",
			Annotations{
				{0, 3, []byte("<X>"), []byte("</X>"), 0},
				{1, 5, []byte("<Y>"), []byte("</Y>"), 0},
				{1, 2, []byte("<Z>"), []byte("</Z>"), 0},
			},
			"<X>a<Y><Z>b</Z>c</Y></X><Y>de</Y>",
			nil,
		},

		// Errors
		"start oob": {"a", Annotations{{-1, 1, []byte("<"), []byte(">"), 0}}, "", ErrStartOutOfBounds},
		"start oob (multiple)": {
			"a",
			Annotations{
				{-3, 1, []byte("1"), []byte(""), 0},
				{-3, 1, []byte("2"), []byte(""), 0},
				{-1, 1, []byte("3"), []byte(""), 0},
			},
			"123a",
			ErrStartOutOfBounds,
		},
		"end oob": {"a", Annotations{{0, 3, []byte("<"), []byte(">"), 0}}, "", ErrEndOutOfBounds},
		"end oob (multiple)": {
			"ab",
			Annotations{
				{0, 3, []byte(""), []byte("1"), 0},
				{1, 3, []byte(""), []byte("2"), 0},
				{0, 5, []byte(""), []byte("3"), 0},
			},
			"ab213",
			ErrEndOutOfBounds,
		},
	}
	for label, test := range tests {
		if *match != "" && !strings.Contains(label, *match) {
			continue
		}

		sort.Sort(Annotations(test.anns))

		got, err := Annotate([]byte(test.input), test.anns, nil)
		if err != test.wantErr {
			if test.wantErr == nil {
				t.Errorf("%s: Annotate: %s", label, err)
			} else {
				t.Errorf("%s: Annotate: got error %v, want %v", label, err, test.wantErr)
			}
		}
		if string(got) != test.want {
			t.Errorf("%s: Annotate:\ngot  %q\nwant %q", label, got, test.want)
			continue
		}
	}
}

func TestAnnotate_Files(t *testing.T) {
	annsByFile := map[string]Annotations{
		"hello_world.txt": Annotations{
			{0, 5, []byte(""), []byte(""), 0},
			{7, 12, []byte(""), []byte(""), 0},
		},
		"adjacent.txt": Annotations{
			{0, 3, []byte(""), []byte(""), 0},
			{3, 6, []byte(""), []byte(""), 0},
		},
		"nested_0.txt": Annotations{
			{0, 4, []byte("<1>"), []byte("</1>"), 0},
			{1, 3, []byte("<2>"), []byte("</2>"), 0},
		},
		"nested_2.txt": Annotations{
			{0, 2, []byte("<1>"), []byte("</1>"), 0},
			{2, 4, []byte("<2>"), []byte("</2>"), 0},
			{4, 6, []byte("<3>"), []byte("</3>"), 0},
			{7, 8, []byte("<4>"), []byte("</4>"), 0},
		},
		"html.txt": Annotations{
			{193, 203, []byte("<1>"), []byte("</1>"), 0},
			{336, 339, []byte("<WOOF>"), []byte("</WOOF>"), 0},
		},
	}

	dir := "testdata"
	tests, err := ioutil.ReadDir(dir)
	if err != nil {
		t.Fatal(err)
	}

	for _, test := range tests {
		name := test.Name()
		if !strings.Contains(name, *match) {
			continue
		}
		if strings.HasSuffix(name, ".html") {
			continue
		}
		path := filepath.Join(dir, name)
		input, err := ioutil.ReadFile(path)
		if err != nil {
			t.Fatal(err)
			continue
		}

		anns := annsByFile[name]
		sort.Sort(anns)

		got, err := Annotate(input, anns, template.HTMLEscape)
		if err != nil {
			t.Errorf("%s: Annotate: %s", name, err)
			continue
		}

		expPath := path + ".html"
		if *saveExp {
			err = ioutil.WriteFile(expPath, got, 0700)
			if err != nil {
				t.Fatal(err)
			}
			continue
		}

		want, err := ioutil.ReadFile(expPath)
		if err != nil {
			t.Fatal(err)
		}

		want = bytes.TrimSpace(want)
		got = bytes.TrimSpace(got)

		if !bytes.Equal(want, got) {
			t.Errorf("%s: want %q, got %q", name, want, got)
			continue
		}
	}

	if *saveExp {
		t.Fatal("overwrote all expected output files with actual output (run tests again without -exp)")
	}
}

func makeFakeData(size1, size2 int) ([]byte, Annotations) {
	input := []byte(strings.Repeat(strings.Repeat("a", size1)+"⌘", size2))
	inputLength := utf8.RuneCount(input)
	n := len(input)/2 - (size1+1)/2
	anns := make(Annotations, n)
	for i := 0; i < n; i++ {
		if i%2 == 0 {
			anns[i] = &Annotation{Start: 2 * i, End: 2*i + 1}
		} else {
			anns[i] = &Annotation{Start: 2*i - 50, End: 2*i + 50}
			if anns[i].Start < 0 {
				anns[i].Start = 0
				anns[i].End = i
			}
			if anns[i].End >= inputLength {
				anns[i].End = inputLength
			}
		}
		anns[i].Left = []byte("L")  //[]byte(strings.Repeat("L", i%20))
		anns[i].Right = []byte("R") //[]byte(strings.Repeat("R", i%20))
		anns[i].WantInner = i % 5
	}
	sort.Sort(anns)
	return input, anns
}

func TestAnnotate_GeneratedData(t *testing.T) {
	input, anns := makeFakeData(1, 15)

	fail := func(err error) {
		annStrs := make([]string, len(anns))
		for i, a := range anns {
			annStrs[i] = fmt.Sprintf("%v", a)
		}
		t.Fatalf("Annotate: %s\n\nInput was:\n%q\n\nAnnotations:\n%s", err, input, strings.Join(annStrs, "\n"))
	}

	tm := time.NewTimer(time.Millisecond * 500)
	done := make(chan error)

	go func() {
		_, err := Annotate(input, anns, nil)
		done <- err
	}()

	select {
	case <-tm.C:
		fail(errors.New("timed out (is there an infinite loop?)"))
	case err := <-done:
		if err != nil {
			fail(err)
		}
	}
}

func BenchmarkAnnotate(b *testing.B) {
	input, anns := makeFakeData(99, 20)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := Annotate(input, anns, nil)
		if err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>


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

/*
Package gorilla/mux implements a request router and dispatcher.

The name mux stands for "HTTP request multiplexer". Like the standard
http.ServeMux, mux.Router matches incoming requests against a list of
registered routes and calls a handler for the route that matches the URL
or other conditions. The main features are:

* URL hosts and paths can be defined using named variables with an optional
regexp.

* Registered URLs can be built, or "reversed", which helps maintaining
references to resources.

* Requests can also be matched based on HTTP methods, URL schemes, header and
query values or using custom matchers.

* Routes can be nested, so that they are only tested if the parent route
matches. This allows defining groups of routes that share common conditions
like a host, a path prefix or other repeated attributes. As a bonus, this
optimizes request matching.

* It implements the http.Handler interface so it is compatible with the
standard http.ServeMux.

The most basic example is to register a couple of URL paths and handlers:

	r := new(mux.Router)
	r.HandleFunc("/", HomeHandler)
	r.HandleFunc("/products", ProductsHandler)
	r.HandleFunc("/articles", ArticlesHandler)

Here we register three routes mapping URL paths to handlers. This is
equivalent to how http.HandleFunc() works: if an incoming request URL matches
one of the paths, the corresponding handler is called passing
(http.ResponseWriter, *http.Request) as parameters.

Paths can have variables. They are defined using the format {name} or
{name:pattern}. If a pattern is not defined, the matched variable
will be anything until the next slash. For example:

	r := new(mux.Router)
	r.HandleFunc("/products/{key}", ProductHandler)
	r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)

The names are used to create a map of route variables which can be retrieved
calling mux.Vars():

	vars := mux.Vars(request)
	category := vars["category"]

And this is all you need to know about the basic usage. More advanced options
are explained below.

Routes can also be restricted to a domain or subdomain. Just define a host
pattern to be matched. They can also have variables:

	r := new(mux.Router)
	// Only matches if domain is "www.domain.com".
	r.HandleFunc("/products", ProductsHandler).Host("www.domain.com")
	// Matches a dynamic subdomain.
	r.HandleFunc("/products", ProductsHandler).
	  Host("{subdomain:[a-z]+}.domain.com")

There are several other matchers that can be added. To match HTTP methods:

	r.HandleFunc("/products", ProductsHandler).Methods("GET", "POST")

...or to match a given URL scheme:

	r.HandleFunc("/products", ProductsHandler).Schemes("https")

...or to match specific header values:

	r.HandleFunc("/products", ProductsHandler).
	  Headers("X-Requested-With", "XMLHttpRequest")

...or to match specific URL query values:

	r.HandleFunc("/products", ProductsHandler).Queries("key", "value")

...or to use a custom matcher function:

	r.HandleFunc("/products", ProductsHandler).MatcherFunc(myFunc)

...and finally, it is possible to combine several matchers in a single route:

	r.HandleFunc("/products", ProductsHandler).
	  Host("www.domain.com").
	  Methods("GET").Schemes("http")

Setting the same matching conditions again and again can be boring, so we have
a way to group several routes that share the same requirements.
We call it "subrouting".

For example, let's say we have several URLs that should only match when the
host is "www.domain.com". We create a route for that host, then get a
"subrouter" from that route:

	r := new(mux.Router)
	subrouter := r.Host("www.domain.com").Subrouter()

Then register routes for the subrouter:

	subrouter.HandleFunc("/products/", ProductsHandler)
	subrouter.HandleFunc("/products/{key}", ProductHandler)
	subrouter.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)

The three URL paths we registered above will only be tested if the domain is
"www.domain.com", because the subrouter is tested first. This is not
only convenient, but also optimizes request matching. You can create
subrouters combining any attribute matchers accepted by a route.

Now let's see how to build registered URLs.

Routes can be named. All routes that define a name can have their URLs built,
or "reversed". We define a name calling Name() on a route. For example:

	r := new(mux.Router)
	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
	  Name("article")

To build a URL, get the route and call the URL() method, passing a sequence of
key/value pairs for the route variables. For the previous route, we would do:

	url := r.GetRoute("article").URL("category", "technology", "id", "42")

...and the result will be a url.URL with the following path:

	"/articles/technology/42"

This also works for host variables:

	r := new(mux.Router)
	r.Host("{subdomain}.domain.com").
	  Path("/articles/{category}/{id:[0-9]+}").
	  HandlerFunc(ArticleHandler).
	  Name("article")

	// url.String() will be "http://news.domain.com/articles/technology/42"
	url := r.GetRoute("article").URL("subdomain", "news",
									 "category", "technology",
									 "id", "42")

All variable names defined in the route are required, and their values must
conform to the corresponding patterns, if any.

There's also a way to build only the URL host or path for a route:
use the methods URLHost() or URLPath() instead. For the previous route,
we would do:

	// "http://news.domain.com/"
	host := r.GetRoute("article").URLHost("subdomain", "news").String()

	// "/articles/technology/42"
	path := r.GetRoute("article").URLPath("category", "technology",
										  "id", "42").String()
*/
package mux
<commit_msg>Updated docs.<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package gorilla/mux implements a request router and dispatcher.

The name mux stands for "HTTP request multiplexer". Like the standard
http.ServeMux, mux.Router matches incoming requests against a list of
registered routes and calls a handler for the route that matches the URL
or other conditions. The main features are:

* URL hosts and paths can be defined using named variables with an optional
regexp.

* Registered URLs can be built, or "reversed", which helps maintaining
references to resources.

* Requests can also be matched based on HTTP methods, URL schemes, header and
query values or using custom matchers.

* Routes can be nested, so that they are only tested if the parent route
matches. This allows defining groups of routes that share common conditions
like a host, a path prefix or other repeated attributes. As a bonus, this
optimizes request matching.

* It implements the http.Handler interface so it is compatible with the
standard http.ServeMux.

The most basic example is to register a couple of URL paths and handlers:

	r := new(mux.Router)
	r.HandleFunc("/", HomeHandler)
	r.HandleFunc("/products", ProductsHandler)
	r.HandleFunc("/articles", ArticlesHandler)

Here we register three routes mapping URL paths to handlers. This is
equivalent to how http.HandleFunc() works: if an incoming request URL matches
one of the paths, the corresponding handler is called passing
(http.ResponseWriter, *http.Request) as parameters.

Paths can have variables. They are defined using the format {name} or
{name:pattern}. If a pattern is not defined, the matched variable
will be anything until the next slash. For example:

	r := new(mux.Router)
	r.HandleFunc("/products/{key}", ProductHandler)
	r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)

The names are used to create a map of route variables which can be retrieved
calling mux.Vars():

	vars := mux.Vars(request)
	category := vars["category"]

And this is all you need to know about the basic usage. More advanced options
are explained below.

Routes can also be restricted to a domain or subdomain. Just define a host
pattern to be matched. They can also have variables:

	r := new(mux.Router)
	// Only matches if domain is "www.domain.com".
	r.HandleFunc("/products", ProductsHandler).Host("www.domain.com")
	// Matches a dynamic subdomain.
	r.HandleFunc("/products", ProductsHandler).
	  Host("{subdomain:[a-z]+}.domain.com")

There are several other matchers that can be added. To match HTTP methods:

	r.Methods("GET", "POST")

...or to match a given URL scheme:

	r.Schemes("https")

...or to match specific header values:

	r.Headers("X-Requested-With", "XMLHttpRequest")

...or to match specific URL query values:

	r.Queries("key", "value")

...or to use a custom matcher function:

	r.MatcherFunc(myFunc)

...and finally, it is possible to combine several matchers in a single route:

	r.HandleFunc("/products", ProductsHandler).
	  Host("www.domain.com").
	  Methods("GET").Schemes("http")

Setting the same matching conditions again and again can be boring, so we have
a way to group several routes that share the same requirements.
We call it "subrouting".

For example, let's say we have several URLs that should only match when the
host is "www.domain.com". We create a route for that host, then get a
"subrouter" from that route:

	r := new(mux.Router)
	subrouter := r.Host("www.domain.com").Subrouter()

Then register routes for the subrouter:

	subrouter.HandleFunc("/products/", ProductsHandler)
	subrouter.HandleFunc("/products/{key}", ProductHandler)
	subrouter.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)

The three URL paths we registered above will only be tested if the domain is
"www.domain.com", because the subrouter is tested first. This is not
only convenient, but also optimizes request matching. You can create
subrouters combining any attribute matchers accepted by a route.

Now let's see how to build registered URLs.

Routes can be named. All routes that define a name can have their URLs built,
or "reversed". We define a name calling Name() on a route. For example:

	r := new(mux.Router)
	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
	  Name("article")

To build a URL, get the route and call the URL() method, passing a sequence of
key/value pairs for the route variables. For the previous route, we would do:

	url, err := r.GetRoute("article").URL("category", "technology", "id", "42")

...and the result will be a url.URL with the following path:

	"/articles/technology/42"

This also works for host variables:

	r := new(mux.Router)
	r.Host("{subdomain}.domain.com").
	  Path("/articles/{category}/{id:[0-9]+}").
	  HandlerFunc(ArticleHandler).
	  Name("article")

	// url.String() will be "http://news.domain.com/articles/technology/42"
	url, err := r.GetRoute("article").URL("subdomain", "news",
										  "category", "technology",
										  "id", "42")

All variable names defined in the route are required, and their values must
conform to the corresponding patterns, if any.

There's also a way to build only the URL host or path for a route:
use the methods URLHost() or URLPath() instead. For the previous route,
we would do:

	// "http://news.domain.com/"
	host, err := r.GetRoute("article").URLHost("subdomain", "news").String()

	// "/articles/technology/42"
	path, err := r.GetRoute("article").URLPath("category", "technology",
											   "id", "42").String()
*/
package mux
<|endoftext|>


<commit_before>package lfs

import (
	"github.com/bmizerany/assert"
	"testing"
)

func TestEndpointDefaultsToOrigin(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.lfs_url": "abc"},
		remotes:   []string{},
	}

	assert.Equal(t, "abc", config.Endpoint())
}

func TestEndpointOverridesOrigin(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{
			"lfs.url":               "abc",
			"remote.origin.lfs_url": "def",
		},
		remotes: []string{},
	}

	assert.Equal(t, "abc", config.Endpoint())
}

func TestEndpointNoOverrideDefaultRemote(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{
			"remote.origin.lfs_url": "abc",
			"remote.other.lfs_url":  "def",
		},
		remotes: []string{},
	}

	assert.Equal(t, "abc", config.Endpoint())
}

func TestEndpointUseAlternateRemote(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{
			"remote.origin.lfs_url": "abc",
			"remote.other.lfs_url":  "def",
		},
		remotes: []string{},
	}

	config.CurrentRemote = "other"

	assert.Equal(t, "def", config.Endpoint())
}

func TestEndpointAddsMediaSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "https://example.com/foo/bar"},
		remotes:   []string{},
	}

	assert.Equal(t, "https://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestBareEndpointAddsMediaSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "https://example.com/foo/bar.git"},
		remotes:   []string{},
	}

	assert.Equal(t, "https://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestSSHEndpointAddsMediaSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "git@example.com:foo/bar"},
		remotes:   []string{},
	}

	assert.Equal(t, "https://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestBareSSHEndpointAddsMediaSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "git@example.com:foo/bar.git"},
		remotes:   []string{},
	}

	assert.Equal(t, "https://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestHTTPEndpointAddsMediaSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "http://example.com/foo/bar"},
		remotes:   []string{},
	}

	assert.Equal(t, "http://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestBareHTTPEndpointAddsMediaSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "http://example.com/foo/bar.git"},
		remotes:   []string{},
	}

	assert.Equal(t, "http://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestObjectUrl(t *testing.T) {
	tests := map[string]string{
		"http://example.com":      "http://example.com/objects/oid",
		"http://example.com/":     "http://example.com/objects/oid",
		"http://example.com/foo":  "http://example.com/foo/objects/oid",
		"http://example.com/foo/": "http://example.com/foo/objects/oid",
	}

	for endpoint, expected := range tests {
		Config.SetConfig("lfs.url", endpoint)
		u, err := Config.ObjectUrl("oid")
		if err != nil {
			t.Errorf("Error building URL for %s: %s", endpoint, err)
		} else {
			if actual := u.String(); expected != actual {
				t.Errorf("Expected %s, got %s", expected, u.String())
			}
		}
	}
}

func TestObjectsUrl(t *testing.T) {
	tests := map[string]string{
		"http://example.com":      "http://example.com/objects",
		"http://example.com/":     "http://example.com/objects",
		"http://example.com/foo":  "http://example.com/foo/objects",
		"http://example.com/foo/": "http://example.com/foo/objects",
	}

	for endpoint, expected := range tests {
		Config.SetConfig("lfs.url", endpoint)
		u, err := Config.ObjectUrl("")
		if err != nil {
			t.Errorf("Error building URL for %s: %s", endpoint, err)
		} else {
			if actual := u.String(); expected != actual {
				t.Errorf("Expected %s, got %s", expected, u.String())
			}
		}
	}
}
<commit_msg>rename these test methods<commit_after>package lfs

import (
	"github.com/bmizerany/assert"
	"testing"
)

func TestEndpointDefaultsToOrigin(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.lfs_url": "abc"},
		remotes:   []string{},
	}

	assert.Equal(t, "abc", config.Endpoint())
}

func TestEndpointOverridesOrigin(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{
			"lfs.url":               "abc",
			"remote.origin.lfs_url": "def",
		},
		remotes: []string{},
	}

	assert.Equal(t, "abc", config.Endpoint())
}

func TestEndpointNoOverrideDefaultRemote(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{
			"remote.origin.lfs_url": "abc",
			"remote.other.lfs_url":  "def",
		},
		remotes: []string{},
	}

	assert.Equal(t, "abc", config.Endpoint())
}

func TestEndpointUseAlternateRemote(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{
			"remote.origin.lfs_url": "abc",
			"remote.other.lfs_url":  "def",
		},
		remotes: []string{},
	}

	config.CurrentRemote = "other"

	assert.Equal(t, "def", config.Endpoint())
}

func TestEndpointAddsLfsSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "https://example.com/foo/bar"},
		remotes:   []string{},
	}

	assert.Equal(t, "https://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestBareEndpointAddsLfsSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "https://example.com/foo/bar.git"},
		remotes:   []string{},
	}

	assert.Equal(t, "https://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestSSHEndpointAddsLfsSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "git@example.com:foo/bar"},
		remotes:   []string{},
	}

	assert.Equal(t, "https://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestBareSSHEndpointAddsLfsSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "git@example.com:foo/bar.git"},
		remotes:   []string{},
	}

	assert.Equal(t, "https://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestHTTPEndpointAddsLfsSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "http://example.com/foo/bar"},
		remotes:   []string{},
	}

	assert.Equal(t, "http://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestBareHTTPEndpointAddsLfsSuffix(t *testing.T) {
	config := &Configuration{
		gitConfig: map[string]string{"remote.origin.url": "http://example.com/foo/bar.git"},
		remotes:   []string{},
	}

	assert.Equal(t, "http://example.com/foo/bar.git/info/lfs", config.Endpoint())
}

func TestObjectUrl(t *testing.T) {
	tests := map[string]string{
		"http://example.com":      "http://example.com/objects/oid",
		"http://example.com/":     "http://example.com/objects/oid",
		"http://example.com/foo":  "http://example.com/foo/objects/oid",
		"http://example.com/foo/": "http://example.com/foo/objects/oid",
	}

	for endpoint, expected := range tests {
		Config.SetConfig("lfs.url", endpoint)
		u, err := Config.ObjectUrl("oid")
		if err != nil {
			t.Errorf("Error building URL for %s: %s", endpoint, err)
		} else {
			if actual := u.String(); expected != actual {
				t.Errorf("Expected %s, got %s", expected, u.String())
			}
		}
	}
}

func TestObjectsUrl(t *testing.T) {
	tests := map[string]string{
		"http://example.com":      "http://example.com/objects",
		"http://example.com/":     "http://example.com/objects",
		"http://example.com/foo":  "http://example.com/foo/objects",
		"http://example.com/foo/": "http://example.com/foo/objects",
	}

	for endpoint, expected := range tests {
		Config.SetConfig("lfs.url", endpoint)
		u, err := Config.ObjectUrl("")
		if err != nil {
			t.Errorf("Error building URL for %s: %s", endpoint, err)
		} else {
			if actual := u.String(); expected != actual {
				t.Errorf("Expected %s, got %s", expected, u.String())
			}
		}
	}
}
<|endoftext|>


<commit_before>/***** BEGIN LICENSE BLOCK *****
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# The Initial Developer of the Original Code is the Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2012
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#   Ian Neubert (ian@ianneubert.com)
#
# ***** END LICENSE BLOCK *****/

package sqs

import (
  "encoding/base64"
  "errors"
  "fmt"
  . "github.com/mozilla-services/heka/pipeline"
  "github.com/AdRoll/goamz/sqs"
)

type SqsOutput struct {
  conf         *SqsOutputConfig
  encoder      Encoder
  queue        *sqs.Queue
}

type SqsOutputConfig struct {
  // AWS access key id
  AccessKey string `toml:"access_key"`
  // AWS secret access key
  SecretKey string `toml:"secret_key"`
  // Queue name
  Queue string
  // Encoder to use
  Encoder string
  // AWS Region to connect to
  Region string
}

func (s *SqsOutput) ConfigStruct() interface{} {
  return &SqsOutputConfig{
    Encoder: "ProtobufEncoder",
    Region: "us-east-1",
  }
}

func (s *SqsOutput) Init(config interface{}) (err error) {
  s.conf = config.(*SqsOutputConfig)

  if s.conf.AccessKey == "" {
    return fmt.Errorf("AccessKey must be set")
  }

  if s.conf.SecretKey == "" {
    return fmt.Errorf("SecretKey must be set")
  }

  if s.conf.Queue == "" {
    return fmt.Errorf("Queue must be set")
  }

  // create sqs client
  client, err := sqs.NewFrom(s.conf.AccessKey, s.conf.SecretKey, s.conf.Region)
  if err != nil {
    return fmt.Errorf("Could not create SQS client: %v", err)
  }

  // get the SQS queue
  s.queue, err = client.GetQueue(s.conf.Queue)
  if err != nil {
    return fmt.Errorf("Could not get SQS queue: %v", err)
  }
  return
}

func (s *SqsOutput) Run(or OutputRunner, h PluginHelper) (err error) {
  var (
    pack     *PipelinePack
    outBytes []byte
    inChan chan *PipelinePack = or.InChan()
  )

  s.encoder = or.Encoder()
  if s.encoder == nil {
    return errors.New("Encoder required.")
  }

  for pack = range inChan {
    if outBytes, err = s.encoder.Encode(pack); err != nil {
      or.LogError(fmt.Errorf("Error encoding message: %v", err))
      pack.Recycle()
      continue
    }

    // send the message to the queue
    _, err = s.queue.SendMessage(base64.StdEncoding.EncodeToString(outBytes))
    if err != nil {
      or.LogError(fmt.Errorf("Could not send SQS message: %v", err))
      pack.Recycle()
      continue
    }

    pack.Recycle()
  }
  return
}

func init() {
  RegisterPlugin("SqsOutput", func() interface{} {
    return new(SqsOutput)
  })
}
<commit_msg>Update for Heka 0.10.0<commit_after>/***** BEGIN LICENSE BLOCK *****
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# The Initial Developer of the Original Code is the Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2012
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#   Ian Neubert (ian@ianneubert.com)
#
# ***** END LICENSE BLOCK *****/

package sqs

import (
  "encoding/base64"
  "errors"
  "fmt"
  . "github.com/mozilla-services/heka/pipeline"
  "github.com/AdRoll/goamz/sqs"
)

type SqsOutput struct {
  conf         *SqsOutputConfig
  encoder      Encoder
  queue        *sqs.Queue
}

type SqsOutputConfig struct {
  // AWS access key id
  AccessKey string `toml:"access_key"`
  // AWS secret access key
  SecretKey string `toml:"secret_key"`
  // Queue name
  Queue string
  // Encoder to use
  Encoder string
  // AWS Region to connect to
  Region string
}

func (s *SqsOutput) ConfigStruct() interface{} {
  return &SqsOutputConfig{
    Encoder: "ProtobufEncoder",
    Region: "us-east-1",
  }
}

func (s *SqsOutput) Init(config interface{}) (err error) {
  s.conf = config.(*SqsOutputConfig)

  if s.conf.AccessKey == "" {
    return fmt.Errorf("AccessKey must be set")
  }

  if s.conf.SecretKey == "" {
    return fmt.Errorf("SecretKey must be set")
  }

  if s.conf.Queue == "" {
    return fmt.Errorf("Queue must be set")
  }

  // create sqs client
  client, err := sqs.NewFrom(s.conf.AccessKey, s.conf.SecretKey, s.conf.Region)
  if err != nil {
    return fmt.Errorf("Could not create SQS client: %v", err)
  }

  // get the SQS queue
  s.queue, err = client.GetQueue(s.conf.Queue)
  if err != nil {
    return fmt.Errorf("Could not get SQS queue: %v", err)
  }
  return
}

func (s *SqsOutput) Run(or OutputRunner, h PluginHelper) (err error) {
  var (
    pack     *PipelinePack
    outBytes []byte
    inChan chan *PipelinePack = or.InChan()
  )

  s.encoder = or.Encoder()
  if s.encoder == nil {
    return errors.New("Encoder required.")
  }

  for pack = range inChan {
    if outBytes, err = s.encoder.Encode(pack); err != nil {
      or.LogError(fmt.Errorf("Error encoding message: %v", err))
      pack.Recycle(nil)
      continue
    }

    // send the message to the queue
    _, err = s.queue.SendMessage(base64.StdEncoding.EncodeToString(outBytes))
    if err != nil {
      or.LogError(fmt.Errorf("Could not send SQS message: %v", err))
      pack.Recycle(nil)
      continue
    }

    pack.Recycle(nil)
  }
  return
}

func init() {
  RegisterPlugin("SqsOutput", func() interface{} {
    return new(SqsOutput)
  })
}
<|endoftext|>


<commit_before>// Copyright 2015 Mitchell Kember. Subject to the MIT License.

// Package system implements SVG rendering of Lindenmayer systems
package system

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
	"os"
	"unicode"
)

// A rewriteSet is a set of rules for replacing variables with sequences.
type rewriteSet map[byte][]byte

// A System is a representation of a Lindenmayer system (L-system).
type System struct {
	axiom []byte     // Initial state of the system.
	rules rewriteSet // Rules for rewriting variables.
	angle float64    // Turn angle, in radians.
	start float64    // Initial direction, in radians (standard position).
	turn  bool       // Turn initial direction (used for dragon).
	base  float64    // Base b in y ~ b^x where y is size and x is depth.
	min   int        // Number of initial depths to skip.
	max   int        // Maximum depth of recursion.
}

// cacheRender is like render but caches results to disk for better performance.
func (s *System) cacheRender(depth int) [][]vector {
	name := s.name()
	if name == "" {
		return s.render(depth)
	}

	filename := fmt.Sprintf("/app/cache/%s-%d.gob", name, depth)
	_, err := os.Stat(filename)
	if err == nil {
		log.Println("Cache hit:", filename)
		file, err := os.Open(filename)
		if err != nil {
			log.Println("File open error:", err)
			return s.render(depth)
		}
		defer file.Close()

		var segments [][]vector
		err = gob.NewDecoder(file).Decode(&segments)
		if err != nil {
			log.Println("Gob decode error:", err)
			return s.render(depth)
		}
		return segments
	}
	if os.IsNotExist(err) {
		log.Println("Cache miss:", filename)
		segments := s.render(depth)
		file, err := os.Create(filename)
		if err != nil {
			log.Println("File create error:", err)
			return segments
		}
		defer file.Close()

		gob.NewEncoder(file).Encode(segments)
		return segments
	}

	log.Println("File stat error:", err)
	return s.render(depth)
}

// render draws the curve for the system at the given depth of recursion. It
// returns a list of polygonal lines as a 2D slice of points.
func (s *System) render(depth int) [][]vector {
	var buf bytes.Buffer
	s.expand(s.axiom, depth, &buf)
	return s.execute(buf.Bytes(), depth)
}

// expand recursively expands seq using the system's rules, stopping when the
// level reaches zero. It writes the results into buf.
func (s *System) expand(seq []byte, level int, buf *bytes.Buffer) {
	if level == 0 {
		buf.Write(seq)
		return
	}

	for _, sym := range seq {
		if replacement, ok := s.rules[sym]; ok {
			s.expand(replacement, level-1, buf)
		} else {
			buf.WriteByte(sym)
		}
	}
}

// execute performs the instructions in seq, ignoring symbols with no special
// meaning. It returns a list of polygonal lines, each one being a sequence of
// points that the were visited.
func (s *System) execute(seq []byte, depth int) [][]vector {
	var segments [][]vector
	var stack []turtle
	turt := s.initialTurtle(depth)
	points := []vector{turt.pos}

	for _, sym := range seq {
		if unicode.IsUpper(rune(sym)) {
			turt.advance()
			points = append(points, turt.pos)
			continue
		}
		switch sym {
		case '+':
			turt.turnCCW()
		case '-':
			turt.turnCW()
		case '[':
			stack = append(stack, turt)
		case ']':
			last := len(stack) - 1
			turt = stack[last]
			stack = stack[:last]
			if len(points) > 0 {
				segments = append(segments, points)
			}
			points = []vector{turt.pos}
		}
	}

	if len(points) > 0 {
		segments = append(segments, points)
	}
	return segments
}
<commit_msg>Use relative path for cache so it works locally and on Heroku<commit_after>// Copyright 2015 Mitchell Kember. Subject to the MIT License.

// Package system implements SVG rendering of Lindenmayer systems
package system

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"log"
	"os"
	"unicode"
)

// A rewriteSet is a set of rules for replacing variables with sequences.
type rewriteSet map[byte][]byte

// A System is a representation of a Lindenmayer system (L-system).
type System struct {
	axiom []byte     // Initial state of the system.
	rules rewriteSet // Rules for rewriting variables.
	angle float64    // Turn angle, in radians.
	start float64    // Initial direction, in radians (standard position).
	turn  bool       // Turn initial direction (used for dragon).
	base  float64    // Base b in y ~ b^x where y is size and x is depth.
	min   int        // Number of initial depths to skip.
	max   int        // Maximum depth of recursion.
}

// cacheRender is like render but caches results to disk for better performance.
func (s *System) cacheRender(depth int) [][]vector {
	name := s.name()
	if name == "" {
		return s.render(depth)
	}

	filename := fmt.Sprintf("cache/%s-%d.gob", name, depth)
	_, err := os.Stat(filename)
	if err == nil {
		log.Println("Cache hit:", filename)
		file, err := os.Open(filename)
		if err != nil {
			log.Println("File open error:", err)
			return s.render(depth)
		}
		defer file.Close()

		var segments [][]vector
		err = gob.NewDecoder(file).Decode(&segments)
		if err != nil {
			log.Println("Gob decode error:", err)
			return s.render(depth)
		}
		return segments
	}
	if os.IsNotExist(err) {
		log.Println("Cache miss:", filename)
		segments := s.render(depth)
		file, err := os.Create(filename)
		if err != nil {
			log.Println("File create error:", err)
			return segments
		}
		defer file.Close()

		gob.NewEncoder(file).Encode(segments)
		return segments
	}

	log.Println("File stat error:", err)
	return s.render(depth)
}

// render draws the curve for the system at the given depth of recursion. It
// returns a list of polygonal lines as a 2D slice of points.
func (s *System) render(depth int) [][]vector {
	var buf bytes.Buffer
	s.expand(s.axiom, depth, &buf)
	return s.execute(buf.Bytes(), depth)
}

// expand recursively expands seq using the system's rules, stopping when the
// level reaches zero. It writes the results into buf.
func (s *System) expand(seq []byte, level int, buf *bytes.Buffer) {
	if level == 0 {
		buf.Write(seq)
		return
	}

	for _, sym := range seq {
		if replacement, ok := s.rules[sym]; ok {
			s.expand(replacement, level-1, buf)
		} else {
			buf.WriteByte(sym)
		}
	}
}

// execute performs the instructions in seq, ignoring symbols with no special
// meaning. It returns a list of polygonal lines, each one being a sequence of
// points that the were visited.
func (s *System) execute(seq []byte, depth int) [][]vector {
	var segments [][]vector
	var stack []turtle
	turt := s.initialTurtle(depth)
	points := []vector{turt.pos}

	for _, sym := range seq {
		if unicode.IsUpper(rune(sym)) {
			turt.advance()
			points = append(points, turt.pos)
			continue
		}
		switch sym {
		case '+':
			turt.turnCCW()
		case '-':
			turt.turnCW()
		case '[':
			stack = append(stack, turt)
		case ']':
			last := len(stack) - 1
			turt = stack[last]
			stack = stack[:last]
			if len(points) > 0 {
				segments = append(segments, points)
			}
			points = []vector{turt.pos}
		}
	}

	if len(points) > 0 {
		segments = append(segments, points)
	}
	return segments
}
<|endoftext|>


<commit_before>// Copyright 2016, RadiantBlue Technologies, 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 piazza

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

const DefaultElasticsearchAddress = "localhost:9200"
const DefaultDomain = ".stage.geointservices.io"
const DefaultProtocol = "http"

type ServiceName string

const (
	PzDiscover      ServiceName = "pz-discover"
	PzElasticSearch ServiceName = "pz-elasticsearch"
	PzGateway       ServiceName = "pz-gateway"
	PzGoCommon      ServiceName = "PZ-GOCOMMON" // not a real service, just for testing
	PzLogger        ServiceName = "pz-logger"
	PzUuidgen       ServiceName = "pz-uuidgen"
	PzWorkflow      ServiceName = "pz-workflow"
)

var EndpointPrefixes = map[ServiceName]string{
	PzDiscover:      "",
	PzElasticSearch: "",
	PzGateway:       "",
	PzLogger:        "/v1",
	PzUuidgen:       "/v1",
	PzWorkflow:      "/v1",
}

var HealthcheckEndpoints = map[ServiceName]string{
	PzDiscover:      "",
	PzElasticSearch: "",
	PzGateway:       "/health",
	PzLogger:        "/",
	PzUuidgen:       "/",
	PzWorkflow:      "/",
}

type ServicesMap map[ServiceName]string

type SystemConfig struct {
	// our own service
	Name    ServiceName
	Address string
	BindTo  string

	// our external services
	endpoints ServicesMap

	vcapApplication *VcapApplication
	vcapServices    *VcapServices
	domain          string
}

func NewSystemConfig(serviceName ServiceName,
	requiredServices []ServiceName) (*SystemConfig, error) {

	var err error

	sys := &SystemConfig{endpoints: make(ServicesMap)}

	sys.vcapApplication, err = NewVcapApplication()
	if err != nil {
		return nil, err
	}

	sys.vcapServices, err = NewVcapServices()
	if err != nil {
		return nil, err
	}

	if sys.vcapApplication != nil {
		sys.domain = sys.vcapApplication.GetDomain()
	} else {
		sys.domain = DefaultDomain
	}

	// set some data about our own service first
	sys.Name = serviceName
	sys.Address = sys.vcapApplication.GetAddress()
	sys.BindTo = sys.vcapApplication.GetBindToPort()

	// set the services table with the services we require,
	// using VcapServices to get the addresses
	err = sys.checkRequirements(requiredServices)
	if err != nil {
		return nil, err
	}

	err = sys.runHealthChecks()
	if err != nil {
		return nil, err
	}

	return sys, nil
}

func (sys *SystemConfig) checkRequirements(requirements []ServiceName) error {

	for _, name := range requirements {

		if name == sys.Name {
			log.Printf("check requirements for %s: case 1", name)
			sys.AddService(name, sys.Address)

		} else {
			if addr, ok := sys.vcapServices.Services[name]; !ok {
				// the service we want is not in VCAP, so fake it
				log.Printf("check requirements for %s: case 2", name)
				sys.AddService(name, string(name)+DefaultDomain)

			} else {
				// the service we want is in VCAP, with a full and valid address
				log.Printf("check requirements for %s: case 3", name)
				sys.AddService(name, addr)
			}
		}

		newaddr, err := sys.GetAddress(name)
		if err != nil {
			return err
		}
		log.Printf("Required service %s: %s", name, newaddr)
	}

	return nil
}

func (sys *SystemConfig) runHealthChecks() error {
	//log.Printf("SystemConfig.runHealthChecks: start")

	for name, addr := range sys.endpoints {
		if name != sys.Name {
			url := fmt.Sprintf("%s://%s%s", DefaultProtocol, addr, HealthcheckEndpoints[name])

			//log.Printf("Service healthy? %s at %s (%s)", name, addr, url)

			resp, err := http.Get(url)
			if err != nil {
				return NewErrorf("Health check errored for service: %s at %s <%#v>", name, url, resp)
			}

			if resp.StatusCode != http.StatusOK {
				return NewErrorf("Health check failed for service: %s at %s <%#v>", name, url, resp)
			}

			log.Printf("Service healthy: %s at %s", name, url)
			/*body, err := ReadFrom(resp.Body)
			if err != nil {
				return err
			}
			log.Printf(">>> %s <<<", string(body))*/
		}
	}

	//log.Printf("SystemConfig.runHealthChecks: end")
	return nil
}

// it is explicitly allowed for outsiders to update an existing service, but we'll log it just to be safe
func (sys *SystemConfig) AddService(name ServiceName, address string) {
	old, ok := sys.endpoints[name]
	sys.endpoints[name] = address
	if ok {
		log.Printf("SystemConfig.AddService: updated %s from %s to %s", name, old, address)
	}
}

func (sys *SystemConfig) GetAddress(name ServiceName) (string, error) {
	addr, ok := sys.endpoints[name]
	if !ok {
		return "", NewErrorf("Unknown service: %s", name)
	}

	return addr, nil
}

func (sys *SystemConfig) GetURL(name ServiceName) (string, error) {
	addr, err := sys.GetAddress(name)
	if err != nil {
		return "", err
	}

	url := fmt.Sprintf("%s://%s%s", DefaultProtocol, addr, EndpointPrefixes[name])

	return url, nil
}

func (sys *SystemConfig) GetDomain() string {
	return sys.domain
}

func (sys *SystemConfig) WaitForService(name ServiceName) error {
	addr, err := sys.GetAddress(name)
	if err != nil {
		return err
	}

	err = sys.WaitForServiceByAddress(name, addr)
	if err != nil {
		return err
	}

	return nil
}

func (sys *SystemConfig) WaitForServiceByAddress(name ServiceName, address string) error {
	url := fmt.Sprintf("%s://%s", DefaultProtocol, address)

	msTime := 0

	for {
		resp, err := http.Get(url)
		if err == nil && resp.StatusCode == http.StatusOK {
			//log.Printf("found service %s", name)
			return nil
		}
		if msTime >= waitTimeout {
			return fmt.Errorf("timed out waiting for service: %s at %s", name, url)
		}
		time.Sleep(waitSleep * time.Millisecond)
		msTime += waitSleep
	}
	/* notreached */
}

/*
func IsLocalConfig() bool {
	localFlag := flag.Bool("local", false, "use localhost ports")
	flag.Parse()
	return *localFlag
}
*/
<commit_msg>remove logging<commit_after>// Copyright 2016, RadiantBlue Technologies, 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 piazza

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

const DefaultElasticsearchAddress = "localhost:9200"
const DefaultDomain = ".stage.geointservices.io"
const DefaultProtocol = "http"

type ServiceName string

const (
	PzDiscover      ServiceName = "pz-discover"
	PzElasticSearch ServiceName = "pz-elasticsearch"
	PzGateway       ServiceName = "pz-gateway"
	PzGoCommon      ServiceName = "PZ-GOCOMMON" // not a real service, just for testing
	PzLogger        ServiceName = "pz-logger"
	PzUuidgen       ServiceName = "pz-uuidgen"
	PzWorkflow      ServiceName = "pz-workflow"
)

var EndpointPrefixes = map[ServiceName]string{
	PzDiscover:      "",
	PzElasticSearch: "",
	PzGateway:       "",
	PzLogger:        "/v1",
	PzUuidgen:       "/v1",
	PzWorkflow:      "/v1",
}

var HealthcheckEndpoints = map[ServiceName]string{
	PzDiscover:      "",
	PzElasticSearch: "",
	PzGateway:       "/health",
	PzLogger:        "/",
	PzUuidgen:       "/",
	PzWorkflow:      "/",
}

type ServicesMap map[ServiceName]string

type SystemConfig struct {
	// our own service
	Name    ServiceName
	Address string
	BindTo  string

	// our external services
	endpoints ServicesMap

	vcapApplication *VcapApplication
	vcapServices    *VcapServices
	domain          string
}

func NewSystemConfig(serviceName ServiceName,
	requiredServices []ServiceName) (*SystemConfig, error) {

	var err error

	sys := &SystemConfig{endpoints: make(ServicesMap)}

	sys.vcapApplication, err = NewVcapApplication()
	if err != nil {
		return nil, err
	}

	sys.vcapServices, err = NewVcapServices()
	if err != nil {
		return nil, err
	}

	if sys.vcapApplication != nil {
		sys.domain = sys.vcapApplication.GetDomain()
	} else {
		sys.domain = DefaultDomain
	}

	// set some data about our own service first
	sys.Name = serviceName
	sys.Address = sys.vcapApplication.GetAddress()
	sys.BindTo = sys.vcapApplication.GetBindToPort()

	// set the services table with the services we require,
	// using VcapServices to get the addresses
	err = sys.checkRequirements(requiredServices)
	if err != nil {
		return nil, err
	}

	err = sys.runHealthChecks()
	if err != nil {
		return nil, err
	}

	return sys, nil
}

func (sys *SystemConfig) checkRequirements(requirements []ServiceName) error {

	for _, name := range requirements {

		if name == sys.Name {
			//log.Printf("check requirements for %s: case 1", name)
			sys.AddService(name, sys.Address)

		} else {
			if addr, ok := sys.vcapServices.Services[name]; !ok {
				// the service we want is not in VCAP, so fake it
				//log.Printf("check requirements for %s: case 2", name)
				sys.AddService(name, string(name)+DefaultDomain)

			} else {
				// the service we want is in VCAP, with a full and valid address
				//log.Printf("check requirements for %s: case 3", name)
				sys.AddService(name, addr)
			}
		}

		newaddr, err := sys.GetAddress(name)
		if err != nil {
			return err
		}
		log.Printf("Required service: %s at %s", name, newaddr)
	}

	return nil
}

func (sys *SystemConfig) runHealthChecks() error {
	//log.Printf("SystemConfig.runHealthChecks: start")

	for name, addr := range sys.endpoints {
		if name != sys.Name {
			url := fmt.Sprintf("%s://%s%s", DefaultProtocol, addr, HealthcheckEndpoints[name])

			//log.Printf("Service healthy? %s at %s (%s)", name, addr, url)

			resp, err := http.Get(url)
			if err != nil {
				return NewErrorf("Health check errored for service: %s at %s <%#v>", name, url, resp)
			}

			if resp.StatusCode != http.StatusOK {
				return NewErrorf("Health check failed for service: %s at %s <%#v>", name, url, resp)
			}

			log.Printf("Service healthy: %s at %s", name, url)
			/*body, err := ReadFrom(resp.Body)
			if err != nil {
				return err
			}
			log.Printf(">>> %s <<<", string(body))*/
		}
	}

	//log.Printf("SystemConfig.runHealthChecks: end")
	return nil
}

// it is explicitly allowed for outsiders to update an existing service, but we'll log it just to be safe
func (sys *SystemConfig) AddService(name ServiceName, address string) {
	old, ok := sys.endpoints[name]
	sys.endpoints[name] = address
	if ok {
		log.Printf("SystemConfig.AddService: updated %s from %s to %s", name, old, address)
	}
}

func (sys *SystemConfig) GetAddress(name ServiceName) (string, error) {
	addr, ok := sys.endpoints[name]
	if !ok {
		return "", NewErrorf("Unknown service: %s", name)
	}

	return addr, nil
}

func (sys *SystemConfig) GetURL(name ServiceName) (string, error) {
	addr, err := sys.GetAddress(name)
	if err != nil {
		return "", err
	}

	url := fmt.Sprintf("%s://%s%s", DefaultProtocol, addr, EndpointPrefixes[name])

	return url, nil
}

func (sys *SystemConfig) GetDomain() string {
	return sys.domain
}

func (sys *SystemConfig) WaitForService(name ServiceName) error {
	addr, err := sys.GetAddress(name)
	if err != nil {
		return err
	}

	err = sys.WaitForServiceByAddress(name, addr)
	if err != nil {
		return err
	}

	return nil
}

func (sys *SystemConfig) WaitForServiceByAddress(name ServiceName, address string) error {
	url := fmt.Sprintf("%s://%s", DefaultProtocol, address)

	msTime := 0

	for {
		resp, err := http.Get(url)
		if err == nil && resp.StatusCode == http.StatusOK {
			//log.Printf("found service %s", name)
			return nil
		}
		if msTime >= waitTimeout {
			return fmt.Errorf("timed out waiting for service: %s at %s", name, url)
		}
		time.Sleep(waitSleep * time.Millisecond)
		msTime += waitSleep
	}
	/* notreached */
}

/*
func IsLocalConfig() bool {
	localFlag := flag.Bool("local", false, "use localhost ports")
	flag.Parse()
	return *localFlag
}
*/
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 web

import "github.com/zenoss/go-json-rest"

//getRoutes returns all registered rest routes
func (sc *ServiceConfig) getRoutes() []rest.Route {

	gz := gzipHandler

	routes := []rest.Route{
		rest.Route{"GET", "/", gz(mainPage)},

		// Backups
		rest.Route{"GET", "/backup/create", gz(sc.authorizedClient(RestBackupCreate))},
		rest.Route{"GET", "/backup/restore", gz(sc.authorizedClient(RestBackupRestore))},
		rest.Route{"GET", "/backup/list", gz(sc.authorizedClient(RestBackupFileList))},
		rest.Route{"GET", "/backup/status", gz(sc.authorizedClient(RestBackupStatus))},
		rest.Route{"GET", "/backup/restore/status", gz(sc.authorizedClient(RestRestoreStatus))},

		// Hosts
		rest.Route{"GET", "/hosts", gz(sc.checkAuth(restGetHosts))},
		rest.Route{"GET", "/hosts/running", gz(sc.checkAuth(restGetActiveHostIDs))},
		rest.Route{"GET", "/hosts/defaultHostAlias", gz(sc.checkAuth(restGetDefaultHostAlias))},
		rest.Route{"GET", "/hosts/:hostId", gz(sc.checkAuth(restGetHost))},
		rest.Route{"POST", "/hosts/add", gz(sc.checkAuth(restAddHost))},
		rest.Route{"DELETE", "/hosts/:hostId", gz(sc.checkAuth(restRemoveHost))},
		rest.Route{"PUT", "/hosts/:hostId", gz(sc.checkAuth(restUpdateHost))},
		rest.Route{"GET", "/hosts/:hostId/running", gz(sc.authorizedClient(restGetRunningForHost))},
		rest.Route{"DELETE", "/hosts/:hostId/:serviceStateId", gz(sc.authorizedClient(restKillRunning))},
		rest.Route{"GET", "/hosts/:hostId/instances", gz(sc.checkAuth(restGetHostInstances))},

		// Pools
		rest.Route{"GET", "/pools/:poolId", gz(sc.checkAuth(restGetPool))},
		rest.Route{"DELETE", "/pools/:poolId", gz(sc.checkAuth(restRemovePool))},
		rest.Route{"PUT", "/pools/:poolId", gz(sc.checkAuth(restUpdatePool))},
		rest.Route{"POST", "/pools/add", gz(sc.checkAuth(restAddPool))},
		rest.Route{"GET", "/pools", gz(sc.checkAuth(restGetPools))},
		rest.Route{"GET", "/pools/:poolId/hosts", gz(sc.checkAuth(restGetHostsForResourcePool))},

		// Pools (VirtualIP)
		rest.Route{"PUT", "/pools/:poolId/virtualip", gz(sc.checkAuth(restAddPoolVirtualIP))},
		rest.Route{"DELETE", "/pools/:poolId/virtualip/*ip", gz(sc.checkAuth(restRemovePoolVirtualIP))},

		// Pools (IPs)
		rest.Route{"GET", "/pools/:poolId/ips", gz(sc.checkAuth(restGetPoolIps))},

		// Services (Apps)
		rest.Route{"GET", "/services", gz(sc.authorizedClient(restGetAllServices))},
		rest.Route{"GET", "/servicehealth", gz(sc.authorizedClient(restGetServicesHealth))},
		rest.Route{"GET", "/services/:serviceId", gz(sc.authorizedClient(restGetService))},
		rest.Route{"GET", "/services/:serviceId/running", gz(sc.authorizedClient(restGetRunningForService))},
		rest.Route{"GET", "/services/:serviceId/status", gz(sc.authorizedClient(restGetStatusForService))},
		rest.Route{"GET", "/services/:serviceId/running/:serviceStateId", gz(sc.authorizedClient(restGetRunningService))},
		rest.Route{"GET", "/services/:serviceId/:serviceStateId/logs", gz(sc.authorizedClient(restGetServiceStateLogs))},
		rest.Route{"GET", "/services/:serviceId/:serviceStateId/logs/download", gz(sc.authorizedClient(downloadServiceStateLogs))},
		rest.Route{"POST", "/services/add", gz(sc.authorizedClient(restAddService))},
		rest.Route{"POST", "/services/deploy", gz(sc.authorizedClient(restDeployService))},
		rest.Route{"DELETE", "/services/:serviceId", gz(sc.authorizedClient(restRemoveService))},
		rest.Route{"GET", "/services/:serviceId/logs", gz(sc.authorizedClient(restGetServiceLogs))},
		rest.Route{"PUT", "/services/:serviceId", gz(sc.authorizedClient(restUpdateService))},
		rest.Route{"GET", "/services/:serviceId/snapshot", gz(sc.authorizedClient(restSnapshotService))},
		rest.Route{"PUT", "/services/:serviceId/restartService", gz(sc.authorizedClient(restRestartService))},
		rest.Route{"PUT", "/services/:serviceId/startService", gz(sc.authorizedClient(restStartService))},
		rest.Route{"PUT", "/services/:serviceId/stopService", gz(sc.authorizedClient(restStopService))},
		rest.Route{"POST", "/services/:serviceId/migrate", sc.authorizedClient(restPostServicesForMigration)},
		rest.Route{"GET", "/hosts/:serviceId/instances", gz(sc.checkAuth(restGetServiceInstances))},

		// Services (Virtual Host)
		rest.Route{"GET", "/services/vhosts", gz(sc.authorizedClient(restGetVirtualHosts))},
		rest.Route{"PUT", "/services/:serviceId/endpoint/:application/vhosts/*name", gz(sc.checkAuth(restAddVirtualHost))},
		rest.Route{"DELETE", "/services/:serviceId/endpoint/:application/vhosts/*name", gz(sc.checkAuth(restRemoveVirtualHost))},
		rest.Route{"POST", "/services/:serviceId/endpoint/:application/vhosts/*name", gz(sc.checkAuth(restVirtualHostEnable))},

		// Services (Endpoint Ports)
		rest.Route{"PUT", "/services/:serviceId/endpoint/:application/ports/*portname", gz(sc.checkAuth(restAddPort))},
		rest.Route{"DELETE", "/services/:serviceId/endpoint/:application/ports/*portname", gz(sc.checkAuth(restRemovePort))},
		rest.Route{"POST", "/services/:serviceId/endpoint/:application/ports/*portname", gz(sc.checkAuth(restPortEnable))},

		// Services (IP)
		rest.Route{"PUT", "/services/:serviceId/ip", gz(sc.authorizedClient(restServiceAutomaticAssignIP))},
		rest.Route{"PUT", "/services/:serviceId/ip/*ip", gz(sc.authorizedClient(restServiceManualAssignIP))},

		// Service templates (App templates)
		rest.Route{"GET", "/templates", gz(sc.checkAuth(restGetAppTemplates))},
		rest.Route{"POST", "/templates/add", gz(sc.checkAuth(restAddAppTemplate))},
		rest.Route{"DELETE", "/templates/:templateId", gz(sc.checkAuth(restRemoveAppTemplate))},
		rest.Route{"POST", "/templates/deploy", gz(sc.checkAuth(restDeployAppTemplate))},
		rest.Route{"POST", "/templates/deploy/status", gz(sc.checkAuth(restDeployAppTemplateStatus))},
		rest.Route{"GET", "/templates/deploy/active", gz(sc.checkAuth(restDeployAppTemplateActive))},

		// Login
		rest.Route{"POST", "/login", gz(sc.unAuthorizedClient(restLogin))},
		rest.Route{"DELETE", "/login", gz(restLogout)},

		// "Misc" stuff
		rest.Route{"GET", "/top/services", gz(sc.authorizedClient(restGetTopServices))},
		rest.Route{"GET", "/running", gz(sc.authorizedClient(restGetAllRunning))},
		rest.Route{"GET", "/config", gz(sc.authorizedClient(restGetUIConfig))},
		rest.Route{"GET", "/servicestatus", gz(sc.authorizedClient(restGetConciseServiceStatus))},

		// Generic static data
		rest.Route{"GET", "/favicon.ico", gz(favIcon)},
		rest.Route{"GET", "/static/*resource", gz(staticData)},
		rest.Route{"GET", "/licenses.html", gz(licenses)},

		// Info about serviced itself
		rest.Route{"GET", "/dockerIsLoggedIn", gz(sc.authorizedClient(restDockerIsLoggedIn))},
		rest.Route{"GET", "/stats", gz(sc.isCollectingStats())},
		rest.Route{"GET", "/version", gz(sc.authorizedClient(restGetServicedVersion))},
		rest.Route{"GET", "/storage", gz(sc.authorizedClient(restGetStorage))},
	}

	// Hardcoding these target URLs for now.
	// TODO: When internal services are allowed to run on other hosts, look that up.
	// All API calls require authentication
	routes = routeToInternalServiceProxy("/api/controlplane/elastic", "http://127.0.0.1:9100/", true, routes)
	routes = routeToInternalServiceProxy("/metrics/api", "http://127.0.0.1:8888/api", true, routes)
	routes = routeToInternalServiceProxy("/api/controlplane/kibana", "http://127.0.0.1:5601", true, routes)

	// Allow static assets for metrics data to be loaded without authentication since they are
	// included in index.html by default.
	routes = routeToInternalServiceProxy("/metrics/static", "http://127.0.0.1:8888/static", false, routes)

	return routes
}
<commit_msg>commented out new and unused web routes<commit_after>// Copyright 2014 The Serviced 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 web

import "github.com/zenoss/go-json-rest"

//getRoutes returns all registered rest routes
func (sc *ServiceConfig) getRoutes() []rest.Route {

	gz := gzipHandler

	routes := []rest.Route{
		rest.Route{"GET", "/", gz(mainPage)},

		// Backups
		rest.Route{"GET", "/backup/create", gz(sc.authorizedClient(RestBackupCreate))},
		rest.Route{"GET", "/backup/restore", gz(sc.authorizedClient(RestBackupRestore))},
		rest.Route{"GET", "/backup/list", gz(sc.authorizedClient(RestBackupFileList))},
		rest.Route{"GET", "/backup/status", gz(sc.authorizedClient(RestBackupStatus))},
		rest.Route{"GET", "/backup/restore/status", gz(sc.authorizedClient(RestRestoreStatus))},

		// Hosts
		rest.Route{"GET", "/hosts", gz(sc.checkAuth(restGetHosts))},
		rest.Route{"GET", "/hosts/running", gz(sc.checkAuth(restGetActiveHostIDs))},
		rest.Route{"GET", "/hosts/defaultHostAlias", gz(sc.checkAuth(restGetDefaultHostAlias))},
		rest.Route{"GET", "/hosts/:hostId", gz(sc.checkAuth(restGetHost))},
		rest.Route{"POST", "/hosts/add", gz(sc.checkAuth(restAddHost))},
		rest.Route{"DELETE", "/hosts/:hostId", gz(sc.checkAuth(restRemoveHost))},
		rest.Route{"PUT", "/hosts/:hostId", gz(sc.checkAuth(restUpdateHost))},
		rest.Route{"GET", "/hosts/:hostId/running", gz(sc.authorizedClient(restGetRunningForHost))},
		rest.Route{"DELETE", "/hosts/:hostId/:serviceStateId", gz(sc.authorizedClient(restKillRunning))},
		// rest.Route{"GET", "/hosts/:hostId/instances", gz(sc.checkAuth(restGetHostInstances))},

		// Pools
		rest.Route{"GET", "/pools/:poolId", gz(sc.checkAuth(restGetPool))},
		rest.Route{"DELETE", "/pools/:poolId", gz(sc.checkAuth(restRemovePool))},
		rest.Route{"PUT", "/pools/:poolId", gz(sc.checkAuth(restUpdatePool))},
		rest.Route{"POST", "/pools/add", gz(sc.checkAuth(restAddPool))},
		rest.Route{"GET", "/pools", gz(sc.checkAuth(restGetPools))},
		rest.Route{"GET", "/pools/:poolId/hosts", gz(sc.checkAuth(restGetHostsForResourcePool))},

		// Pools (VirtualIP)
		rest.Route{"PUT", "/pools/:poolId/virtualip", gz(sc.checkAuth(restAddPoolVirtualIP))},
		rest.Route{"DELETE", "/pools/:poolId/virtualip/*ip", gz(sc.checkAuth(restRemovePoolVirtualIP))},

		// Pools (IPs)
		rest.Route{"GET", "/pools/:poolId/ips", gz(sc.checkAuth(restGetPoolIps))},

		// Services (Apps)
		rest.Route{"GET", "/services", gz(sc.authorizedClient(restGetAllServices))},
		rest.Route{"GET", "/servicehealth", gz(sc.authorizedClient(restGetServicesHealth))},
		rest.Route{"GET", "/services/:serviceId", gz(sc.authorizedClient(restGetService))},
		rest.Route{"GET", "/services/:serviceId/running", gz(sc.authorizedClient(restGetRunningForService))},
		rest.Route{"GET", "/services/:serviceId/status", gz(sc.authorizedClient(restGetStatusForService))},
		rest.Route{"GET", "/services/:serviceId/running/:serviceStateId", gz(sc.authorizedClient(restGetRunningService))},
		rest.Route{"GET", "/services/:serviceId/:serviceStateId/logs", gz(sc.authorizedClient(restGetServiceStateLogs))},
		rest.Route{"GET", "/services/:serviceId/:serviceStateId/logs/download", gz(sc.authorizedClient(downloadServiceStateLogs))},
		rest.Route{"POST", "/services/add", gz(sc.authorizedClient(restAddService))},
		rest.Route{"POST", "/services/deploy", gz(sc.authorizedClient(restDeployService))},
		rest.Route{"DELETE", "/services/:serviceId", gz(sc.authorizedClient(restRemoveService))},
		rest.Route{"GET", "/services/:serviceId/logs", gz(sc.authorizedClient(restGetServiceLogs))},
		rest.Route{"PUT", "/services/:serviceId", gz(sc.authorizedClient(restUpdateService))},
		rest.Route{"GET", "/services/:serviceId/snapshot", gz(sc.authorizedClient(restSnapshotService))},
		rest.Route{"PUT", "/services/:serviceId/restartService", gz(sc.authorizedClient(restRestartService))},
		rest.Route{"PUT", "/services/:serviceId/startService", gz(sc.authorizedClient(restStartService))},
		rest.Route{"PUT", "/services/:serviceId/stopService", gz(sc.authorizedClient(restStopService))},
		rest.Route{"POST", "/services/:serviceId/migrate", sc.authorizedClient(restPostServicesForMigration)},
		// rest.Route{"GET", "/hosts/:serviceId/instances", gz(sc.checkAuth(restGetServiceInstances))},

		// Services (Virtual Host)
		rest.Route{"GET", "/services/vhosts", gz(sc.authorizedClient(restGetVirtualHosts))},
		rest.Route{"PUT", "/services/:serviceId/endpoint/:application/vhosts/*name", gz(sc.checkAuth(restAddVirtualHost))},
		rest.Route{"DELETE", "/services/:serviceId/endpoint/:application/vhosts/*name", gz(sc.checkAuth(restRemoveVirtualHost))},
		rest.Route{"POST", "/services/:serviceId/endpoint/:application/vhosts/*name", gz(sc.checkAuth(restVirtualHostEnable))},

		// Services (Endpoint Ports)
		rest.Route{"PUT", "/services/:serviceId/endpoint/:application/ports/*portname", gz(sc.checkAuth(restAddPort))},
		rest.Route{"DELETE", "/services/:serviceId/endpoint/:application/ports/*portname", gz(sc.checkAuth(restRemovePort))},
		rest.Route{"POST", "/services/:serviceId/endpoint/:application/ports/*portname", gz(sc.checkAuth(restPortEnable))},

		// Services (IP)
		rest.Route{"PUT", "/services/:serviceId/ip", gz(sc.authorizedClient(restServiceAutomaticAssignIP))},
		rest.Route{"PUT", "/services/:serviceId/ip/*ip", gz(sc.authorizedClient(restServiceManualAssignIP))},

		// Service templates (App templates)
		rest.Route{"GET", "/templates", gz(sc.checkAuth(restGetAppTemplates))},
		rest.Route{"POST", "/templates/add", gz(sc.checkAuth(restAddAppTemplate))},
		rest.Route{"DELETE", "/templates/:templateId", gz(sc.checkAuth(restRemoveAppTemplate))},
		rest.Route{"POST", "/templates/deploy", gz(sc.checkAuth(restDeployAppTemplate))},
		rest.Route{"POST", "/templates/deploy/status", gz(sc.checkAuth(restDeployAppTemplateStatus))},
		rest.Route{"GET", "/templates/deploy/active", gz(sc.checkAuth(restDeployAppTemplateActive))},

		// Login
		rest.Route{"POST", "/login", gz(sc.unAuthorizedClient(restLogin))},
		rest.Route{"DELETE", "/login", gz(restLogout)},

		// "Misc" stuff
		rest.Route{"GET", "/top/services", gz(sc.authorizedClient(restGetTopServices))},
		rest.Route{"GET", "/running", gz(sc.authorizedClient(restGetAllRunning))},
		rest.Route{"GET", "/config", gz(sc.authorizedClient(restGetUIConfig))},
		rest.Route{"GET", "/servicestatus", gz(sc.authorizedClient(restGetConciseServiceStatus))},

		// Generic static data
		rest.Route{"GET", "/favicon.ico", gz(favIcon)},
		rest.Route{"GET", "/static/*resource", gz(staticData)},
		rest.Route{"GET", "/licenses.html", gz(licenses)},

		// Info about serviced itself
		rest.Route{"GET", "/dockerIsLoggedIn", gz(sc.authorizedClient(restDockerIsLoggedIn))},
		rest.Route{"GET", "/stats", gz(sc.isCollectingStats())},
		rest.Route{"GET", "/version", gz(sc.authorizedClient(restGetServicedVersion))},
		rest.Route{"GET", "/storage", gz(sc.authorizedClient(restGetStorage))},
	}

	// Hardcoding these target URLs for now.
	// TODO: When internal services are allowed to run on other hosts, look that up.
	// All API calls require authentication
	routes = routeToInternalServiceProxy("/api/controlplane/elastic", "http://127.0.0.1:9100/", true, routes)
	routes = routeToInternalServiceProxy("/metrics/api", "http://127.0.0.1:8888/api", true, routes)
	routes = routeToInternalServiceProxy("/api/controlplane/kibana", "http://127.0.0.1:5601", true, routes)

	// Allow static assets for metrics data to be loaded without authentication since they are
	// included in index.html by default.
	routes = routeToInternalServiceProxy("/metrics/static", "http://127.0.0.1:8888/static", false, routes)

	return routes
}
<|endoftext|>