<commit_before>package ergo

import (
	"net/http"

	"github.com/wlMalk/ergo/validation"
)

type Request struct {
	*http.Request
	Input      map[string]validation.Valuer
	pathParams map[string]string
	operation  *Operation // Operation object
}

func NewRequest(httpRequest *http.Request) *Request {
	return &Request{
		Request: httpRequest,
		Input:   map[string]validation.Valuer{},
	}
}

// Req returns the request.
func (req *Request) Req() *http.Request {
	return req.Request
}

// Param returns the input parameter value by its name.
func (req *Request) Param(name string) validation.Valuer {
	return req.Input[name]
}

// ParamOk returns the input parameter value by its name.
func (req *Request) ParamOk(name string) (validation.Valuer, bool) {
	p, ok := req.Input[name]
	return p, ok
}

// Params returns a map of input parameters values by their names.
// If no names given then it returns r.Input
func (req *Request) Params(names ...string) map[string]validation.Valuer {
	if len(names) == 0 {
		return req.Input
	}
	params := map[string]validation.Valuer{}
	for _, n := range names {
		p, ok := req.Input[n]
		if !ok {
			continue
		}
		params[n] = p
	}
	return params
}

func (req *Request) GetOperation() Operationer {
	return req.operation
}
<commit_msg>Exposed SetPathParams in Request for wrappers to use<commit_after>package ergo

import (
	"net/http"

	"github.com/wlMalk/ergo/validation"
)

type Request struct {
	*http.Request
	Input      map[string]validation.Valuer
	pathParams map[string]string
	operation  *Operation // Operation object
}

func NewRequest(httpRequest *http.Request) *Request {
	return &Request{
		Request:    httpRequest,
		pathParams: map[string]string{},
		Input:      map[string]validation.Valuer{},
	}
}

// Req returns the request.
func (req *Request) Req() *http.Request {
	return req.Request
}

// Param returns the input parameter value by its name.
func (req *Request) Param(name string) validation.Valuer {
	return req.Input[name]
}

// ParamOk returns the input parameter value by its name.
func (req *Request) ParamOk(name string) (validation.Valuer, bool) {
	p, ok := req.Input[name]
	return p, ok
}

// Params returns a map of input parameters values by their names.
// If no names given then it returns r.Input
func (req *Request) Params(names ...string) map[string]validation.Valuer {
	if len(names) == 0 {
		return req.Input
	}
	params := map[string]validation.Valuer{}
	for _, n := range names {
		p, ok := req.Input[n]
		if !ok {
			continue
		}
		params[n] = p
	}
	return params
}

func (req *Request) GetOperation() Operationer {
	return req.operation
}

func (req *Request) SetPathParams(params map[string]string) {
	req.pathParams = params
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/peterh/liner"
)

// Resolve asks the user to resolve the identifiers
func Resolve(identifiers []*Identifier, config *Config, in *bufio.Reader, out *bufio.Writer) map[string]map[string]string {
	line := liner.NewLiner()
	defer line.Close()
	line.SetCtrlCAborts(true)
	values := make(map[string]map[string]string)

	scopeAsked := make(map[string]bool)
	if in == nil {
		for _, id := range identifiers {
			if found(values, id) || id.scope == "" || scopeAsked[id.scope] {
				continue
			}
			scopeAsked[id.scope] = true
			var keys []string
			added := make(map[string]bool)
			for _, d := range identifiers {
				if id.scope == d.scope && !added[d.key] {
					keys = append(keys, d.key)
					added[d.key] = true
				}
			}
			if len(keys) == 0 {
				continue
			}
			hs := config.historyPairs(&IdentifierGroup{scope: id.scope, keys: keys})
			if len(hs) == 0 {
				continue
			}
			line.ClearHistory()
			for i := len(hs) - 1; i >= 0; i-- {
				line.AppendHistory(hs[i])
			}
			prompt := fmt.Sprintf("[%s] %s: ", id.scope, strings.Join(keys, ", "))
			text, err := line.Prompt(prompt)
			if err != nil {
				if err == liner.ErrPromptAborted || err == io.EOF {
					os.Exit(1)
				}
				log.Fatal(err)
			}
			xs := strings.Split(strings.TrimSuffix(text, "\n"), ", ")
			if len(xs) == len(keys) {
				for i, key := range keys {
					id := &Identifier{scope: id.scope, key: key}
					insert(values, id, strings.Replace(xs[i], ",\\ ", ", ", -1))
				}
			}
		}
	}

	for _, id := range identifiers {
		if found(values, id) {
			continue
		}
		prompt := fmt.Sprintf("%s: ", id.key)
		if id.scope != "" {
			prompt = fmt.Sprintf("[%s] %s: ", id.scope, id.key)
		}
		var text string
		var err error
		if in == nil {
			line.ClearHistory()
			hs := config.history(id)
			for i := len(hs) - 1; i >= 0; i-- {
				line.AppendHistory(hs[i])
			}
			text, err = line.Prompt(prompt)
			if err != nil {
				if err == liner.ErrPromptAborted || err == io.EOF {
					os.Exit(1)
				}
				log.Fatal(err)
			}
		} else {
			out.WriteString(prompt)
			out.Flush()
			text, err = in.ReadString('\n')
			if err != nil {
				log.Fatal(err)
			}
		}
		insert(values, id, strings.TrimSuffix(text, "\n"))
	}

	return values
}
<commit_msg>local setHistory function for DRY<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/peterh/liner"
)

// Resolve asks the user to resolve the identifiers
func Resolve(identifiers []*Identifier, config *Config, in *bufio.Reader, out *bufio.Writer) map[string]map[string]string {
	line := liner.NewLiner()
	defer line.Close()
	line.SetCtrlCAborts(true)
	setHistory := func(history []string) {
		line.ClearHistory()
		for i := len(history) - 1; i >= 0; i-- {
			line.AppendHistory(history[i])
		}
	}
	values := make(map[string]map[string]string)

	scopeAsked := make(map[string]bool)
	if in == nil {
		for _, id := range identifiers {
			if found(values, id) || id.scope == "" || scopeAsked[id.scope] {
				continue
			}
			scopeAsked[id.scope] = true
			var keys []string
			added := make(map[string]bool)
			for _, d := range identifiers {
				if id.scope == d.scope && !added[d.key] {
					keys = append(keys, d.key)
					added[d.key] = true
				}
			}
			if len(keys) == 0 {
				continue
			}
			history := config.historyPairs(&IdentifierGroup{scope: id.scope, keys: keys})
			if len(history) == 0 {
				continue
			}
			setHistory(history)
			prompt := fmt.Sprintf("[%s] %s: ", id.scope, strings.Join(keys, ", "))
			text, err := line.Prompt(prompt)
			if err != nil {
				if err == liner.ErrPromptAborted || err == io.EOF {
					os.Exit(1)
				}
				log.Fatal(err)
			}
			xs := strings.Split(strings.TrimSuffix(text, "\n"), ", ")
			if len(xs) == len(keys) {
				for i, key := range keys {
					id := &Identifier{scope: id.scope, key: key}
					insert(values, id, strings.Replace(xs[i], ",\\ ", ", ", -1))
				}
			}
		}
	}

	for _, id := range identifiers {
		if found(values, id) {
			continue
		}
		prompt := fmt.Sprintf("%s: ", id.key)
		if id.scope != "" {
			prompt = fmt.Sprintf("[%s] %s: ", id.scope, id.key)
		}
		var text string
		var err error
		if in == nil {
			setHistory(config.history(id))
			text, err = line.Prompt(prompt)
			if err != nil {
				if err == liner.ErrPromptAborted || err == io.EOF {
					os.Exit(1)
				}
				log.Fatal(err)
			}
		} else {
			out.WriteString(prompt)
			out.Flush()
			text, err = in.ReadString('\n')
			if err != nil {
				log.Fatal(err)
			}
		}
		insert(values, id, strings.TrimSuffix(text, "\n"))
	}

	return values
}
<|endoftext|>


<commit_before>// Copyright 2016 IBM Corporation
//
//   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 logging

import (
	"fmt"

	"github.com/Sirupsen/logrus"
	"github.com/Sirupsen/logrus/formatters/logstash"
)

func init() {
	logrus.SetLevel(logrus.ErrorLevel) // default to printing only Error level and above
}

// GetLogger returns a logger where the module field is set to name
func GetLogger(module string) *logrus.Entry {
	if module == "" {
		logrus.Warnf("missing module name parameter")
		module = "undefined"
	}
	return logrus.WithField("module", module)
}

// GetLogFormatter returns a formatter according to the given format.
// Supported formats are 'text', 'json', and 'logstash'.
func GetLogFormatter(format string) (logrus.Formatter, error) {
	switch format {
	case "text":
		formatter := &logrus.TextFormatter{}
		formatter.DisableColors = true
		return formatter, nil
	case "json":
		return &logrus.JSONFormatter{}, nil
	case "logstash":
		return &logstash.LogstashFormatter{}, nil
	default:
		return nil, fmt.Errorf("unknown log format: %v\n", format)
	}
}
<commit_msg>Fixed new golint issue<commit_after>// Copyright 2016 IBM Corporation
//
//   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 logging

import (
	"fmt"

	"github.com/Sirupsen/logrus"
	"github.com/Sirupsen/logrus/formatters/logstash"
)

func init() {
	logrus.SetLevel(logrus.ErrorLevel) // default to printing only Error level and above
}

// GetLogger returns a logger where the module field is set to name
func GetLogger(module string) *logrus.Entry {
	if module == "" {
		logrus.Warnf("missing module name parameter")
		module = "undefined"
	}
	return logrus.WithField("module", module)
}

// GetLogFormatter returns a formatter according to the given format.
// Supported formats are 'text', 'json', and 'logstash'.
func GetLogFormatter(format string) (logrus.Formatter, error) {
	switch format {
	case "text":
		formatter := &logrus.TextFormatter{}
		formatter.DisableColors = true
		return formatter, nil
	case "json":
		return &logrus.JSONFormatter{}, nil
	case "logstash":
		return &logstash.LogstashFormatter{}, nil
	default:
		return nil, fmt.Errorf("unknown log format: %v", format)
	}
}
<|endoftext|>


<commit_before>package scene

import (
	"fmt"
	"image"
	"time"

	"github.com/pankona/gomo-simra/simra"
)

type effect struct {
	game       *game
	animations map[string]*simra.AnimationSet
	effects    map[string]*simra.Sprite
}

func (e *effect) initialize() {
	e.animations = make(map[string]*simra.AnimationSet)
	e.effects = make(map[string]*simra.Sprite)

	// smoke animation
	numOfAnimation := 3
	w := 512 / numOfAnimation
	h := 528 / 4
	resource := "smoke.png"
	animationSet := simra.NewAnimationSet()
	for i := 0; i < numOfAnimation; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (1)
	numOfAnimation = 5
	w = 600 / numOfAnimation
	h = 120
	resource = "atkeffect1.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < numOfAnimation; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (2)
	numOfAnimation = 7
	w = 840 / numOfAnimation
	h = 120
	resource = "atkeffect2.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < numOfAnimation; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (3)
	numOfAnimation = 8
	w = 960 / numOfAnimation
	h = 120
	resource = "atkeffect3.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < numOfAnimation; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (4)
	w = 600 / 5
	h = 120
	resource = "atkeffect4.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < 5; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	for i := 0; i < 3; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, h, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (5)
	w = 600 / 6
	h = 120
	resource = "atkeffect5.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < 6; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	for i := 0; i < 6; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, h, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

}

func (e *effect) OnEvent(i interface{}) {
	c, ok := i.(*command)
	if !ok {
		panic("unexpected command received. fatal.")
	}

	switch c.commandtype {
	case commandSpawn:
		p, ok := c.data.(uniter)
		if !ok {
			// ignore
			break
		}
		sprite := simra.NewSprite()
		sprite.W = 512 / 3
		sprite.H = 528 / 4
		x, y := p.GetPosition()
		sprite.X, sprite.Y = x-10, y+20

		animationSet := e.animations["smoke.png"]
		sprite.AddAnimationSet("smoke.png", animationSet)
		simra.GetInstance().AddSprite2(sprite)
		sprite.StartAnimation("smoke.png", true, func() {})
		e.effects[p.GetID()] = sprite

	case commandSpawned:
		p, ok := c.data.(uniter)
		if !ok {
			// ignore
			break
		}
		sprite := e.effects[p.GetID()]
		sprite.StopAnimation()
		delete(e.effects, p.GetID())
		simra.GetInstance().RemoveSprite(sprite)

	case commandAttack:
		p, ok := c.data.(uniter)
		if !ok {
			// ignore
			break
		}
		target := p.GetTarget()
		tx, ty := target.GetPosition()

		sprite := simra.NewSprite()
		sprite.W = 64
		sprite.H = 64
		sprite.X, sprite.Y = tx, ty
		var atkeffect string
		switch p.GetUnitType() {
		case "player1":
			atkeffect = "atkeffect1.png"
		case "player2":
			atkeffect = "atkeffect2.png"
		case "player3":
			atkeffect = "atkeffect3.png"
		case "enemy1":
			atkeffect = "atkeffect4.png"
		case "enemy2":
			atkeffect = "atkeffect5.png"
		default:
			simra.LogError("[%s]'s atkeffect is not loaded!", p.GetUnitType())
			panic("atkeffect is not loaded!")
		}

		animationSet := e.animations[atkeffect]
		sprite.AddAnimationSet(atkeffect, animationSet)
		simra.GetInstance().AddSprite2(sprite)
		sprite.StartAnimation(atkeffect, true, func() {})
		e.effects[p.GetID()] = sprite

	case commandAttackEnd:
		p, ok := c.data.(uniter)
		if !ok {
			// ignore
			break
		}

		fmt.Printf("[effect][%s] ends attacking\n", p.GetID())

		sprite := e.effects[p.GetID()]
		sprite.StopAnimation()
		delete(e.effects, p.GetID())
		simra.GetInstance().RemoveSprite(sprite)
	}
}
<commit_msg>not to remove already removed effect to avoid crash<commit_after>package scene

import (
	"fmt"
	"image"
	"time"

	"github.com/pankona/gomo-simra/simra"
)

type effect struct {
	game       *game
	animations map[string]*simra.AnimationSet
	effects    map[string]*simra.Sprite
}

func (e *effect) initialize() {
	e.animations = make(map[string]*simra.AnimationSet)
	e.effects = make(map[string]*simra.Sprite)

	// smoke animation
	numOfAnimation := 3
	w := 512 / numOfAnimation
	h := 528 / 4
	resource := "smoke.png"
	animationSet := simra.NewAnimationSet()
	for i := 0; i < numOfAnimation; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (1)
	numOfAnimation = 5
	w = 600 / numOfAnimation
	h = 120
	resource = "atkeffect1.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < numOfAnimation; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (2)
	numOfAnimation = 7
	w = 840 / numOfAnimation
	h = 120
	resource = "atkeffect2.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < numOfAnimation; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (3)
	numOfAnimation = 8
	w = 960 / numOfAnimation
	h = 120
	resource = "atkeffect3.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < numOfAnimation; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (4)
	w = 600 / 5
	h = 120
	resource = "atkeffect4.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < 5; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	for i := 0; i < 3; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, h, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

	// attack animation (5)
	w = 600 / 6
	h = 120
	resource = "atkeffect5.png"
	animationSet = simra.NewAnimationSet()
	for i := 0; i < 6; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, 0, ((int)(w)*(i+1))-1, int(h))))
	}
	for i := 0; i < 6; i++ {
		animationSet.AddTexture(simra.NewImageTexture(resource,
			image.Rect((int)(w)*i, h, ((int)(w)*(i+1))-1, int(h))))
	}
	// TODO: don't relay on time. use fps based animation control
	animationSet.SetInterval(100 * time.Millisecond)
	e.animations[resource] = animationSet

}

func (e *effect) OnEvent(i interface{}) {
	c, ok := i.(*command)
	if !ok {
		panic("unexpected command received. fatal.")
	}

	switch c.commandtype {
	case commandSpawn:
		p, ok := c.data.(uniter)
		if !ok {
			// ignore
			break
		}
		sprite := simra.NewSprite()
		sprite.W = 512 / 3
		sprite.H = 528 / 4
		x, y := p.GetPosition()
		sprite.X, sprite.Y = x-10, y+20

		animationSet := e.animations["smoke.png"]
		sprite.AddAnimationSet("smoke.png", animationSet)
		simra.GetInstance().AddSprite2(sprite)
		sprite.StartAnimation("smoke.png", true, func() {})
		e.effects[p.GetID()] = sprite

	case commandSpawned:
		p, ok := c.data.(uniter)
		if !ok {
			// ignore
			break
		}
		sprite := e.effects[p.GetID()]
		sprite.StopAnimation()
		delete(e.effects, p.GetID())
		simra.GetInstance().RemoveSprite(sprite)

	case commandAttack:
		p, ok := c.data.(uniter)
		if !ok {
			// ignore
			break
		}
		target := p.GetTarget()
		tx, ty := target.GetPosition()

		sprite := simra.NewSprite()
		sprite.W = 64
		sprite.H = 64
		sprite.X, sprite.Y = tx, ty
		var atkeffect string
		switch p.GetUnitType() {
		case "player1":
			atkeffect = "atkeffect1.png"
		case "player2":
			atkeffect = "atkeffect2.png"
		case "player3":
			atkeffect = "atkeffect3.png"
		case "enemy1":
			atkeffect = "atkeffect4.png"
		case "enemy2":
			atkeffect = "atkeffect5.png"
		default:
			simra.LogError("[%s]'s atkeffect is not loaded!", p.GetUnitType())
			panic("atkeffect is not loaded!")
		}

		animationSet := e.animations[atkeffect]
		sprite.AddAnimationSet(atkeffect, animationSet)
		simra.GetInstance().AddSprite2(sprite)
		sprite.StartAnimation(atkeffect, true, func() {})
		e.effects[p.GetID()] = sprite

	case commandAttackEnd:
		p, ok := c.data.(uniter)
		if !ok {
			// ignore
			break
		}

		fmt.Printf("[effect][%s] ends attacking\n", p.GetID())

		sprite, ok := e.effects[p.GetID()]
		if !ok {
			// maybe this is already removed effect. do nothing.
			break
		}

		sprite.StopAnimation()
		delete(e.effects, p.GetID())
		simra.GetInstance().RemoveSprite(sprite)
	}
}
<|endoftext|>


<commit_before>package sdhook

// ResType is a monitored resource descriptor type.
//
// See https://cloud.google.com/logging/docs/api/v2/resource-list
type ResType string

const (
	ResTypeAPI                     ResType = "api"
	ResTypeAppScriptFunction       ResType = "app_script_function"
	ResTypeAwsEc2Instance          ResType = "aws_ec2_instance"
	ResTypeBigqueryResource        ResType = "bigquery_resource"
	ResTypeBuild                   ResType = "build"
	ResTypeClientAuthConfigBrand   ResType = "client_auth_config_brand"
	ResTypeClientAuthConfigClient  ResType = "client_auth_config_client"
	ResTypeCloudDebuggerResource   ResType = "cloud_debugger_resource"
	ResTypeCloudFunction           ResType = "cloud_function"
	ResTypeCloudsqlDatabase        ResType = "cloudsql_database"
	ResTypeContainer               ResType = "container"
	ResTypeDataflowStep            ResType = "dataflow_step"
	ResTypeDataprocCluster         ResType = "dataproc_cluster"
	ResTypeDeployment              ResType = "deployment"
	ResTypeDeploymentManagerType   ResType = "deployment_manager_type"
	ResTypeDNSManagedZone          ResType = "dns_managed_zone"
	ResTypeGaeApp                  ResType = "gae_app"
	ResTypeGceAutoscaler           ResType = "gce_autoscaler"
	ResTypeGceBackendService       ResType = "gce_backend_service"
	ResTypeGceDisk                 ResType = "gce_disk"
	ResTypeGceFirewallRule         ResType = "gce_firewall_rule"
	ResTypeGceForwardingRule       ResType = "gce_forwarding_rule"
	ResTypeGceHealthCheck          ResType = "gce_health_check"
	ResTypeGceImage                ResType = "gce_image"
	ResTypeGceInstance             ResType = "gce_instance"
	ResTypeGceInstanceGroup        ResType = "gce_instance_group"
	ResTypeGceInstanceGroupManager ResType = "gce_instance_group_manager"
	ResTypeGceInstanceTemplate     ResType = "gce_instance_template"
	ResTypeGceNetwork              ResType = "gce_network"
	ResTypeGceOperation            ResType = "gce_operation"
	ResTypeGceProject              ResType = "gce_project"
	ResTypeGceReservedAddress      ResType = "gce_reserved_address"
	ResTypeGceRoute                ResType = "gce_route"
	ResTypeGceRouter               ResType = "gce_router"
	ResTypeGceSnapshot             ResType = "gce_snapshot"
	ResTypeGceSslCertificate       ResType = "gce_ssl_certificate"
	ResTypeGceSubnetwork           ResType = "gce_subnetwork"
	ResTypeGceTargetHTTPProxy      ResType = "gce_target_http_proxy"
	ResTypeGceTargetHTTPSProxy     ResType = "gce_target_https_proxy"
	ResTypeGceTargetPool           ResType = "gce_target_pool"
	ResTypeGceURLMap               ResType = "gce_url_map"
	ResTypeGcsBucket               ResType = "gcs_bucket"
	ResTypeGkeCluster              ResType = "gke_cluster"
	ResTypeGlobal                  ResType = "global"
	ResTypeHTTPLoadBalancer        ResType = "http_load_balancer"
	ResTypeLoggingLog              ResType = "logging_log"
	ResTypeLoggingSink             ResType = "logging_sink"
	ResTypeMetric                  ResType = "metric"
	ResTypeMlJob                   ResType = "ml_job"
	ResTypeOrganization            ResType = "organization"
	ResTypeProject                 ResType = "project"
	ResTypeServiceAccount          ResType = "service_account"
	ResTypeTestserviceMatrix       ResType = "testservice_matrix"
	ResTypeVpnGateway              ResType = "vpn_gateway"
)
<commit_msg>add restype "Cloud Run"<commit_after>package sdhook

// ResType is a monitored resource descriptor type.
//
// See https://cloud.google.com/logging/docs/api/v2/resource-list
type ResType string

const (
	ResTypeAPI                     ResType = "api"
	ResTypeAppScriptFunction       ResType = "app_script_function"
	ResTypeAwsEc2Instance          ResType = "aws_ec2_instance"
	ResTypeBigqueryResource        ResType = "bigquery_resource"
	ResTypeBuild                   ResType = "build"
	ResTypeClientAuthConfigBrand   ResType = "client_auth_config_brand"
	ResTypeClientAuthConfigClient  ResType = "client_auth_config_client"
	ResTypeCloudDebuggerResource   ResType = "cloud_debugger_resource"
	ResTypeCloudFunction           ResType = "cloud_function"
	ResTypeCloudRunRevision        ResType = "cloud_run_revision"
	ResTypeCloudsqlDatabase        ResType = "cloudsql_database"
	ResTypeContainer               ResType = "container"
	ResTypeDataflowStep            ResType = "dataflow_step"
	ResTypeDataprocCluster         ResType = "dataproc_cluster"
	ResTypeDeployment              ResType = "deployment"
	ResTypeDeploymentManagerType   ResType = "deployment_manager_type"
	ResTypeDNSManagedZone          ResType = "dns_managed_zone"
	ResTypeGaeApp                  ResType = "gae_app"
	ResTypeGceAutoscaler           ResType = "gce_autoscaler"
	ResTypeGceBackendService       ResType = "gce_backend_service"
	ResTypeGceDisk                 ResType = "gce_disk"
	ResTypeGceFirewallRule         ResType = "gce_firewall_rule"
	ResTypeGceForwardingRule       ResType = "gce_forwarding_rule"
	ResTypeGceHealthCheck          ResType = "gce_health_check"
	ResTypeGceImage                ResType = "gce_image"
	ResTypeGceInstance             ResType = "gce_instance"
	ResTypeGceInstanceGroup        ResType = "gce_instance_group"
	ResTypeGceInstanceGroupManager ResType = "gce_instance_group_manager"
	ResTypeGceInstanceTemplate     ResType = "gce_instance_template"
	ResTypeGceNetwork              ResType = "gce_network"
	ResTypeGceOperation            ResType = "gce_operation"
	ResTypeGceProject              ResType = "gce_project"
	ResTypeGceReservedAddress      ResType = "gce_reserved_address"
	ResTypeGceRoute                ResType = "gce_route"
	ResTypeGceRouter               ResType = "gce_router"
	ResTypeGceSnapshot             ResType = "gce_snapshot"
	ResTypeGceSslCertificate       ResType = "gce_ssl_certificate"
	ResTypeGceSubnetwork           ResType = "gce_subnetwork"
	ResTypeGceTargetHTTPProxy      ResType = "gce_target_http_proxy"
	ResTypeGceTargetHTTPSProxy     ResType = "gce_target_https_proxy"
	ResTypeGceTargetPool           ResType = "gce_target_pool"
	ResTypeGceURLMap               ResType = "gce_url_map"
	ResTypeGcsBucket               ResType = "gcs_bucket"
	ResTypeGkeCluster              ResType = "gke_cluster"
	ResTypeGlobal                  ResType = "global"
	ResTypeHTTPLoadBalancer        ResType = "http_load_balancer"
	ResTypeLoggingLog              ResType = "logging_log"
	ResTypeLoggingSink             ResType = "logging_sink"
	ResTypeMetric                  ResType = "metric"
	ResTypeMlJob                   ResType = "ml_job"
	ResTypeOrganization            ResType = "organization"
	ResTypeProject                 ResType = "project"
	ResTypeServiceAccount          ResType = "service_account"
	ResTypeTestserviceMatrix       ResType = "testservice_matrix"
	ResTypeVpnGateway              ResType = "vpn_gateway"
)
<|endoftext|>


<commit_before>package schema

// Schema is the metadata container for a schema definition
type Schema struct {
	Name   string
	Tables map[string]*Table
	// For get ops
	TableAliases map[string]string
}

// Table is the metadata container for a SQL table definition
type Table struct {
	// Should dyndao use a LastInsertID() mechanism after INSERTing (or
	// whatever the equivalent is, like with Oracle or PostgreSQL) or will
	// the calling code supply a primary key.
	CallerSuppliesPK bool

	MultiKey  bool
	Primary   string
	Name      string
	AliasName string

	ForeignKeys []string

	Columns       map[string]*Column
	ColumnAliases map[string]string

	EssentialColumns []string

	JSONCol      string
	ParentTables []string               `json:"ParentTables"`
	Children     map[string]*ChildTable `json:"Children"`

	// YAGNI?
	// TODO: ChildrenInsertionOrder?
	// TODO: DeletionOrder?
}

// GetTableName returns either ourDefault or the override string. It is assumed
// that you'll pass in the table key (schema.Tables[key]) and the table name
// (schema.Tables[key].Name), so that this wrapper function can decide.
func GetTableName(override string, ourDefault string) string {
	if override != "" {
		return override
	}
	return ourDefault
}

// Column represents a single column in a SQL table
type Column struct {
	IsSingleTable bool
	AllowNull     bool
	IsNumber      bool
	IsJSON        bool
	IsIdentity    bool
	IsForeignKey  bool
	IsUnique      bool
	Length        int
	Name          string

	DefaultValue string
	DBType       string

	MapToString bool
}

// ChildTable represents a relationship between a parent table
// and a child table
type ChildTable struct {
	ParentTable string

	MultiKey      bool
	LocalColumn   string
	ForeignColumn string

	LocalColumns   []string
	ForeignColumns []string
}
<commit_msg>cleanup<commit_after>package schema

type Schema struct {
	Name   string
	Tables map[string]*Table
	// For get ops
	TableAliases map[string]string
}

type Table struct {
	CallerSuppliesPK bool // Database-generated PK or user-generated

	MultiKey  bool
	Primary   string
	Name      string
	AliasName string

	ForeignKeys []string

	Columns       map[string]*Column
	ColumnAliases map[string]string

	EssentialColumns []string

	JSONCol      string
	ParentTables []string
	Children     map[string]*ChildTable
	// YAGNI?
	// TODO: ChildrenInsertionOrder?
	// TODO: DeletionOrder?
}

// GetTableName returns either ourDefault or the override string. It is assumed
// that you'll pass in the table key (schema.Tables[key]) and the table name
// (schema.Tables[key].Name), so that this wrapper function can decide.
func GetTableName(override string, ourDefault string) string {
	if override != "" {
		return override
	}
	return ourDefault
}

// Column represents a single column in a SQL table
type Column struct {
	IsSingleTable bool
	AllowNull     bool
	IsNumber      bool
	IsJSON        bool
	IsIdentity    bool
	IsForeignKey  bool
	IsUnique      bool
	Length        int
	Name          string

	DefaultValue string
	DBType       string

	MapToString bool
}

type ChildTable struct {
	ParentTable string

	MultiKey      bool
	LocalColumn   string
	ForeignColumn string

	LocalColumns   []string
	ForeignColumns []string
}
<|endoftext|>


<commit_before>package ui

import (
	"bytes"
	"errors"
	"fmt"
	"runtime"
	"strings"

	"github.com/moncho/dry/terminal"
	"github.com/nsf/termbox-go"
)

type newLineEvent func()

// A View is a region of the screen where text can be rendered. It maintains
//its own internal buffer and cursor position.)
type View struct {
	name             string
	x0, y0, x1, y1   int      //view position in the screen
	width, height    int      //view width,height
	bufferX, bufferY int      //current position in the view buffer
	cursorX, cursorY int      //cursor position in the screen, valid values between 0 and x1, y1
	lines            [][]rune //the content buffer
	showCursor       bool

	newLineNotifier newLineEvent

	theme  *ColorTheme
	markup *Markup
}

// ViewSize returns the width and the height of the View.
func (v *View) ViewSize() (width, height int) {
	return v.width, v.height
}

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

// SetCursor sets the cursor position of the view at the given point,
// relative to the screen. An error is returned if the position is outside
// the screen limits.
func (v *View) setCursor(x, y int) error {
	maxX, maxY := v.ViewSize()
	if x < 0 || x >= maxX || y < 0 || y >= maxY {
		return invalidPointError(x, y)
	}
	v.cursorX = x
	v.cursorY = y
	return nil
}

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

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

// Position returns the position in the view buffer.
func (v *View) Position() (x, y int) {
	return v.bufferX, v.bufferY
}

// Write appends a byte slice into the view's internal buffer, as defined
// by the io.Writer interface.
func (v *View) Write(p []byte) (n int, err error) {

	for _, ch := range bytes.Runes(p) {
		switch ch {
		case '\n':
			v.lines = append(v.lines, nil)
			if v.newLineNotifier != nil {
				v.newLineNotifier()
			}
		case '\r':
			nl := len(v.lines)
			if nl > 0 {
				v.lines[nl-1] = nil
			} else {
				v.lines = make([][]rune, 1)
			}
		default:
			nl := len(v.lines)
			if nl > 0 {
				v.lines[nl-1] = append(v.lines[nl-1], ch)
				//If the length of the line is higher than then view size
				//content goes to a new line
				if len(v.lines[nl-1]) >= v.width {
					v.lines = append(v.lines, nil)
				}
			} else {
				v.lines = append(v.lines, []rune{ch})
			}
		}
	}
	return len(p), nil
}

// Render renders the view buffer contents.
func (v *View) render() {
	_, maxY := v.ViewSize()
	y := v.y0
	for _, vline := range v.lines[v.bufferY:] {
		if y > maxY {
			break
		}
		v.renderLine(v.x0, y, string(vline))
		y++
	}
	if v.showCursor {
		v.drawCursor()
	}
}

//calculateCursorPosition gives the cursor position
//from the beginning of the view
func (v *View) calculateCursorPosition() (int, int) {
	return v.x0 + v.cursorX, v.y0 + v.cursorY
}

func (v *View) drawCursor() {
	cursorX, cursorY := v.calculateCursorPosition()

	_, ry, _ := v.realPosition(cursorX, cursorY)

	if ry <= len(v.lines) {
		termbox.SetCursor(cursorX, cursorY)
	}
}

// realPosition returns the position in the internal buffer corresponding to the
// point (x, y) of the view.
func (v *View) realPosition(vx, vy int) (x, y int, err error) {
	vx = v.bufferX + vx
	vy = v.bufferY + vy

	if vx < 0 || vy < 0 {
		return 0, 0, invalidPointError(x, y)
	}

	if len(v.lines) == 0 {
		return vx, vy, nil
	}
	x = vx
	if vy < len(v.lines) {
		y = vy
	} else {
		y = vy - len(v.lines) + 1
	}

	return x, y, nil
}

//renderLine renders the given line, returns the number of screen lines used
func (v *View) renderLine(x int, y int, line string) (int, error) {
	lines := 1
	maxWidth, _ := v.ViewSize()
	if v.markup != nil {
		lines = renderLineWithMarkup(x, y, maxWidth, line, v.markup)
	} else {

		ansiClean := terminal.RemoveANSIEscapeCharacters(line)
		// Methods receives a single line, so just the first element
		// returned by the cleaner is considered
		if len(ansiClean) > 0 {
			_, lines = renderString(x, y, maxWidth, string(ansiClean[0]), termbox.Attribute(v.theme.Fg), termbox.Attribute(v.theme.Bg))
		}
	}
	return lines, nil
}

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

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

// Line returns a string with the line of the view's internal buffer
// at the position corresponding to the point (x, y).
func (v *View) Line(y int) (string, error) {
	_, y, err := v.realPosition(0, y)
	if err != nil {
		return "", err
	}

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

// Word returns a string with the word of the view's internal buffer
// at the position corresponding to the point (x, y).
func (v *View) Word(x, y int) (string, error) {
	x, y, err := v.realPosition(x, y)
	if err != nil {
		return "", err
	}

	if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
		return "", invalidPointError(x, y)
	}
	l := string(v.lines[y])
	nl := strings.LastIndexFunc(l[:x], indexFunc)
	if nl == -1 {
		nl = 0
	} else {
		nl = nl + 1
	}
	nr := strings.IndexFunc(l[x:], indexFunc)
	if nr == -1 {
		nr = len(l)
	} else {
		nr = nr + x
	}
	return string(l[nl:nr]), nil
}

//CursorDown moves the cursor down one line
func (v *View) CursorDown() {
	cursorX, cursorY := v.Cursor()
	ox, bufferY := v.Position()
	if bufferY+cursorY <= len(v.lines) {
		if err := v.setCursor(cursorX, cursorY+1); err != nil {
			v.setPosition(ox, bufferY+1)
		}
	}
}

//CursorUp moves the cursor up one line
func (v *View) CursorUp() {
	ox, bufferY := v.Position()
	cursorX, cursorY := v.Cursor()
	if err := v.setCursor(cursorX, cursorY-1); err != nil && bufferY > 0 {
		v.setPosition(ox, bufferY-1)
	}
}

//PageDown moves the buffer position down by the length of the screen,
//at the end of buffer it also moves the cursor position to the bottom
//of the screen
func (v *View) PageDown() {
	_, cursorY := v.Cursor()
	bufferX, bufferY := v.Position()
	_, height := v.ViewSize()
	viewLength := len(v.lines)
	if bufferY+height+cursorY < viewLength {
		newOy := bufferY + height
		if newOy >= viewLength {
			v.setPosition(bufferX, viewLength)
		} else {
			v.setPosition(bufferX, newOy)
		}
		_, bufferY := v.Position()
		if bufferY >= viewLength-cursorY {
			v.CursorDown()
		}
	} else {
		v.CursorToBottom()
	}
}

//PageUp moves the buffer position up by the length of the screen,
//at the beginning of buffer it also moves the cursor position to the beginning
//of the screen
func (v *View) PageUp() {
	bufferX, bufferY := v.Position()
	cursorX, cursorY := v.Cursor()
	_, height := v.ViewSize()
	if err := v.setCursor(cursorX, cursorY-height); err != nil && bufferY > 0 {
		newOy := bufferY - height
		if newOy < 0 {
			v.setPosition(bufferX, 0)
		} else {
			v.setPosition(bufferX, newOy)
		}
	}
}

//CursorToBottom moves the cursor to the bottom of the view buffer
func (v *View) CursorToBottom() {
	v.bufferY = len(v.lines) - v.y1
	v.cursorY = v.y1
}

//CursorToTop moves the cursor to the top of the view buffer
func (v *View) CursorToTop() {
	v.bufferY = 0
	v.cursorY = 0
}

//MarkupSupport sets markup support in the view
func (v *View) MarkupSupport() {
	v.markup = NewMarkup(v.theme)
}

// NewView returns a new View
func NewView(name string, x0, y0, x1, y1 int, showCursor bool, theme *ColorTheme) *View {
	v := &View{
		name:  name,
		x0:    x0,
		y0:    y0,
		x1:    x1,
		y1:    y1,
		width: x1 - x0,
		//last line is used by the cursor and for reading input, it is not used to
		//render view buffer
		height:     y1 - y0 - 1,
		showCursor: showCursor,
		theme:      theme,
	}

	return v
}

// NewMarkupView returns a new View with markup support
func NewMarkupView(name string, x0, y0, x1, y1 int, showCursor bool, theme *ColorTheme) *View {
	v := NewView(name, x0, y0, x1, y1, showCursor, theme)
	v.markup = NewMarkup(theme)

	return v
}

// indexFunc allows to split lines by words taking into account spaces
// and 0.
func indexFunc(r rune) bool {
	return r == ' ' || r == 0
}

func invalidPointError(x, y int) error {
	_, file, line, _ := runtime.Caller(2)
	return fmt.Errorf(
		"Invalid point. x: %d, y: %d. Caller: %s, line: %d", x, y, file, line)
}
<commit_msg>Add noop func as new-line callback by default<commit_after>package ui

import (
	"bytes"
	"errors"
	"fmt"
	"runtime"
	"strings"

	"github.com/moncho/dry/terminal"
	"github.com/nsf/termbox-go"
)

type eventCallback func()

// A View is a region of the screen where text can be rendered. It maintains
//its own internal buffer and cursor position.)
type View struct {
	name             string
	x0, y0, x1, y1   int      //view position in the screen
	width, height    int      //view width,height
	bufferX, bufferY int      //current position in the view buffer
	cursorX, cursorY int      //cursor position in the screen, valid values between 0 and x1, y1
	lines            [][]rune //the content buffer
	showCursor       bool

	newLineCallback eventCallback

	theme  *ColorTheme
	markup *Markup
}

// ViewSize returns the width and the height of the View.
func (v *View) ViewSize() (width, height int) {
	return v.width, v.height
}

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

// SetCursor sets the cursor position of the view at the given point,
// relative to the screen. An error is returned if the position is outside
// the screen limits.
func (v *View) setCursor(x, y int) error {
	maxX, maxY := v.ViewSize()
	if x < 0 || x >= maxX || y < 0 || y >= maxY {
		return invalidPointError(x, y)
	}
	v.cursorX = x
	v.cursorY = y
	return nil
}

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

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

// Position returns the position in the view buffer.
func (v *View) Position() (x, y int) {
	return v.bufferX, v.bufferY
}

// Write appends a byte slice into the view's internal buffer, as defined
// by the io.Writer interface.
func (v *View) Write(p []byte) (n int, err error) {

	for _, ch := range bytes.Runes(p) {
		switch ch {
		case '\n':
			v.lines = append(v.lines, nil)
			v.newLineCallback()
		case '\r':
			nl := len(v.lines)
			if nl > 0 {
				v.lines[nl-1] = nil
			} else {
				v.lines = make([][]rune, 1)
			}
		default:
			nl := len(v.lines)
			if nl > 0 {
				v.lines[nl-1] = append(v.lines[nl-1], ch)
				//If the length of the line is higher than then view size
				//content goes to a new line
				if len(v.lines[nl-1]) >= v.width {
					v.lines = append(v.lines, nil)
				}
			} else {
				v.lines = append(v.lines, []rune{ch})
			}
		}
	}
	return len(p), nil
}

// Render renders the view buffer contents.
func (v *View) render() {
	_, maxY := v.ViewSize()
	y := v.y0
	for _, vline := range v.lines[v.bufferY:] {
		if y > maxY {
			break
		}
		v.renderLine(v.x0, y, string(vline))
		y++
	}
	if v.showCursor {
		v.drawCursor()
	}
}

//calculateCursorPosition gives the cursor position
//from the beginning of the view
func (v *View) calculateCursorPosition() (int, int) {
	return v.x0 + v.cursorX, v.y0 + v.cursorY
}

func (v *View) drawCursor() {
	cursorX, cursorY := v.calculateCursorPosition()

	_, ry, _ := v.realPosition(cursorX, cursorY)

	if ry <= len(v.lines) {
		termbox.SetCursor(cursorX, cursorY)
	}
}

// realPosition returns the position in the internal buffer corresponding to the
// point (x, y) of the view.
func (v *View) realPosition(vx, vy int) (x, y int, err error) {
	vx = v.bufferX + vx
	vy = v.bufferY + vy

	if vx < 0 || vy < 0 {
		return 0, 0, invalidPointError(x, y)
	}

	if len(v.lines) == 0 {
		return vx, vy, nil
	}
	x = vx
	if vy < len(v.lines) {
		y = vy
	} else {
		y = vy - len(v.lines) + 1
	}

	return x, y, nil
}

//renderLine renders the given line, returns the number of screen lines used
func (v *View) renderLine(x int, y int, line string) (int, error) {
	lines := 1
	maxWidth, _ := v.ViewSize()
	if v.markup != nil {
		lines = renderLineWithMarkup(x, y, maxWidth, line, v.markup)
	} else {

		ansiClean := terminal.RemoveANSIEscapeCharacters(line)
		// Methods receives a single line, so just the first element
		// returned by the cleaner is considered
		if len(ansiClean) > 0 {
			_, lines = renderString(x, y, maxWidth, string(ansiClean[0]), termbox.Attribute(v.theme.Fg), termbox.Attribute(v.theme.Bg))
		}
	}
	return lines, nil
}

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

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

// Line returns a string with the line of the view's internal buffer
// at the position corresponding to the point (x, y).
func (v *View) Line(y int) (string, error) {
	_, y, err := v.realPosition(0, y)
	if err != nil {
		return "", err
	}

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

// Word returns a string with the word of the view's internal buffer
// at the position corresponding to the point (x, y).
func (v *View) Word(x, y int) (string, error) {
	x, y, err := v.realPosition(x, y)
	if err != nil {
		return "", err
	}

	if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
		return "", invalidPointError(x, y)
	}
	l := string(v.lines[y])
	nl := strings.LastIndexFunc(l[:x], indexFunc)
	if nl == -1 {
		nl = 0
	} else {
		nl = nl + 1
	}
	nr := strings.IndexFunc(l[x:], indexFunc)
	if nr == -1 {
		nr = len(l)
	} else {
		nr = nr + x
	}
	return string(l[nl:nr]), nil
}

//CursorDown moves the cursor down one line
func (v *View) CursorDown() {
	cursorX, cursorY := v.Cursor()
	ox, bufferY := v.Position()
	if bufferY+cursorY <= len(v.lines) {
		if err := v.setCursor(cursorX, cursorY+1); err != nil {
			v.setPosition(ox, bufferY+1)
		}
	}
}

//CursorUp moves the cursor up one line
func (v *View) CursorUp() {
	ox, bufferY := v.Position()
	cursorX, cursorY := v.Cursor()
	if err := v.setCursor(cursorX, cursorY-1); err != nil && bufferY > 0 {
		v.setPosition(ox, bufferY-1)
	}
}

//PageDown moves the buffer position down by the length of the screen,
//at the end of buffer it also moves the cursor position to the bottom
//of the screen
func (v *View) PageDown() {
	_, cursorY := v.Cursor()
	bufferX, bufferY := v.Position()
	_, height := v.ViewSize()
	viewLength := len(v.lines)
	if bufferY+height+cursorY < viewLength {
		newOy := bufferY + height
		if newOy >= viewLength {
			v.setPosition(bufferX, viewLength)
		} else {
			v.setPosition(bufferX, newOy)
		}
		_, bufferY := v.Position()
		if bufferY >= viewLength-cursorY {
			v.CursorDown()
		}
	} else {
		v.CursorToBottom()
	}
}

//PageUp moves the buffer position up by the length of the screen,
//at the beginning of buffer it also moves the cursor position to the beginning
//of the screen
func (v *View) PageUp() {
	bufferX, bufferY := v.Position()
	cursorX, cursorY := v.Cursor()
	_, height := v.ViewSize()
	if err := v.setCursor(cursorX, cursorY-height); err != nil && bufferY > 0 {
		newOy := bufferY - height
		if newOy < 0 {
			v.setPosition(bufferX, 0)
		} else {
			v.setPosition(bufferX, newOy)
		}
	}
}

//CursorToBottom moves the cursor to the bottom of the view buffer
func (v *View) CursorToBottom() {
	v.bufferY = len(v.lines) - v.y1
	v.cursorY = v.y1
}

//CursorToTop moves the cursor to the top of the view buffer
func (v *View) CursorToTop() {
	v.bufferY = 0
	v.cursorY = 0
}

//MarkupSupport sets markup support in the view
func (v *View) MarkupSupport() {
	v.markup = NewMarkup(v.theme)
}

// NewView returns a new View
func NewView(name string, x0, y0, x1, y1 int, showCursor bool, theme *ColorTheme) *View {
	v := &View{
		name:  name,
		x0:    x0,
		y0:    y0,
		x1:    x1,
		y1:    y1,
		width: x1 - x0,
		//last line is used by the cursor and for reading input, it is not used to
		//render view buffer
		height:          y1 - y0 - 1,
		showCursor:      showCursor,
		theme:           theme,
		newLineCallback: func() {},
	}

	return v
}

// NewMarkupView returns a new View with markup support
func NewMarkupView(name string, x0, y0, x1, y1 int, showCursor bool, theme *ColorTheme) *View {
	v := NewView(name, x0, y0, x1, y1, showCursor, theme)
	v.markup = NewMarkup(theme)

	return v
}

// indexFunc allows to split lines by words taking into account spaces
// and 0.
func indexFunc(r rune) bool {
	return r == ' ' || r == 0
}

func invalidPointError(x, y int) error {
	_, file, line, _ := runtime.Caller(2)
	return fmt.Errorf(
		"Invalid point. x: %d, y: %d. Caller: %s, line: %d", x, y, file, line)
}
<|endoftext|>


<commit_before>package linker

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"plaid/parser"
)

type node struct {
	flag     int
	path     string
	ast      *parser.Program
	children []*node
	parents  []*node
	module   *Module
}

type graph struct {
	root  *node
	nodes map[string]*node
}

func (g *graph) resetFlags() {
	for _, n := range g.nodes {
		n.flag = 0
	}
}

// Link does some stuff
func Link(path string, ast *parser.Program, builtins ...*Module) (*Module, error) {
	order, err := resolve(path, ast)
	if err != nil {
		return nil, err
	}

	// Link ordered modules.
	for _, n := range order {
		for _, child := range n.children {
			n.module.Imports = append(n.module.Imports, child.module)
		}
	}

	return order[len(order)-1].module, nil
}

// resolve determines if a module has any dependency cycles
func resolve(path string, ast *parser.Program) ([]*node, error) {
	n := makeNode(path, ast)
	g, err := buildGraph(n, loadDependency)
	if err != nil {
		return nil, err
	}

	if cycle := findCycle(g.root, nil); cycle != nil {
		return nil, fmt.Errorf("Dependency cycle: %s", routeToString(cycle))
	}

	order := orderDependencies(g)
	return order, nil
}

func nodesToModules(route []*node) (mods []*Module) {
	for _, n := range route {
		mod := n.module
		for _, dep := range n.children {
			if containsNode(route, dep) == false {

			}
		}
		mods = append(mods, mod)
	}
	return mods
}

func orderDependencies(g *graph) (order []*node) {
	const FlagTemp = 1
	const FlagPerm = 2

	var visit func(*node)
	visit = func(n *node) {
		if n.flag == FlagPerm {
			return
		} else if n.flag == FlagTemp {
			panic("not a DAG")
		} else {
			n.flag = FlagTemp
			for _, m := range n.children {
				visit(m)
			}
			n.flag = FlagPerm
			order = append(order, n)
		}
	}

	g.resetFlags()
	visit(g.root)
	return order
}

func routeToString(route []*node) (out string) {
	if len(route) == 0 {
		return "empty route"
	}

	for i, n := range route {
		if i == len(route)-1 {
			out += filepath.Base(n.path)
		} else {
			out += fmt.Sprintf("%s <- ", filepath.Base(n.path))
		}
	}
	return out
}

func findCycle(n *node, route []*node) (cycle []*node) {
	for _, child := range n.children {
		newRoute := append(route, n)

		if containsNode(newRoute, child) {
			return extractCycle(append(newRoute, child))
		}

		if cycle := findCycle(child, newRoute); cycle != nil {
			return cycle
		}
	}

	return nil
}

func containsNode(list []*node, goal *node) bool {
	for _, n := range list {
		if goal == n {
			return true
		}
	}

	return false
}

func extractCycle(route []*node) (cycle []*node) {
	for i := len(route) - 1; i >= 0; i-- {
		if len(cycle) > 0 && route[i] == cycle[0] {
			return append(cycle, route[i])
		}

		cycle = append(cycle, route[i])
	}

	return nil
}

func buildGraph(n *node, load func(string) (*node, error)) (g *graph, err error) {
	g = &graph{n, map[string]*node{}}
	done := map[string]*node{}
	todo := []*node{n}
	g.nodes[n.path] = n
	done[n.path] = n

	for len(todo) > 0 {
		n, todo = todo[0], todo[1:]
		for _, path := range getDependencyPaths(n) {
			if dep := done[path]; dep != nil {
				addParent(dep, n)
				addChild(n, dep)
			} else if dep := g.nodes[path]; dep != nil {
				addParent(dep, n)
				addChild(n, dep)
				addTodo(&todo, dep)
			} else if dep, err = load(path); err == nil {
				addParent(dep, n)
				addChild(n, dep)
				addTodo(&todo, dep)
				g.nodes[path] = dep
			} else {
				return nil, err
			}
		}
		addDone(done, n)
	}

	return g, nil
}

func getDependencyPaths(n *node) (paths []string) {
	for _, stmt := range n.ast.Stmts {
		if stmt, ok := stmt.(*parser.UseStmt); ok {
			dir := filepath.Dir(n.path)
			path := filepath.Join(dir, stmt.Path.Val)
			paths = append(paths, path)
		}
	}

	return paths
}

func addParent(child *node, parent *node) {
	child.parents = append(child.parents, parent)
}

func addChild(parent *node, child *node) {
	parent.children = append(parent.children, child)
}

func addTodo(todo *[]*node, n *node) {
	*todo = append(*todo, n)
}

func addDone(done map[string]*node, n *node) {
	done[n.path] = n
}

func loadDependency(path string) (n *node, err error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	ast, err := parser.Parse(path, string(buf))
	if err != nil {
		return nil, err
	}

	return makeNode(path, ast), nil
}

func makeNode(path string, ast *parser.Program) *node {
	return &node{
		path: path,
		ast:  ast,
		module: &Module{
			Name: path,
			AST:  ast,
		},
	}
}
<commit_msg>dependency-inject function for computing import branches<commit_after>package linker

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"plaid/parser"
)

type node struct {
	flag     int
	path     string
	ast      *parser.Program
	children []*node
	parents  []*node
	module   *Module
}

type graph struct {
	root  *node
	nodes map[string]*node
}

func (g *graph) resetFlags() {
	for _, n := range g.nodes {
		n.flag = 0
	}
}

// Link does some stuff
func Link(path string, ast *parser.Program, builtins ...*Module) (*Module, error) {
	order, err := resolve(path, ast)
	if err != nil {
		return nil, err
	}

	// Link ordered modules.
	for _, n := range order {
		for _, child := range n.children {
			n.module.Imports = append(n.module.Imports, child.module)
		}
	}

	return order[len(order)-1].module, nil
}

// resolve determines if a module has any dependency cycles
func resolve(path string, ast *parser.Program) ([]*node, error) {
	n := makeNode(path, ast)
	g, err := buildGraph(n, getDependencyPaths, loadDependency)
	if err != nil {
		return nil, err
	}

	if cycle := findCycle(g.root, nil); cycle != nil {
		return nil, fmt.Errorf("Dependency cycle: %s", routeToString(cycle))
	}

	order := orderDependencies(g)
	return order, nil
}

func nodesToModules(route []*node) (mods []*Module) {
	for _, n := range route {
		mod := n.module
		for _, dep := range n.children {
			if containsNode(route, dep) == false {

			}
		}
		mods = append(mods, mod)
	}
	return mods
}

func orderDependencies(g *graph) (order []*node) {
	const FlagTemp = 1
	const FlagPerm = 2

	var visit func(*node)
	visit = func(n *node) {
		if n.flag == FlagPerm {
			return
		} else if n.flag == FlagTemp {
			panic("not a DAG")
		} else {
			n.flag = FlagTemp
			for _, m := range n.children {
				visit(m)
			}
			n.flag = FlagPerm
			order = append(order, n)
		}
	}

	g.resetFlags()
	visit(g.root)
	return order
}

func routeToString(route []*node) (out string) {
	if len(route) == 0 {
		return "empty route"
	}

	for i, n := range route {
		if i == len(route)-1 {
			out += filepath.Base(n.path)
		} else {
			out += fmt.Sprintf("%s <- ", filepath.Base(n.path))
		}
	}
	return out
}

func findCycle(n *node, route []*node) (cycle []*node) {
	for _, child := range n.children {
		newRoute := append(route, n)

		if containsNode(newRoute, child) {
			return extractCycle(append(newRoute, child))
		}

		if cycle := findCycle(child, newRoute); cycle != nil {
			return cycle
		}
	}

	return nil
}

func containsNode(list []*node, goal *node) bool {
	for _, n := range list {
		if goal == n {
			return true
		}
	}

	return false
}

func extractCycle(route []*node) (cycle []*node) {
	for i := len(route) - 1; i >= 0; i-- {
		if len(cycle) > 0 && route[i] == cycle[0] {
			return append(cycle, route[i])
		}

		cycle = append(cycle, route[i])
	}

	return nil
}

func buildGraph(n *node, branch func(*node) []string, load func(string) (*node, error)) (g *graph, err error) {
	g = &graph{n, map[string]*node{}}
	done := map[string]*node{}
	todo := []*node{n}
	g.nodes[n.path] = n
	done[n.path] = n

	for len(todo) > 0 {
		n, todo = todo[0], todo[1:]
		for _, path := range branch(n) {
			if dep := done[path]; dep != nil {
				addParent(dep, n)
				addChild(n, dep)
			} else if dep := g.nodes[path]; dep != nil {
				addParent(dep, n)
				addChild(n, dep)
				addTodo(&todo, dep)
			} else if dep, err = load(path); err == nil {
				addParent(dep, n)
				addChild(n, dep)
				addTodo(&todo, dep)
				g.nodes[path] = dep
			} else {
				return nil, err
			}
		}
		addDone(done, n)
	}

	return g, nil
}

func getDependencyPaths(n *node) (paths []string) {
	for _, stmt := range n.ast.Stmts {
		if stmt, ok := stmt.(*parser.UseStmt); ok {
			dir := filepath.Dir(n.path)
			path := filepath.Join(dir, stmt.Path.Val)
			paths = append(paths, path)
		}
	}

	return paths
}

func addParent(child *node, parent *node) {
	child.parents = append(child.parents, parent)
}

func addChild(parent *node, child *node) {
	parent.children = append(parent.children, child)
}

func addTodo(todo *[]*node, n *node) {
	*todo = append(*todo, n)
}

func addDone(done map[string]*node, n *node) {
	done[n.path] = n
}

func loadDependency(path string) (n *node, err error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	ast, err := parser.Parse(path, string(buf))
	if err != nil {
		return nil, err
	}

	return makeNode(path, ast), nil
}

func makeNode(path string, ast *parser.Program) *node {
	return &node{
		path: path,
		ast:  ast,
		module: &Module{
			Name: path,
			AST:  ast,
		},
	}
}
<|endoftext|>


<commit_before>package sconsify

import (
	"bufio"
	"os"
	"strings"

	"github.com/mitchellh/go-homedir"
)

const SCONSIFY_CONF_LOCATION = "/.sconsify"

func GetCacheLocation() string {
	basePath := getConfLocation()
	if basePath != "" {
		return basePath + "/cache"
	}
	return ""
}

func DeleteCache(cacheLocation string) {
	if strings.HasSuffix(cacheLocation, SCONSIFY_CONF_LOCATION+"/cache") {
		os.RemoveAll(cacheLocation)
	}
}

func getConfLocation() string {
	dir, err := homedir.Dir()
	if err == nil {
		dir, err = homedir.Expand(dir)
		if err == nil && dir != "" {
			return dir + SCONSIFY_CONF_LOCATION
		}
	}
	return ""
}

func ProcessSconsifyrc() {
	basePath := getConfLocation()
	if basePath == "" {
		return
	}

	file, err := os.Open(basePath + "/sconsifyrc")
	if err != nil {
		return

	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.Trim(scanner.Text(), " ")
		key := line
		if index := strings.Index(line, "="); index > 0 {
			key = line[0:index]
		}
		contains := false
		for i, value := range os.Args {
			if i > 0 {
				if strings.HasPrefix(value, key) {
					contains = true
					break
				}
			}
		}

		if !contains {
			os.Args = append(os.Args, line)
		}
	}
}
<commit_msg>Polishing process sconsifyrc methods<commit_after>package sconsify

import (
	"bufio"
	"os"
	"strings"

	"github.com/mitchellh/go-homedir"
)

const SCONSIFY_CONF_LOCATION = "/.sconsify"

func GetCacheLocation() string {
	basePath := getConfLocation()
	if basePath != "" {
		return basePath + "/cache"
	}
	return ""
}

func DeleteCache(cacheLocation string) {
	if strings.HasSuffix(cacheLocation, SCONSIFY_CONF_LOCATION+"/cache") {
		os.RemoveAll(cacheLocation)
	}
}

func getConfLocation() string {
	dir, err := homedir.Dir()
	if err == nil {
		dir, err = homedir.Expand(dir)
		if err == nil && dir != "" {
			return dir + SCONSIFY_CONF_LOCATION
		}
	}
	return ""
}

func ProcessSconsifyrc() {
	basePath := getConfLocation()
	if basePath == "" {
		return
	}

	file, err := os.Open(basePath + "/sconsifyrc")
	if err != nil {
		return

	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		argument := strings.Trim(scanner.Text(), " ")
		argumentName := getOnlyArgumentName(argument)
		if !containsArgument(argumentName) {
			appendArgument(argument)
		}
	}
}

func getOnlyArgumentName(line string) string {
	if index := strings.Index(line, "="); index > 0 {
		return line[0:index]
	}
	return line
}

func containsArgument(argumentName string) bool {
	for i, value := range os.Args {
		if i > 0 {
			if strings.HasPrefix(value, argumentName) {
				return true
			}
		}
	}
	return false
}

func appendArgument(argument string) {
	os.Args = append(os.Args, argument)
}
<|endoftext|>


<commit_before>package falcore

import (
	"io"
	//"io/ioutil"
	"net/http"
	"strings"
	"bytes"
	"time"
)

// Keeps the body of a request in a string so it can be re-read at each stage of the pipeline
// implements io.ReadCloser to match http.Request.Body

type StringBody struct {
	BodyBuffer *bytes.Reader
	bpe *bufferPoolEntry
}

type StringBodyFilter struct {
	pool *bufferPool
}

func NewStringBodyFilter() *StringBodyFilter {
	sbf := &StringBodyFilter{}
	sbf.pool = newBufferPool(100, 1024)
	return sbf
}
func (sbf *StringBodyFilter) FilterRequest(request *Request) *http.Response {
	req := request.HttpRequest
	// This caches the request body so that multiple filters can iterate it
	if req.Method == "POST" || req.Method == "PUT" {
		sb, err := sbf.readRequestBody(req)
		if sb == nil || err != nil {
			request.CurrentStage.Status = 3 // Skip
			Debug("%s No Req Body or Ignored: %v", request.ID, err)
		}
	} else {
		request.CurrentStage.Status = 1 // Skip
	}
	return nil
}

// reads the request body and replaces the buffer with self
// returns nil if the body is multipart and not replaced
func (sbf *StringBodyFilter)readRequestBody(r *http.Request) (sb *StringBody, err error) {
	start := time.Now()
	ct := r.Header.Get("Content-Type")
	// leave it on the buffer if we're multipart
	if strings.SplitN(ct, ";", 2)[0] != "multipart/form-data" && r.ContentLength > 0 {
		sb = &StringBody{}
		const maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
		sb.bpe = sbf.pool.take(io.LimitReader(r.Body, maxFormSize+1))
		cumu := time.Since(start)
		Warn("C1: %v", cumu)
		b, e := sb.bpe.br.ReadBytes(0)
		cumu = time.Since(start)
		Warn("C2: %v", cumu)
		//Error("B: %v, E: %v\n", b, e)
		if e != nil && e != io.EOF {
			return nil, e
		}
		sb.BodyBuffer = bytes.NewReader(b)
		cumu = time.Since(start)
		Warn("C3: %v", cumu)
		go r.Body.Close()
		r.Body = sb
		cumu = time.Since(start)
		Warn("C4: %v", cumu)
		return sb, nil
	}
	return nil, nil // ignore
}

// Returns a buffer used in the FilterRequest stage to a buffer pool
// this speeds up this filter significantly by reusing buffers
func (sbf *StringBodyFilter)ReturnBuffer(request *Request) {
	if sb, ok := request.HttpRequest.Body.(*StringBody); ok {
		sbf.pool.give(sb.bpe)
	}
}

// Insert this in the response pipeline to return the buffer pool for the request body
// If there is an appropriate place in your flow, you can call ReturnBuffer explicitly
func (sbf *StringBodyFilter) FilterResponse(request *Request, res *http.Response) {
	sbf.ReturnBuffer(request)
}

func (sb *StringBody) Read(b []byte) (n int, err error) {
	return sb.BodyBuffer.Read(b)
}

func (sb *StringBody) Close() error {
	// start over
	sb.BodyBuffer.Seek(0, 0)
	return nil
}
<commit_msg>more debug<commit_after>package falcore

import (
	"io"
	//"io/ioutil"
	"net/http"
	"strings"
	"bytes"
	"time"
)

// Keeps the body of a request in a string so it can be re-read at each stage of the pipeline
// implements io.ReadCloser to match http.Request.Body

type StringBody struct {
	BodyBuffer *bytes.Reader
	bpe *bufferPoolEntry
}

type StringBodyFilter struct {
	pool *bufferPool
}

func NewStringBodyFilter() *StringBodyFilter {
	sbf := &StringBodyFilter{}
	sbf.pool = newBufferPool(100, 1024)
	return sbf
}
func (sbf *StringBodyFilter) FilterRequest(request *Request) *http.Response {
	req := request.HttpRequest
	// This caches the request body so that multiple filters can iterate it
	if req.Method == "POST" || req.Method == "PUT" {
		sb, err := sbf.readRequestBody(req)
		if sb == nil || err != nil {
			request.CurrentStage.Status = 3 // Skip
			Debug("%s No Req Body or Ignored: %v", request.ID, err)
		}
	} else {
		request.CurrentStage.Status = 1 // Skip
	}
	return nil
}

// reads the request body and replaces the buffer with self
// returns nil if the body is multipart and not replaced
func (sbf *StringBodyFilter)readRequestBody(r *http.Request) (sb *StringBody, err error) {
	start := time.Now()
	ct := r.Header.Get("Content-Type")
	// leave it on the buffer if we're multipart
	if strings.SplitN(ct, ";", 2)[0] != "multipart/form-data" && r.ContentLength > 0 {
		sb = &StringBody{}
		const maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
		//rr := io.LimitReader(r.Body, maxFormSize+1)
		rr := r.Body
		sb.bpe = sbf.pool.take(rr)
		cumu := time.Since(start)
		Warn("C1: %v", cumu)
		b, e := sb.bpe.br.ReadBytes(0)
		cumu = time.Since(start)
		Warn("C2: %v", cumu)
		//Error("B: %v, E: %v\n", b, e)
		if e != nil && e != io.EOF {
			return nil, e
		}
		sb.BodyBuffer = bytes.NewReader(b)
		cumu = time.Since(start)
		Warn("C3: %v", cumu)
		go r.Body.Close()
		r.Body = sb
		cumu = time.Since(start)
		Warn("C4: %v", cumu)
		return sb, nil
	}
	return nil, nil // ignore
}

// Returns a buffer used in the FilterRequest stage to a buffer pool
// this speeds up this filter significantly by reusing buffers
func (sbf *StringBodyFilter)ReturnBuffer(request *Request) {
	if sb, ok := request.HttpRequest.Body.(*StringBody); ok {
		sbf.pool.give(sb.bpe)
	}
}

// Insert this in the response pipeline to return the buffer pool for the request body
// If there is an appropriate place in your flow, you can call ReturnBuffer explicitly
func (sbf *StringBodyFilter) FilterResponse(request *Request, res *http.Response) {
	sbf.ReturnBuffer(request)
}

func (sb *StringBody) Read(b []byte) (n int, err error) {
	return sb.BodyBuffer.Read(b)
}

func (sb *StringBody) Close() error {
	// start over
	sb.BodyBuffer.Seek(0, 0)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/mopsalarm/go-pr0gramm"
	"github.com/rcrowley/go-metrics"
)

func UpdateAll(db *sql.DB) error {
	return pr0gramm.StreamPaged(pr0gramm.NewItemsRequest(), func(items []pr0gramm.Item) (bool, error) {
		writeItems(db, items)
		time.Sleep(10 * time.Second)
		return true, nil
	})
}

func Update(db *sql.DB, maxItemAge time.Duration) {
	logrus.WithField("max-age", maxItemAge).Info("Updating items now")

	var items []pr0gramm.Item
	err := pr0gramm.Stream(pr0gramm.NewItemsRequest(), pr0gramm.ConsumeIf(
		func(item pr0gramm.Item) bool {
			return time.Since(item.Created.Time).Seconds() < maxItemAge.Seconds()
		},
		func(item pr0gramm.Item) error {
			items = append(items, item)
			return nil
		}))

	if err != nil {
		logrus.WithError(err).Warn("Could not fetch all items")
	}

	if len(items) == 0 {
		return
	}

	writeItems(db, items)
}
func writeItems(db *sql.DB, items []pr0gramm.Item) {
	tx, err := db.Begin()
	if err != nil {
		logrus.WithError(err).Warn("Could not open transction")
		return
	}

	defer tx.Commit()

	statement, err := tx.Prepare(`INSERT INTO items
		(id, promoted,up, down, created, image, thumb, fullsize, source, flags, username, mark, width, height, audio)
		VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
		ON CONFLICT (id) DO UPDATE SET up=EXCLUDED.up, down=EXCLUDED.down`)

	if err != nil {
		logrus.WithError(err).Warn("Could not prepare insert statement")
		return
	}

	defer statement.Close()

	start := time.Now()
	logrus.WithField("count", len(items)).Info("Writing items to database")
	for _, item := range items {
		_, err := statement.Exec(
			uint64(item.Id), uint64(item.Promoted),
			item.Up, item.Down,
			item.Created.Time.Unix(),
			item.Image, item.Thumbnail, item.Fullsize, item.Source,
			item.Flags, item.User, item.Mark, item.Width, item.Height, item.Audio)

		if err != nil {
			logrus.WithError(err).Warn("Could not insert item into database, skipping.")
		} else {
			metrics.GetOrRegisterMeter("pr0gramm.meta.items.inserted", nil).Mark(1)
		}
	}

	logrus.
		WithField("duration", time.Since(start)).
		WithField("count", len(items)).
		Info("Finished writing items")
}
<commit_msg>Update promoted id and mark on update<commit_after>package main

import (
	"database/sql"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/mopsalarm/go-pr0gramm"
	"github.com/rcrowley/go-metrics"
)

func UpdateAll(db *sql.DB) error {
	return pr0gramm.StreamPaged(pr0gramm.NewItemsRequest(), func(items []pr0gramm.Item) (bool, error) {
		writeItems(db, items)
		time.Sleep(10 * time.Second)
		return true, nil
	})
}

func Update(db *sql.DB, maxItemAge time.Duration) {
	logrus.WithField("max-age", maxItemAge).Info("Updating items now")

	var items []pr0gramm.Item
	err := pr0gramm.Stream(pr0gramm.NewItemsRequest(), pr0gramm.ConsumeIf(
		func(item pr0gramm.Item) bool {
			return time.Since(item.Created.Time).Seconds() < maxItemAge.Seconds()
		},
		func(item pr0gramm.Item) error {
			items = append(items, item)
			return nil
		}))

	if err != nil {
		logrus.WithError(err).Warn("Could not fetch all items")
	}

	if len(items) == 0 {
		return
	}

	writeItems(db, items)
}
func writeItems(db *sql.DB, items []pr0gramm.Item) {
	tx, err := db.Begin()
	if err != nil {
		logrus.WithError(err).Warn("Could not open transction")
		return
	}

	defer tx.Commit()

	statement, err := tx.Prepare(`INSERT INTO items
		(id, promoted, up, down, created, image, thumb, fullsize, source, flags, username, mark, width, height, audio)
		VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15)
		ON CONFLICT (id) DO UPDATE SET up=EXCLUDED.up, down=EXCLUDED.down, promoted=EXCLUDED.promoted, mark=EXCLUDED.mark`)

	if err != nil {
		logrus.WithError(err).Warn("Could not prepare insert statement")
		return
	}

	defer statement.Close()

	start := time.Now()
	logrus.WithField("count", len(items)).Info("Writing items to database")
	for _, item := range items {
		_, err := statement.Exec(
			uint64(item.Id), uint64(item.Promoted),
			item.Up, item.Down,
			item.Created.Time.Unix(),
			item.Image, item.Thumbnail, item.Fullsize, item.Source,
			item.Flags, item.User, item.Mark, item.Width, item.Height, item.Audio)

		if err != nil {
			logrus.WithError(err).Warn("Could not insert item into database, skipping.")
		} else {
			metrics.GetOrRegisterMeter("pr0gramm.meta.items.inserted", nil).Mark(1)
		}
	}

	logrus.
		WithField("duration", time.Since(start)).
		WithField("count", len(items)).
		Info("Finished writing items")
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// Read static host/IP entries from /etc/hosts.

package net

import (
	"sync"
	"time"
)

const cacheMaxAge = 5 * time.Minute

// hostsPath points to the file with static IP/address entries.
var hostsPath = "/etc/hosts"

// Simple cache.
var hosts struct {
	sync.Mutex
	byName map[string][]string
	byAddr map[string][]string
	expire time.Time
	path   string
}

func readHosts() {
	now := time.Now()
	hp := hostsPath
	if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
		hs := make(map[string][]string)
		is := make(map[string][]string)
		var file *file
		if file, _ = open(hp); file == nil {
			return
		}
		for line, ok := file.readLine(); ok; line, ok = file.readLine() {
			if i := byteIndex(line, '#'); i >= 0 {
				// Discard comments.
				line = line[0:i]
			}
			f := getFields(line)
			if len(f) < 2 || ParseIP(f[0]) == nil {
				continue
			}
			for i := 1; i < len(f); i++ {
				h := f[i]
				hs[h] = append(hs[h], f[0])
				is[f[0]] = append(is[f[0]], h)
			}
		}
		// Update the data cache.
		hosts.expire = time.Now().Add(cacheMaxAge)
		hosts.path = hp
		hosts.byName = hs
		hosts.byAddr = is
		file.close()
	}
}

// lookupStaticHost looks up the addresses for the given host from /etc/hosts.
func lookupStaticHost(host string) []string {
	hosts.Lock()
	defer hosts.Unlock()
	readHosts()
	if len(hosts.byName) != 0 {
		if ips, ok := hosts.byName[host]; ok {
			return ips
		}
	}
	return nil
}

// lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
func lookupStaticAddr(addr string) []string {
	hosts.Lock()
	defer hosts.Unlock()
	readHosts()
	if len(hosts.byAddr) != 0 {
		if hosts, ok := hosts.byAddr[addr]; ok {
			return hosts
		}
	}
	return nil
}
<commit_msg>net: do not call time.Now() twice<commit_after>// Copyright 2009 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.

// Read static host/IP entries from /etc/hosts.

package net

import (
	"sync"
	"time"
)

const cacheMaxAge = 5 * time.Minute

// hostsPath points to the file with static IP/address entries.
var hostsPath = "/etc/hosts"

// Simple cache.
var hosts struct {
	sync.Mutex
	byName map[string][]string
	byAddr map[string][]string
	expire time.Time
	path   string
}

func readHosts() {
	now := time.Now()
	hp := hostsPath
	if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
		hs := make(map[string][]string)
		is := make(map[string][]string)
		var file *file
		if file, _ = open(hp); file == nil {
			return
		}
		for line, ok := file.readLine(); ok; line, ok = file.readLine() {
			if i := byteIndex(line, '#'); i >= 0 {
				// Discard comments.
				line = line[0:i]
			}
			f := getFields(line)
			if len(f) < 2 || ParseIP(f[0]) == nil {
				continue
			}
			for i := 1; i < len(f); i++ {
				h := f[i]
				hs[h] = append(hs[h], f[0])
				is[f[0]] = append(is[f[0]], h)
			}
		}
		// Update the data cache.
		hosts.expire = now.Add(cacheMaxAge)
		hosts.path = hp
		hosts.byName = hs
		hosts.byAddr = is
		file.close()
	}
}

// lookupStaticHost looks up the addresses for the given host from /etc/hosts.
func lookupStaticHost(host string) []string {
	hosts.Lock()
	defer hosts.Unlock()
	readHosts()
	if len(hosts.byName) != 0 {
		if ips, ok := hosts.byName[host]; ok {
			return ips
		}
	}
	return nil
}

// lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
func lookupStaticAddr(addr string) []string {
	hosts.Lock()
	defer hosts.Unlock()
	readHosts()
	if len(hosts.byAddr) != 0 {
		if hosts, ok := hosts.byAddr[addr]; ok {
			return hosts
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2009 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 sync

import (
	"sync/atomic"
)

// Once is an object that will perform exactly one action.
type Once struct {
	m    Mutex
	done int32
}

// Do calls the function f if and only if the method is being called for the
// first time with this receiver.  In other words, given
// 	var once Once
// if once.Do(f) is called multiple times, only the first call will invoke f,
// even if f has a different value in each invocation.  A new instance of
// Once is required for each function to execute.
//
// Do is intended for initialization that must be run exactly once.  Since f
// is niladic, it may be necessary to use a function literal to capture the
// arguments to a function to be invoked by Do:
// 	config.once.Do(func() { config.init(filename) })
//
// Because no call to Do returns until the one call to f returns, if f causes
// Do to be called, it will deadlock.
//
func (o *Once) Do(f func()) {
	if atomic.AddInt32(&o.done, 0) == 1 {
		return
	}
	// Slow-path.
	o.m.Lock()
	defer o.m.Unlock()
	if o.done == 0 {
		f()
		atomic.CompareAndSwapInt32(&o.done, 0, 1)
	}
}
<commit_msg>sync: improve Once fast path Use atomic.LoadUint32(&done) instead of atomic.AddInt32(&done, 0) on fast path.<commit_after>// Copyright 2009 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 sync

import (
	"sync/atomic"
)

// Once is an object that will perform exactly one action.
type Once struct {
	m    Mutex
	done uint32
}

// Do calls the function f if and only if the method is being called for the
// first time with this receiver.  In other words, given
// 	var once Once
// if once.Do(f) is called multiple times, only the first call will invoke f,
// even if f has a different value in each invocation.  A new instance of
// Once is required for each function to execute.
//
// Do is intended for initialization that must be run exactly once.  Since f
// is niladic, it may be necessary to use a function literal to capture the
// arguments to a function to be invoked by Do:
// 	config.once.Do(func() { config.init(filename) })
//
// Because no call to Do returns until the one call to f returns, if f causes
// Do to be called, it will deadlock.
//
func (o *Once) Do(f func()) {
	if atomic.LoadUint32(&o.done) == 1 {
		return
	}
	// Slow-path.
	o.m.Lock()
	defer o.m.Unlock()
	if o.done == 0 {
		f()
		atomic.CompareAndSwapUint32(&o.done, 0, 1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 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 time

import (
	"os"
	"sync"
)

// A Ticker holds a synchronous channel that delivers `ticks' of a clock
// at intervals.
type Ticker struct {
	C        <-chan int64 // The channel on which the ticks are delivered.
	c        chan<- int64 // The same channel, but the end we use.
	ns       int64
	shutdown chan bool // Buffered channel used to signal shutdown.
	nextTick int64
	next     *Ticker
}

// Stop turns off a ticker.  After Stop, no more ticks will be sent.
func (t *Ticker) Stop() {
	// Make it non-blocking so multiple Stops don't block.
	_ = t.shutdown <- true
}

// Tick is a convenience wrapper for NewTicker providing access to the ticking
// channel only.  Useful for clients that have no need to shut down the ticker.
func Tick(ns int64) <-chan int64 {
	if ns <= 0 {
		return nil
	}
	return NewTicker(ns).C
}

type alarmer struct {
	wakeUp   chan bool // wakeup signals sent/received here
	wakeMeAt chan int64
	wakeTime int64
}

// Set alarm to go off at time ns, if not already set earlier.
func (a *alarmer) set(ns int64) {
	switch {
	case a.wakeTime > ns:
		// Next tick we expect is too late; shut down the late runner
		// and (after fallthrough) start a new wakeLoop.
		a.wakeMeAt <- -1
		fallthrough
	case a.wakeMeAt == nil:
		// There's no wakeLoop, start one.
		a.wakeMeAt = make(chan int64, 10)
		go wakeLoop(a.wakeMeAt, a.wakeUp)
		fallthrough
	case a.wakeTime == 0:
		// Nobody else is waiting; it's just us.
		a.wakeTime = ns
		a.wakeMeAt <- ns
	default:
		// There's already someone scheduled.
	}
}

// Channel to notify tickerLoop of new Tickers being created.
var newTicker chan *Ticker

func startTickerLoop() {
	newTicker = make(chan *Ticker)
	go tickerLoop()
}

// wakeLoop delivers ticks at scheduled times, sleeping until the right moment.
// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new
// wakeLoop but they will share the wakeUp channel and signal that this one
// is done by giving it a negative time request.
func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
	for {
		wakeAt := <-wakeMeAt
		if wakeAt < 0 { // tickerLoop has started another wakeLoop
			return
		}
		now := Nanoseconds()
		if wakeAt > now {
			Sleep(wakeAt - now)
			now = Nanoseconds()
		}
		wakeUp <- true
	}
}

// A single tickerLoop serves all ticks to Tickers.  It waits for two events:
// either the creation of a new Ticker or a tick from the alarm,
// signalling a time to wake up one or more Tickers.
func tickerLoop() {
	// Represents the next alarm to be delivered.
	var alarm alarmer
	// All wakeLoops deliver wakeups to this channel.
	alarm.wakeUp = make(chan bool, 10)
	var now, prevTime, wakeTime int64
	var tickers *Ticker
	for {
		select {
		case t := <-newTicker:
			// Add Ticker to list
			t.next = tickers
			tickers = t
			// Arrange for a new alarm if this one precedes the existing one.
			alarm.set(t.nextTick)
		case <-alarm.wakeUp:
			now = Nanoseconds()
			// Ignore an old time due to a dying wakeLoop
			if now < prevTime {
				continue
			}
			wakeTime = now + 1e15 // very long in the future
			var prev *Ticker = nil
			// Scan list of tickers, delivering updates to those
			// that need it and determining the next wake time.
			// TODO(r): list should be sorted in time order.
			for t := tickers; t != nil; t = t.next {
				if _, ok := <-t.shutdown; ok {
					// Ticker is done; remove it from list.
					if prev == nil {
						tickers = t.next
					} else {
						prev.next = t.next
					}
					continue
				}
				if t.nextTick <= now {
					if len(t.c) == 0 {
						// Only send if there's room.  We must not block.
						// The channel is allocated with a one-element
						// buffer, which is sufficient: if he hasn't picked
						// up the last tick, no point in sending more.
						t.c <- now
					}
					t.nextTick += t.ns
					if t.nextTick <= now {
						// Still behind; advance in one big step.
						t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns
					}
				}
				if t.nextTick < wakeTime {
					wakeTime = t.nextTick
				}
				prev = t
			}
			if tickers != nil {
				// Please send wakeup at earliest required time.
				// If there are no tickers, don't bother.
				alarm.wakeMeAt <- wakeTime
			} else {
				alarm.wakeTime = 0
			}
		}
		prevTime = now
	}
}

var onceStartTickerLoop sync.Once

// NewTicker returns a new Ticker containing a channel that will
// send the time, in nanoseconds, every ns nanoseconds.  It adjusts the
// intervals to make up for pauses in delivery of the ticks. The value of
// ns must be greater than zero; if not, NewTicker will panic.
func NewTicker(ns int64) *Ticker {
	if ns <= 0 {
		panic(os.ErrorString("non-positive interval for NewTicker"))
	}
	c := make(chan int64, 1) //  See comment on send in tickerLoop
	t := &Ticker{
		C:        c,
		c:        c,
		ns:       ns,
		shutdown: make(chan bool, 1),
		nextTick: Nanoseconds() + ns,
	}
	onceStartTickerLoop.Do(startTickerLoop)
	// must be run in background so global Tickers can be created
	go func() { newTicker <- t }()
	return t
}
<commit_msg>time: fix tick accuracy when using multiple Tickers<commit_after>// Copyright 2009 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 time

import (
	"os"
	"sync"
)

// A Ticker holds a synchronous channel that delivers `ticks' of a clock
// at intervals.
type Ticker struct {
	C        <-chan int64 // The channel on which the ticks are delivered.
	c        chan<- int64 // The same channel, but the end we use.
	ns       int64
	shutdown chan bool // Buffered channel used to signal shutdown.
	nextTick int64
	next     *Ticker
}

// Stop turns off a ticker.  After Stop, no more ticks will be sent.
func (t *Ticker) Stop() {
	// Make it non-blocking so multiple Stops don't block.
	_ = t.shutdown <- true
}

// Tick is a convenience wrapper for NewTicker providing access to the ticking
// channel only.  Useful for clients that have no need to shut down the ticker.
func Tick(ns int64) <-chan int64 {
	if ns <= 0 {
		return nil
	}
	return NewTicker(ns).C
}

type alarmer struct {
	wakeUp   chan bool // wakeup signals sent/received here
	wakeMeAt chan int64
	wakeTime int64
}

// Set alarm to go off at time ns, if not already set earlier.
func (a *alarmer) set(ns int64) {
	switch {
	case a.wakeTime > ns:
		// Next tick we expect is too late; shut down the late runner
		// and (after fallthrough) start a new wakeLoop.
		close(a.wakeMeAt)
		fallthrough
	case a.wakeMeAt == nil:
		// There's no wakeLoop, start one.
		a.wakeMeAt = make(chan int64)
		a.wakeUp = make(chan bool, 1)
		go wakeLoop(a.wakeMeAt, a.wakeUp)
		fallthrough
	case a.wakeTime == 0:
		// Nobody else is waiting; it's just us.
		a.wakeTime = ns
		a.wakeMeAt <- ns
	default:
		// There's already someone scheduled.
	}
}

// Channel to notify tickerLoop of new Tickers being created.
var newTicker chan *Ticker

func startTickerLoop() {
	newTicker = make(chan *Ticker)
	go tickerLoop()
}

// wakeLoop delivers ticks at scheduled times, sleeping until the right moment.
// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new
// wakeLoop and signal that this one is done by closing the wakeMeAt channel.
func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
	for wakeAt := range wakeMeAt {
		Sleep(wakeAt - Nanoseconds())
		wakeUp <- true
	}
}

// A single tickerLoop serves all ticks to Tickers.  It waits for two events:
// either the creation of a new Ticker or a tick from the alarm,
// signalling a time to wake up one or more Tickers.
func tickerLoop() {
	// Represents the next alarm to be delivered.
	var alarm alarmer
	var now, wakeTime int64
	var tickers *Ticker
	for {
		select {
		case t := <-newTicker:
			// Add Ticker to list
			t.next = tickers
			tickers = t
			// Arrange for a new alarm if this one precedes the existing one.
			alarm.set(t.nextTick)
		case <-alarm.wakeUp:
			now = Nanoseconds()
			wakeTime = now + 1e15 // very long in the future
			var prev *Ticker = nil
			// Scan list of tickers, delivering updates to those
			// that need it and determining the next wake time.
			// TODO(r): list should be sorted in time order.
			for t := tickers; t != nil; t = t.next {
				if _, ok := <-t.shutdown; ok {
					// Ticker is done; remove it from list.
					if prev == nil {
						tickers = t.next
					} else {
						prev.next = t.next
					}
					continue
				}
				if t.nextTick <= now {
					if len(t.c) == 0 {
						// Only send if there's room.  We must not block.
						// The channel is allocated with a one-element
						// buffer, which is sufficient: if he hasn't picked
						// up the last tick, no point in sending more.
						t.c <- now
					}
					t.nextTick += t.ns
					if t.nextTick <= now {
						// Still behind; advance in one big step.
						t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns
					}
				}
				if t.nextTick < wakeTime {
					wakeTime = t.nextTick
				}
				prev = t
			}
			if tickers != nil {
				// Please send wakeup at earliest required time.
				// If there are no tickers, don't bother.
				alarm.wakeTime = wakeTime
				alarm.wakeMeAt <- wakeTime
			} else {
				alarm.wakeTime = 0
			}
		}
	}
}

var onceStartTickerLoop sync.Once

// NewTicker returns a new Ticker containing a channel that will
// send the time, in nanoseconds, every ns nanoseconds.  It adjusts the
// intervals to make up for pauses in delivery of the ticks. The value of
// ns must be greater than zero; if not, NewTicker will panic.
func NewTicker(ns int64) *Ticker {
	if ns <= 0 {
		panic(os.ErrorString("non-positive interval for NewTicker"))
	}
	c := make(chan int64, 1) //  See comment on send in tickerLoop
	t := &Ticker{
		C:        c,
		c:        c,
		ns:       ns,
		shutdown: make(chan bool, 1),
		nextTick: Nanoseconds() + ns,
	}
	onceStartTickerLoop.Do(startTickerLoop)
	// must be run in background so global Tickers can be created
	go func() { newTicker <- t }()
	return t
}
<|endoftext|>


<commit_before>package loggly

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/gliderlabs/logspout/router"
)

const (
	adapterName         = "loggly"
	logglyTokenEnvVar   = "LOGGLY_TOKEN"
	logglyTagsEnvVar    = "LOGGLY_TAGS"
	logglyTagsHeader    = "X-LOGGLY-TAG"
	logglyAddr          = "https://logs-01.loggly.com"
	logglyEventEndpoint = "/inputs"
)

// TODO: consider logging all fatals to loggly

func init() {
	router.AdapterFactories.Register(NewLogglyAdapter, adapterName)

	r := &router.Route{
		Adapter: "loggly",
	}

	// It's not documented in the logspout repo but if you want to use an adapter
	// without going through the routesapi you must add at #init or via #New...
	err := router.Routes.Add(r)
	if err != nil {
		log.Fatal("Could not add route: ", err.Error())
	}
}

// NewLogglyAdapter returns an Adapter with that uses a loggly token taken from
// the LOGGLY_TOKEN environment variable
func NewLogglyAdapter(route *router.Route) (router.LogAdapter, error) {
	token := os.Getenv(logglyTokenEnvVar)

	if token == "" {
		return nil, errors.New("Could not find environment variable LOGGLY_TOKEN")
	}

	return &Adapter{
		token:  token,
		client: http.Client{},
		tags:   os.Getenv(logglyTagsEnvVar),
	}, nil
}

// Adapter satisfies the router.LogAdapter interface by providing Stream which
// passes all messages to loggly.
type Adapter struct {
	token  string
	client http.Client
	tags   string
}

// Stream satisfies the router.LogAdapter interface and passes all messages to
// Loggly
func (l *Adapter) Stream(logstream chan *router.Message) {
	for m := range logstream {
		msg := logglyMessage{
			Message:           m.Data,
			ContainerName:     m.Container.Name,
			ContainerID:       m.Container.ID,
			ContainerImage:    m.Container.Config.Image,
			ContainerHostname: m.Container.Config.Hostname,
		}

		err := l.SendMessage(msg)

		if err != nil {
			log.Println(err.Error())
		}
	}
}

// SendMessage handles creating and sending a request to Loggly. Any errors
// that occur during that process are bubbled up to the caller
func (l *Adapter) SendMessage(msg logglyMessage) error {
	js, err := json.Marshal(msg)

	if err != nil {
		return err
	}

	url := fmt.Sprintf("%s%s/%s", logglyAddr, logglyEventEndpoint, l.token)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(js))

	if l.tags != "" {
		req.Header.Add(logglyTagsHeader, l.tags)
	}

	if err != nil {
		return err
	}

	// TODO: possibly use pool of workers to send requests?
	resp, err := l.client.Do(req)

	if err != nil {
		errMsg := fmt.Sprintf("Error from client: %s", err.Error())
		return errors.New(errMsg)
	}

	if resp.StatusCode != http.StatusOK {
		errMsg := fmt.Sprintf("Received a non 200 status code: %s", err.Error())
		return errors.New(errMsg)
	}

	return nil
}

type logglyMessage struct {
	Message           string `json:"message"`
	ContainerName     string `json:"container_name"`
	ContainerID       string `json:"container_id"`
	ContainerImage    string `json:"container_image"`
	ContainerHostname string `json:"hostname"`
}
<commit_msg>format error messages in the standard Golang style<commit_after>package loggly

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/gliderlabs/logspout/router"
)

const (
	adapterName         = "loggly"
	logglyTokenEnvVar   = "LOGGLY_TOKEN"
	logglyTagsEnvVar    = "LOGGLY_TAGS"
	logglyTagsHeader    = "X-LOGGLY-TAG"
	logglyAddr          = "https://logs-01.loggly.com"
	logglyEventEndpoint = "/inputs"
)

// TODO: consider logging all fatals to loggly

func init() {
	router.AdapterFactories.Register(NewLogglyAdapter, adapterName)

	r := &router.Route{
		Adapter: "loggly",
	}

	// It's not documented in the logspout repo but if you want to use an adapter
	// without going through the routesapi you must add at #init or via #New...
	err := router.Routes.Add(r)
	if err != nil {
		log.Fatal("Could not add route: ", err.Error())
	}
}

// NewLogglyAdapter returns an Adapter with that uses a loggly token taken from
// the LOGGLY_TOKEN environment variable
func NewLogglyAdapter(route *router.Route) (router.LogAdapter, error) {
	token := os.Getenv(logglyTokenEnvVar)

	if token == "" {
		return nil, errors.New("Could not find environment variable LOGGLY_TOKEN")
	}

	return &Adapter{
		token:  token,
		client: http.Client{},
		tags:   os.Getenv(logglyTagsEnvVar),
	}, nil
}

// Adapter satisfies the router.LogAdapter interface by providing Stream which
// passes all messages to loggly.
type Adapter struct {
	token  string
	client http.Client
	tags   string
}

// Stream satisfies the router.LogAdapter interface and passes all messages to
// Loggly
func (l *Adapter) Stream(logstream chan *router.Message) {
	for m := range logstream {
		msg := logglyMessage{
			Message:           m.Data,
			ContainerName:     m.Container.Name,
			ContainerID:       m.Container.ID,
			ContainerImage:    m.Container.Config.Image,
			ContainerHostname: m.Container.Config.Hostname,
		}

		err := l.SendMessage(msg)

		if err != nil {
			log.Println(err.Error())
		}
	}
}

// SendMessage handles creating and sending a request to Loggly. Any errors
// that occur during that process are bubbled up to the caller
func (l *Adapter) SendMessage(msg logglyMessage) error {
	js, err := json.Marshal(msg)

	if err != nil {
		return err
	}

	url := fmt.Sprintf("%s%s/%s", logglyAddr, logglyEventEndpoint, l.token)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(js))

	if err != nil {
		return err
	}

	if l.tags != "" {
		req.Header.Add(logglyTagsHeader, l.tags)
	}

	// TODO: possibly use pool of workers to send requests?
	resp, err := l.client.Do(req)

	if err != nil {
		return fmt.Errorf(
			"error from client: %s",
			err.Error(),
		)
	}

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf(
			"received a non 200 status code when sending message to loggly: %s",
			err.Error(),
		)
	}

	return nil
}

type logglyMessage struct {
	Message           string `json:"message"`
	ContainerName     string `json:"container_name"`
	ContainerID       string `json:"container_id"`
	ContainerImage    string `json:"container_image"`
	ContainerHostname string `json:"hostname"`
}
<|endoftext|>


<commit_before>package elasticsearch

import (
	"errors"
	"fmt"
	"strings"

	log "github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
	"gopkg.in/olivere/elastic.v2"
)

const illegalCharacters = "[:,?<>/\\*?| ]"

type ESClient struct {
	client *elastic.Client
	index  string
	typ    string
}

func NewESClient(url string) (*ESClient, error) {
	client, err := elastic.NewSimpleClient(elastic.SetURL(url))
	if err != nil {
		return nil, err
	}

	return &ESClient{client, "", ""}, nil
}

func (esc *ESClient) Initialize(index, typ string) error {
	if strings.ContainsAny(index, illegalCharacters) {
		return errors.New(fmt.Sprintf("Index name contains illegal characters (%s)", index))
	}
	esc.index = index
	if strings.ContainsAny(typ, illegalCharacters) {
		return errors.New(fmt.Sprintf("Type contains illegal characters (%s)", typ))
	}
	esc.typ = typ

	return nil
}

func (esc *ESClient) Index(doc string) error {

	response, err := esc.client.Index().
		Index(esc.index).
		Type(esc.typ).
		BodyString(doc).
		Refresh("true").
		Do(context.Background())
	if err != nil {
		log.Errorf("Failed indexing document %s for index %s. %+v", doc, esc.index, err)
	} else {
		log.Infof("Indexed document ID: %s into index name: %s", response.Id, response.Index)
	}

	return err
}
<commit_msg>revert;<commit_after>package elasticsearch

import (
	"errors"
	"fmt"
	"strings"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/olivere/elastic.v2"
)

const illegalCharacters = "[:,?<>/\\*?| ]"

type ESClient struct {
	client *elastic.Client
	index  string
	typ    string
}

func NewESClient(url string) (*ESClient, error) {
	client, err := elastic.NewSimpleClient(elastic.SetURL(url))
	if err != nil {
		return nil, err
	}

	return &ESClient{client, "", ""}, nil
}

func (esc *ESClient) Initialize(index, typ string) error {
	if strings.ContainsAny(index, illegalCharacters) {
		return errors.New(fmt.Sprintf("Index name contains illegal characters (%s)", index))
	}
	esc.index = index
	if strings.ContainsAny(typ, illegalCharacters) {
		return errors.New(fmt.Sprintf("Type contains illegal characters (%s)", typ))
	}
	esc.typ = typ

	return nil
}

func (esc *ESClient) Index(doc string) error {

	response, err := esc.client.Index().
		Index(esc.index).
		Type(esc.typ).
		BodyString(doc).
		Refresh(true).
		Do()
	if err != nil {
		log.Errorf("Failed indexing document %s for index %s. %+v", doc, esc.index, err)
	} else {
		log.Infof("Indexed document ID: %s into index name: %s", response.Id, response.Index)
	}

	return err
}
<|endoftext|>