<commit_before>package datasource

import (
	"strings"
	"time"

	"github.com/alexanderzobnin/grafana-zabbix/pkg/timeseries"

	"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
	"github.com/grafana/grafana-plugin-sdk-go/backend"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"golang.org/x/net/context"
)

// ZabbixAPIQuery handles query requests to Zabbix API
func (ds *ZabbixDatasourceInstance) ZabbixAPIQuery(ctx context.Context, apiReq *zabbix.ZabbixAPIRequest) (*ZabbixAPIResourceResponse, error) {
	resultJson, err := ds.zabbix.Request(ctx, apiReq)
	if err != nil {
		return nil, err
	}
	result := resultJson.Interface()
	return BuildAPIResponse(&result)
}

func BuildAPIResponse(responseData *interface{}) (*ZabbixAPIResourceResponse, error) {
	return &ZabbixAPIResourceResponse{
		Result: *responseData,
	}, nil
}

// TestConnection checks authentication and version of the Zabbix API and returns that info
func (ds *ZabbixDatasourceInstance) TestConnection(ctx context.Context) (string, error) {
	_, err := ds.zabbix.GetAllGroups(ctx)
	if err != nil {
		return "", err
	}

	response, err := ds.zabbix.Request(ctx, &zabbix.ZabbixAPIRequest{Method: "apiinfo.version"})
	if err != nil {
		return "", err
	}

	resultByte, _ := response.MarshalJSON()
	return string(resultByte), nil
}

func (ds *ZabbixDatasourceInstance) queryNumericItems(ctx context.Context, query *QueryModel) ([]*data.Frame, error) {
	groupFilter := query.Group.Filter
	hostFilter := query.Host.Filter
	appFilter := query.Application.Filter
	itemTagFilter := query.ItemTag.Filter
	itemFilter := query.Item.Filter

	items, err := ds.zabbix.GetItems(ctx, groupFilter, hostFilter, appFilter, itemTagFilter, itemFilter, "num")
	if err != nil {
		return nil, err
	}

	frames, err := ds.queryNumericDataForItems(ctx, query, items)
	if err != nil {
		return nil, err
	}

	return frames, nil
}

func (ds *ZabbixDatasourceInstance) queryItemIdData(ctx context.Context, query *QueryModel) ([]*data.Frame, error) {
	itemids := strings.Split(query.ItemIDs, ",")
	for i, id := range itemids {
		itemids[i] = strings.Trim(id, " ")
	}

	items, err := ds.zabbix.GetItemsByIDs(ctx, itemids)
	if err != nil {
		return nil, err
	}

	frames, err := ds.queryNumericDataForItems(ctx, query, items)
	if err != nil {
		return nil, err
	}

	return frames, nil
}

func (ds *ZabbixDatasourceInstance) queryNumericDataForItems(ctx context.Context, query *QueryModel, items []*zabbix.Item) ([]*data.Frame, error) {
	trendValueType := ds.getTrendValueType(query)
	consolidateBy := ds.getConsolidateBy(query)

	if consolidateBy != "" {
		trendValueType = consolidateBy
	}

	err := applyFunctionsPre(query, items)
	if err != nil {
		return nil, err
	}

	history, err := ds.getHistotyOrTrend(ctx, query, items, trendValueType)
	if err != nil {
		return nil, err
	}

	series := convertHistoryToTimeSeries(history, items)
	return ds.applyDataProcessing(ctx, query, series, false)
}

func (ds *ZabbixDatasourceInstance) applyDataProcessing(ctx context.Context, query *QueryModel, series []*timeseries.TimeSeriesData, DBPostProcessing bool) ([]*data.Frame, error) {
	consolidateBy := ds.getConsolidateBy(query)
	useTrend := ds.isUseTrend(query.TimeRange)

	// Sort trend data (in some cases Zabbix API returns it unsorted)
	if useTrend {
		sortSeriesPoints(series)
	}

	// Align time series data if possible
	disableDataAlignment := query.Options.DisableDataAlignment || ds.Settings.DisableDataAlignment || query.QueryType == MODE_ITSERVICE
	if !disableDataAlignment {
		if useTrend && !DBPostProcessing {
			for _, s := range series {
				// Trend data is already aligned (by 1 hour interval), but null values should be added
				s.TS = s.TS.FillTrendWithNulls()
			}
		} else {
			for _, s := range series {
				// Skip unnecessary data alignment if item interval less than query interval
				// because data will be downsampled in this case
				if s.Meta.Interval != nil && *s.Meta.Interval > query.Interval {
					s.TS = s.TS.Align(*s.Meta.Interval)
				}
			}
		}

		if len(series) > 1 {
			series = timeseries.PrepareForStack(series)
		}
	}

	series, err := applyFunctions(series, query.Functions)
	if err != nil {
		return nil, err
	}

	for _, s := range series {
		if int64(s.Len()) > query.MaxDataPoints && query.Interval > 0 {
			downsampleFunc := consolidateBy
			if downsampleFunc == "" {
				downsampleFunc = "avg"
			}
			downsampled, err := applyGroupBy(s.TS, query.Interval.String(), downsampleFunc)
			if err == nil {
				s.TS = downsampled
			} else {
				ds.logger.Debug("Error downsampling series", "error", err)
			}
		}
	}

	valueMaps := make([]zabbix.ValueMap, 0)
	if query.Options.UseZabbixValueMapping {
		valueMaps, err = ds.zabbix.GetValueMappings(ctx)
		if err != nil {
			ds.logger.Error("Error getting value maps", "error", err)
			valueMaps = []zabbix.ValueMap{}
		}
	}
	frames := convertTimeSeriesToDataFrames(series, valueMaps)
	return frames, nil
}

func (ds *ZabbixDatasourceInstance) getTrendValueType(query *QueryModel) string {
	trendValue := "avg"

	for _, fn := range query.Functions {
		if fn.Def.Name == "trendValue" && len(fn.Params) > 0 {
			trendValue = fn.Params[0].(string)
		}
	}

	return trendValue
}

func (ds *ZabbixDatasourceInstance) getConsolidateBy(query *QueryModel) string {
	consolidateBy := ""

	for _, fn := range query.Functions {
		if fn.Def.Name == "consolidateBy" && len(fn.Params) > 0 {
			consolidateBy = fn.Params[0].(string)
		}
	}
	return consolidateBy
}

func (ds *ZabbixDatasourceInstance) getHistotyOrTrend(ctx context.Context, query *QueryModel, items []*zabbix.Item, trendValueType string) (zabbix.History, error) {
	timeRange := query.TimeRange
	useTrend := ds.isUseTrend(timeRange)

	if useTrend {
		result, err := ds.zabbix.GetTrend(ctx, items, timeRange)
		if err != nil {
			return nil, err
		}
		return convertTrendToHistory(result, trendValueType)
	}

	return ds.zabbix.GetHistory(ctx, items, timeRange)
}

func (ds *ZabbixDatasourceInstance) isUseTrend(timeRange backend.TimeRange) bool {
	if !ds.Settings.Trends {
		return false
	}

	trendsFrom := ds.Settings.TrendsFrom
	trendsRange := ds.Settings.TrendsRange
	fromSec := timeRange.From.Unix()
	toSec := timeRange.To.Unix()
	rangeSec := float64(toSec - fromSec)

	if (fromSec < time.Now().Add(-trendsFrom).Unix()) || (rangeSec > trendsRange.Seconds()) {
		return true
	}
	return false
}
<commit_msg>Skip alignment only if item interval twice less than query interval<commit_after>package datasource

import (
	"strings"
	"time"

	"github.com/alexanderzobnin/grafana-zabbix/pkg/timeseries"

	"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
	"github.com/grafana/grafana-plugin-sdk-go/backend"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"golang.org/x/net/context"
)

// ZabbixAPIQuery handles query requests to Zabbix API
func (ds *ZabbixDatasourceInstance) ZabbixAPIQuery(ctx context.Context, apiReq *zabbix.ZabbixAPIRequest) (*ZabbixAPIResourceResponse, error) {
	resultJson, err := ds.zabbix.Request(ctx, apiReq)
	if err != nil {
		return nil, err
	}
	result := resultJson.Interface()
	return BuildAPIResponse(&result)
}

func BuildAPIResponse(responseData *interface{}) (*ZabbixAPIResourceResponse, error) {
	return &ZabbixAPIResourceResponse{
		Result: *responseData,
	}, nil
}

// TestConnection checks authentication and version of the Zabbix API and returns that info
func (ds *ZabbixDatasourceInstance) TestConnection(ctx context.Context) (string, error) {
	_, err := ds.zabbix.GetAllGroups(ctx)
	if err != nil {
		return "", err
	}

	response, err := ds.zabbix.Request(ctx, &zabbix.ZabbixAPIRequest{Method: "apiinfo.version"})
	if err != nil {
		return "", err
	}

	resultByte, _ := response.MarshalJSON()
	return string(resultByte), nil
}

func (ds *ZabbixDatasourceInstance) queryNumericItems(ctx context.Context, query *QueryModel) ([]*data.Frame, error) {
	groupFilter := query.Group.Filter
	hostFilter := query.Host.Filter
	appFilter := query.Application.Filter
	itemTagFilter := query.ItemTag.Filter
	itemFilter := query.Item.Filter

	items, err := ds.zabbix.GetItems(ctx, groupFilter, hostFilter, appFilter, itemTagFilter, itemFilter, "num")
	if err != nil {
		return nil, err
	}

	frames, err := ds.queryNumericDataForItems(ctx, query, items)
	if err != nil {
		return nil, err
	}

	return frames, nil
}

func (ds *ZabbixDatasourceInstance) queryItemIdData(ctx context.Context, query *QueryModel) ([]*data.Frame, error) {
	itemids := strings.Split(query.ItemIDs, ",")
	for i, id := range itemids {
		itemids[i] = strings.Trim(id, " ")
	}

	items, err := ds.zabbix.GetItemsByIDs(ctx, itemids)
	if err != nil {
		return nil, err
	}

	frames, err := ds.queryNumericDataForItems(ctx, query, items)
	if err != nil {
		return nil, err
	}

	return frames, nil
}

func (ds *ZabbixDatasourceInstance) queryNumericDataForItems(ctx context.Context, query *QueryModel, items []*zabbix.Item) ([]*data.Frame, error) {
	trendValueType := ds.getTrendValueType(query)
	consolidateBy := ds.getConsolidateBy(query)

	if consolidateBy != "" {
		trendValueType = consolidateBy
	}

	err := applyFunctionsPre(query, items)
	if err != nil {
		return nil, err
	}

	history, err := ds.getHistotyOrTrend(ctx, query, items, trendValueType)
	if err != nil {
		return nil, err
	}

	series := convertHistoryToTimeSeries(history, items)
	return ds.applyDataProcessing(ctx, query, series, false)
}

func (ds *ZabbixDatasourceInstance) applyDataProcessing(ctx context.Context, query *QueryModel, series []*timeseries.TimeSeriesData, DBPostProcessing bool) ([]*data.Frame, error) {
	consolidateBy := ds.getConsolidateBy(query)
	useTrend := ds.isUseTrend(query.TimeRange)

	// Sort trend data (in some cases Zabbix API returns it unsorted)
	if useTrend {
		sortSeriesPoints(series)
	}

	// Align time series data if possible
	disableDataAlignment := query.Options.DisableDataAlignment || ds.Settings.DisableDataAlignment || query.QueryType == MODE_ITSERVICE
	if !disableDataAlignment {
		if useTrend && !DBPostProcessing {
			for _, s := range series {
				// Trend data is already aligned (by 1 hour interval), but null values should be added
				s.TS = s.TS.FillTrendWithNulls()
			}
		} else {
			for _, s := range series {
				// Skip unnecessary data alignment if item interval less than query interval
				// because data will be downsampled in this case. 2 multiplier used to prevent situations when query and item
				// intervals are the same, but downsampling will be performed (query interval is rounded value of time range / max data points).
				if s.Meta.Interval != nil && *s.Meta.Interval*2 > query.Interval {
					s.TS = s.TS.Align(*s.Meta.Interval)
				}
			}
		}

		if len(series) > 1 {
			series = timeseries.PrepareForStack(series)
		}
	}

	series, err := applyFunctions(series, query.Functions)
	if err != nil {
		return nil, err
	}

	for _, s := range series {
		if int64(s.Len()) > query.MaxDataPoints && query.Interval > 0 {
			downsampleFunc := consolidateBy
			if downsampleFunc == "" {
				downsampleFunc = "avg"
			}
			downsampled, err := applyGroupBy(s.TS, query.Interval.String(), downsampleFunc)
			if err == nil {
				s.TS = downsampled
			} else {
				ds.logger.Debug("Error downsampling series", "error", err)
			}
		}
	}

	valueMaps := make([]zabbix.ValueMap, 0)
	if query.Options.UseZabbixValueMapping {
		valueMaps, err = ds.zabbix.GetValueMappings(ctx)
		if err != nil {
			ds.logger.Error("Error getting value maps", "error", err)
			valueMaps = []zabbix.ValueMap{}
		}
	}
	frames := convertTimeSeriesToDataFrames(series, valueMaps)
	return frames, nil
}

func (ds *ZabbixDatasourceInstance) getTrendValueType(query *QueryModel) string {
	trendValue := "avg"

	for _, fn := range query.Functions {
		if fn.Def.Name == "trendValue" && len(fn.Params) > 0 {
			trendValue = fn.Params[0].(string)
		}
	}

	return trendValue
}

func (ds *ZabbixDatasourceInstance) getConsolidateBy(query *QueryModel) string {
	consolidateBy := ""

	for _, fn := range query.Functions {
		if fn.Def.Name == "consolidateBy" && len(fn.Params) > 0 {
			consolidateBy = fn.Params[0].(string)
		}
	}
	return consolidateBy
}

func (ds *ZabbixDatasourceInstance) getHistotyOrTrend(ctx context.Context, query *QueryModel, items []*zabbix.Item, trendValueType string) (zabbix.History, error) {
	timeRange := query.TimeRange
	useTrend := ds.isUseTrend(timeRange)

	if useTrend {
		result, err := ds.zabbix.GetTrend(ctx, items, timeRange)
		if err != nil {
			return nil, err
		}
		return convertTrendToHistory(result, trendValueType)
	}

	return ds.zabbix.GetHistory(ctx, items, timeRange)
}

func (ds *ZabbixDatasourceInstance) isUseTrend(timeRange backend.TimeRange) bool {
	if !ds.Settings.Trends {
		return false
	}

	trendsFrom := ds.Settings.TrendsFrom
	trendsRange := ds.Settings.TrendsRange
	fromSec := timeRange.From.Unix()
	toSec := timeRange.To.Unix()
	rangeSec := float64(toSec - fromSec)

	if (fromSec < time.Now().Add(-trendsFrom).Unix()) || (rangeSec > trendsRange.Seconds()) {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 Authors of Cilium
//
// 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 defaults

import (
	"github.com/sirupsen/logrus"
)

const (
	// IPv6ClusterAllocCIDR is the default value for option.IPv6ClusterAllocCIDR
	IPv6ClusterAllocCIDR = IPv6ClusterAllocCIDRBase + "/64"

	// IPv6ClusterAllocCIDRBase is the default base for IPv6ClusterAllocCIDR
	IPv6ClusterAllocCIDRBase = "fdfd::"

	// RuntimePath is the default path to the runtime directory
	RuntimePath = "/var/run/cilium"

	// RuntimePathRights are the default access rights of the RuntimePath directory
	RuntimePathRights = 0775

	// StateDirRights are the default access rights of the state directory
	StateDirRights = 0770

	//StateDir is the default path for the state directory relative to RuntimePath
	StateDir = "state"

	// BpfDir is the default path for template files relative to LibDir
	BpfDir = "bpf"

	// LibraryPath is the default path to the cilium libraries directory
	LibraryPath = "/var/lib/cilium"

	// SockPath is the path to the UNIX domain socket exposing the API to clients locally
	SockPath = RuntimePath + "/cilium.sock"

	// SockPathEnv is the environment variable to overwrite SockPath
	SockPathEnv = "CILIUM_SOCK"

	// MonitorSockPath is the path to the UNIX domain socket used to distribute events
	// between multiple monitors.
	MonitorSockPath = RuntimePath + "/monitor.sock"

	// PidFilePath is the path to the pid file for the agent.
	PidFilePath = RuntimePath + "/cilium.pid"

	// DefaultLogLevel is the alternative we provide to Debug
	// We set this in pkg/logging.
	DefaultLogLevel = logrus.InfoLevel

	// EventsPipe is the name of the named pipe for agent <=> monitor events
	EventsPipe = "events.sock"
)
<commit_msg>node: Undo default IPv6 prefix change<commit_after>// Copyright 2016-2017 Authors of Cilium
//
// 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 defaults

import (
	"github.com/sirupsen/logrus"
)

const (
	// IPv6ClusterAllocCIDR is the default value for option.IPv6ClusterAllocCIDR
	IPv6ClusterAllocCIDR = IPv6ClusterAllocCIDRBase + "/64"

	// IPv6ClusterAllocCIDRBase is the default base for IPv6ClusterAllocCIDR
	IPv6ClusterAllocCIDRBase = "f00d::"

	// RuntimePath is the default path to the runtime directory
	RuntimePath = "/var/run/cilium"

	// RuntimePathRights are the default access rights of the RuntimePath directory
	RuntimePathRights = 0775

	// StateDirRights are the default access rights of the state directory
	StateDirRights = 0770

	//StateDir is the default path for the state directory relative to RuntimePath
	StateDir = "state"

	// BpfDir is the default path for template files relative to LibDir
	BpfDir = "bpf"

	// LibraryPath is the default path to the cilium libraries directory
	LibraryPath = "/var/lib/cilium"

	// SockPath is the path to the UNIX domain socket exposing the API to clients locally
	SockPath = RuntimePath + "/cilium.sock"

	// SockPathEnv is the environment variable to overwrite SockPath
	SockPathEnv = "CILIUM_SOCK"

	// MonitorSockPath is the path to the UNIX domain socket used to distribute events
	// between multiple monitors.
	MonitorSockPath = RuntimePath + "/monitor.sock"

	// PidFilePath is the path to the pid file for the agent.
	PidFilePath = RuntimePath + "/cilium.pid"

	// DefaultLogLevel is the alternative we provide to Debug
	// We set this in pkg/logging.
	DefaultLogLevel = logrus.InfoLevel

	// EventsPipe is the name of the named pipe for agent <=> monitor events
	EventsPipe = "events.sock"
)
<|endoftext|>


<commit_before>// Package poly provides polygon detection methods.
package poly

import "fmt"

// Point is simple 2D point
type Point struct {
	X, Y, Z float64 // X=latitude, Y=longitude, (Z is optional, e.g. for elevation or timestamp)
}

// InsideRect detects point is inside of another rect
func (p Point) InsideRect(rect Rect) bool {
	if p.X < rect.Min.X || p.X > rect.Max.X {
		return false
	}
	if p.Y < rect.Min.Y || p.Y > rect.Max.Y {
		return false
	}
	return true
}

// Polygon is series of points that make up a polygon
type Polygon []Point

// InsideRect detects polygon is inside of another rect
func (p Polygon) InsideRect(rect Rect) bool {
	if len(p) == 0 {
		return false
	}
	for _, p := range p {
		if !p.InsideRect(rect) {
			return false
		}
	}
	return true
}

// IntersectsRect detects polygon is inside of another rect
func (p Polygon) IntersectsRect(rect Rect) bool {
	if len(p) == 0 {
		return false
	}
	rectPoly := Polygon{rect.Min, {rect.Min.X, rect.Max.Y, 0}, rect.Max, {rect.Max.X, rect.Min.Y, 0}, rect.Min}
	return p.Intersects(rectPoly, nil)
}

// String returns a string representation of the polygon.
func (p Polygon) String() string {
	s := "{"
	for i, p := range p {
		if i > 0 {
			s += ", "
		}
		s += fmt.Sprintf("{%v, %v}", p.X, p.Y)
	}
	s += "}"
	return s
}

// Rect is rectangle
type Rect struct {
	Min, Max Point
}

// Polygon returns a polygon for the rect
func (r Rect) Polygon() Polygon {
	p := Polygon(make([]Point, 5))
	p[0] = Point{X: r.Min.X, Y: r.Max.Y}
	p[1] = Point{X: r.Max.X, Y: r.Max.Y}
	p[2] = Point{X: r.Max.X, Y: r.Min.Y}
	p[3] = Point{X: r.Min.X, Y: r.Min.Y}
	p[4] = Point{X: r.Min.X, Y: r.Max.Y}
	return p
}

// Rect returns the bounding box rectangle for the polygon
func (p Polygon) Rect() Rect {
	var bbox Rect
	for i, p := range p {
		if i == 0 {
			bbox.Min = p
			bbox.Max = p
		} else {
			if p.X < bbox.Min.X {
				bbox.Min.X = p.X
			} else if p.X > bbox.Max.X {
				bbox.Max.X = p.X
			}
			if p.Y < bbox.Min.Y {
				bbox.Min.Y = p.Y
			} else if p.Y > bbox.Max.Y {
				bbox.Max.Y = p.Y
			}
		}
	}
	return bbox
}

// IntersectsRect detects if two bboxes intersect.
func (r Rect) IntersectsRect(rect Rect) bool {
	if r.Min.Y > rect.Max.Y || r.Max.Y < rect.Min.Y {
		return false
	}
	if r.Min.X > rect.Max.X || r.Max.X < rect.Min.X {
		return false
	}
	return true
}

// InsideRect detects rect is inside of another rect
func (r Rect) InsideRect(rect Rect) bool {
	if r.Min.X < rect.Min.X || r.Max.X > rect.Max.X {
		return false
	}
	if r.Min.Y < rect.Min.Y || r.Max.Y > rect.Max.Y {
		return false
	}
	return true
}
<commit_msg>Update poly geo comment<commit_after>// Package poly provides polygon detection methods.
package poly

import "fmt"

// Point is simple 2D point
// For geo locations: X is lat, Y is lon, and Z is elev or time measure.
type Point struct {
	X, Y, Z float64
}

// InsideRect detects point is inside of another rect
func (p Point) InsideRect(rect Rect) bool {
	if p.X < rect.Min.X || p.X > rect.Max.X {
		return false
	}
	if p.Y < rect.Min.Y || p.Y > rect.Max.Y {
		return false
	}
	return true
}

// Polygon is series of points that make up a polygon
type Polygon []Point

// InsideRect detects polygon is inside of another rect
func (p Polygon) InsideRect(rect Rect) bool {
	if len(p) == 0 {
		return false
	}
	for _, p := range p {
		if !p.InsideRect(rect) {
			return false
		}
	}
	return true
}

// IntersectsRect detects polygon is inside of another rect
func (p Polygon) IntersectsRect(rect Rect) bool {
	if len(p) == 0 {
		return false
	}
	rectPoly := Polygon{rect.Min, {rect.Min.X, rect.Max.Y, 0}, rect.Max, {rect.Max.X, rect.Min.Y, 0}, rect.Min}
	return p.Intersects(rectPoly, nil)
}

// String returns a string representation of the polygon.
func (p Polygon) String() string {
	s := "{"
	for i, p := range p {
		if i > 0 {
			s += ", "
		}
		s += fmt.Sprintf("{%v, %v}", p.X, p.Y)
	}
	s += "}"
	return s
}

// Rect is rectangle
type Rect struct {
	Min, Max Point
}

// Polygon returns a polygon for the rect
func (r Rect) Polygon() Polygon {
	p := Polygon(make([]Point, 5))
	p[0] = Point{X: r.Min.X, Y: r.Max.Y}
	p[1] = Point{X: r.Max.X, Y: r.Max.Y}
	p[2] = Point{X: r.Max.X, Y: r.Min.Y}
	p[3] = Point{X: r.Min.X, Y: r.Min.Y}
	p[4] = Point{X: r.Min.X, Y: r.Max.Y}
	return p
}

// Rect returns the bounding box rectangle for the polygon
func (p Polygon) Rect() Rect {
	var bbox Rect
	for i, p := range p {
		if i == 0 {
			bbox.Min = p
			bbox.Max = p
		} else {
			if p.X < bbox.Min.X {
				bbox.Min.X = p.X
			} else if p.X > bbox.Max.X {
				bbox.Max.X = p.X
			}
			if p.Y < bbox.Min.Y {
				bbox.Min.Y = p.Y
			} else if p.Y > bbox.Max.Y {
				bbox.Max.Y = p.Y
			}
		}
	}
	return bbox
}

// IntersectsRect detects if two bboxes intersect.
func (r Rect) IntersectsRect(rect Rect) bool {
	if r.Min.Y > rect.Max.Y || r.Max.Y < rect.Min.Y {
		return false
	}
	if r.Min.X > rect.Max.X || r.Max.X < rect.Min.X {
		return false
	}
	return true
}

// InsideRect detects rect is inside of another rect
func (r Rect) InsideRect(rect Rect) bool {
	if r.Min.X < rect.Min.X || r.Max.X > rect.Max.X {
		return false
	}
	if r.Min.Y < rect.Min.Y || r.Max.Y > rect.Max.Y {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package loader

import (
	"github.com/hellofresh/janus/pkg/api"
	"github.com/hellofresh/janus/pkg/middleware"
	"github.com/hellofresh/janus/pkg/plugin"
	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/hellofresh/janus/pkg/router"
	log "github.com/sirupsen/logrus"
)

// APILoader is responsible for loading all apis form a datastore and configure them in a register
type APILoader struct {
	register     *proxy.Register
	pluginLoader *plugin.Loader
}

// NewAPILoader creates a new instance of the api manager
func NewAPILoader(register *proxy.Register, pluginLoader *plugin.Loader) *APILoader {
	return &APILoader{register, pluginLoader}
}

// LoadDefinitions registers all ApiDefinitions from a data source
func (m *APILoader) LoadDefinitions(repo api.Repository) {
	specs := m.getAPISpecs(repo)
	m.RegisterApis(specs)
}

// RegisterApis load application middleware
func (m *APILoader) RegisterApis(apiSpecs []*api.Spec) {
	for _, referenceSpec := range apiSpecs {
		m.RegisterAPI(referenceSpec)
	}
}

// RegisterAPI register an API Spec in the register
func (m *APILoader) RegisterAPI(referenceSpec *api.Spec) {
	logger := log.WithField("api_name", referenceSpec.Name)

	active, err := referenceSpec.Validate()
	if false == active && err != nil {
		logger.WithError(err).Error("Validation errors")
	}

	if false == referenceSpec.Active {
		logger.Warn("API is not active, skipping...")
		active = false
	}

	if active {
		var handlers []router.Constructor

		for _, pDefinition := range referenceSpec.Plugins {
			if pDefinition.Enabled {
				logger.WithField("name", pDefinition.Name).Debug("Plugin enabled")
				if p := m.pluginLoader.Get(pDefinition.Name); p != nil {
					middlewares, err := p.GetMiddlewares(pDefinition.Config, referenceSpec)
					if err != nil {
						logger.WithError(err).
							WithField("plugin_name", pDefinition.Name).
							Error("Error loading plugin")
					}

					for _, mw := range middlewares {
						handlers = append(handlers, mw)
					}
				}
			} else {
				logger.WithField("name", pDefinition.Name).Debug("Plugin not enabled")
			}
		}

		if len(referenceSpec.Definition.Proxy.Hosts) > 0 {
			handlers = append(handlers, middleware.NewHostMatcher(referenceSpec.Definition.Proxy.Hosts).Handler)
		}

		m.register.Add(proxy.NewRoute(referenceSpec.Proxy, handlers, nil))
		logger.Debug("API registered")
	} else {
		logger.WithError(err).Warn("API URI is invalid or not active, skipping...")
	}
}

// getAPISpecs Load application specs from data source
func (m *APILoader) getAPISpecs(repo api.Repository) []*api.Spec {
	definitions, err := repo.FindAll()
	if err != nil {
		log.Panic(err)
	}

	var specs []*api.Spec
	for _, definition := range definitions {
		specs = append(specs, &api.Spec{Definition: definition})
	}

	return specs
}
<commit_msg>Better logging<commit_after>package loader

import (
	"github.com/hellofresh/janus/pkg/api"
	"github.com/hellofresh/janus/pkg/middleware"
	"github.com/hellofresh/janus/pkg/plugin"
	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/hellofresh/janus/pkg/router"
	log "github.com/sirupsen/logrus"
)

// APILoader is responsible for loading all apis form a datastore and configure them in a register
type APILoader struct {
	register     *proxy.Register
	pluginLoader *plugin.Loader
}

// NewAPILoader creates a new instance of the api manager
func NewAPILoader(register *proxy.Register, pluginLoader *plugin.Loader) *APILoader {
	return &APILoader{register, pluginLoader}
}

// LoadDefinitions registers all ApiDefinitions from a data source
func (m *APILoader) LoadDefinitions(repo api.Repository) {
	specs := m.getAPISpecs(repo)
	m.RegisterApis(specs)
}

// RegisterApis load application middleware
func (m *APILoader) RegisterApis(apiSpecs []*api.Spec) {
	for _, referenceSpec := range apiSpecs {
		m.RegisterAPI(referenceSpec)
	}
}

// RegisterAPI register an API Spec in the register
func (m *APILoader) RegisterAPI(referenceSpec *api.Spec) {
	logger := log.WithField("api_name", referenceSpec.Name)

	active, err := referenceSpec.Validate()
	if false == active && err != nil {
		logger.WithError(err).Error("Validation errors")
	}

	if false == referenceSpec.Active {
		logger.Warn("API is not active, skipping...")
		active = false
	}

	if active {
		var handlers []router.Constructor

		for _, pDefinition := range referenceSpec.Plugins {
			l := logger.WithField("name", pDefinition.Name)
			if pDefinition.Enabled {
				l.Debug("Plugin enabled")
				if p := m.pluginLoader.Get(pDefinition.Name); p != nil {
					middlewares, err := p.GetMiddlewares(pDefinition.Config, referenceSpec)
					if err != nil {
						l.WithError(err).Error("Error loading plugin")
					}

					for _, mw := range middlewares {
						handlers = append(handlers, mw)
					}
				}
			} else {
				l.Debug("Plugin not enabled")
			}
		}

		if len(referenceSpec.Definition.Proxy.Hosts) > 0 {
			handlers = append(handlers, middleware.NewHostMatcher(referenceSpec.Definition.Proxy.Hosts).Handler)
		}

		m.register.Add(proxy.NewRoute(referenceSpec.Proxy, handlers, nil))
		logger.Debug("API registered")
	} else {
		logger.WithError(err).Warn("API URI is invalid or not active, skipping...")
	}
}

// getAPISpecs Load application specs from data source
func (m *APILoader) getAPISpecs(repo api.Repository) []*api.Spec {
	definitions, err := repo.FindAll()
	if err != nil {
		log.Panic(err)
	}

	var specs []*api.Spec
	for _, definition := range definitions {
		specs = append(specs, &api.Spec{Definition: definition})
	}

	return specs
}
<|endoftext|>


<commit_before>package object

// TODO might just be the worst interface name ever
type objectable interface {
	ToObject() Object
}

// Objectable is a temp interface, we should consider removing
type Objectable interface {
	objectable
}
<commit_msg>remove(ibject): remove objectable<commit_after><|endoftext|>


<commit_before>package gcache

import (
	"strings"
)

const (
	// https://developers.google.com/drive/v3/web/handle-errors
	// 400
	reasonBadRequest            = "badRequest"
	reasonInvalidSharingRequest = "invalidSharingRequest"
	// 401
	reasonAuthError = "authError"
	// 403
	reasonDailyLimitExceeded          = "dailyLimitExceeded"
	reasonUserRateLimitExceeded       = "userRateLimitExceeded"
	reasonRateLimitExceeded           = "rateLimitExceeded"
	reasonSharingRateLimitExceeded    = "sharingRateLimitExceeded"
	reasonAppNotAuthorizedToFile      = "appNotAuthorizedToFile"
	reasonInsufficientFilePermissions = "insufficientFilePermissions"
	reasonDomainPolicy                = "domainPolicy"
	// 404
	reasonNotFound = "notFound"
	// 500
	reasonBackendError = "backendError"
)

var (
	errInvalidSecurityTicket = []string{"invalid security ticket"}
	errDeadlineExceeded      = []string{"Deadline exceeded"}
	errFileNotExportable     = []string{"fileNotExportable"}
	errServerError           = []string{
		"500 Internal Server Error",
		"502 Bad Gateway",
		"503 Service Unavailable",
		"504 Gateway Timeout",
	}
	errRateLimit = []string{
		reasonUserRateLimitExceeded,
		reasonRateLimitExceeded,
	}
)

// DriveFileDoesNotExistError is as HTTP response that is 40X HTTP status.
type DriveFileDoesNotExistError struct {
	message string
}

func (err DriveFileDoesNotExistError) Error() string {
	return err.message
}

// NewDriveFileDoesNotExistError returns a DriveFileDoesNotExistError.
func NewDriveFileDoesNotExistError() *DriveFileDoesNotExistError {
	return &DriveFileDoesNotExistError{message: "drive: file does not exist"}
}

// IsInvalidSecurityTicket returns is whether it is "invalid security ticket" error or not.
func IsInvalidSecurityTicket(
	err error,
) bool {
	return containsErrorMessage(err, errInvalidSecurityTicket)
}

// IsDeadlineExceededError returns is whether it is "Deadline exceeded" error or not.
func IsDeadlineExceededError(
	err error,
) bool {
	return containsErrorMessage(err, errDeadlineExceeded)
}

// IsFileNotExportableError returns is whether it is "fileNotExportable" error or not.
func IsFileNotExportableError(
	err error,
) bool {
	return containsErrorMessage(err, errFileNotExportable)
}

// IsServerError returns is whether it is 50X server errors or not.
func IsServerError(
	err error,
) bool {
	return containsErrorMessage(err, errServerError)
}

// IsRateLimit returns is whether it is "userRateLimitExceeded" or "rateLimitExceeded" server errors or not.
func IsRateLimit(
	err error,
) bool {
	return containsErrorMessage(err, errRateLimit)
}

func containsErrorMessage(
	err error,
	messages []string,
) bool {
	if err == nil {
		return false
	}
	errorMessage := err.Error()
	for _, message := range messages {
		if strings.Contains(errorMessage, message) {
			return true
		}
	}
	return false
}
<commit_msg>fix return type<commit_after>package gcache

import (
	"strings"
)

const (
	// https://developers.google.com/drive/v3/web/handle-errors
	// 400
	reasonBadRequest            = "badRequest"
	reasonInvalidSharingRequest = "invalidSharingRequest"
	// 401
	reasonAuthError = "authError"
	// 403
	reasonDailyLimitExceeded          = "dailyLimitExceeded"
	reasonUserRateLimitExceeded       = "userRateLimitExceeded"
	reasonRateLimitExceeded           = "rateLimitExceeded"
	reasonSharingRateLimitExceeded    = "sharingRateLimitExceeded"
	reasonAppNotAuthorizedToFile      = "appNotAuthorizedToFile"
	reasonInsufficientFilePermissions = "insufficientFilePermissions"
	reasonDomainPolicy                = "domainPolicy"
	// 404
	reasonNotFound = "notFound"
	// 500
	reasonBackendError = "backendError"
)

var (
	errInvalidSecurityTicket = []string{"invalid security ticket"}
	errDeadlineExceeded      = []string{"Deadline exceeded"}
	errFileNotExportable     = []string{"fileNotExportable"}
	errServerError           = []string{
		"500 Internal Server Error",
		"502 Bad Gateway",
		"503 Service Unavailable",
		"504 Gateway Timeout",
	}
	errRateLimit = []string{
		reasonUserRateLimitExceeded,
		reasonRateLimitExceeded,
	}
)

// DriveFileDoesNotExistError is as HTTP response that is 40X HTTP status.
type DriveFileDoesNotExistError struct {
	message string
}

func (err DriveFileDoesNotExistError) Error() string {
	return err.message
}

// NewDriveFileDoesNotExistError returns a DriveFileDoesNotExistError.
func NewDriveFileDoesNotExistError() error {
	return &DriveFileDoesNotExistError{message: "drive: file does not exist"}
}

// IsInvalidSecurityTicket returns is whether it is "invalid security ticket" error or not.
func IsInvalidSecurityTicket(
	err error,
) bool {
	return containsErrorMessage(err, errInvalidSecurityTicket)
}

// IsDeadlineExceededError returns is whether it is "Deadline exceeded" error or not.
func IsDeadlineExceededError(
	err error,
) bool {
	return containsErrorMessage(err, errDeadlineExceeded)
}

// IsFileNotExportableError returns is whether it is "fileNotExportable" error or not.
func IsFileNotExportableError(
	err error,
) bool {
	return containsErrorMessage(err, errFileNotExportable)
}

// IsServerError returns is whether it is 50X server errors or not.
func IsServerError(
	err error,
) bool {
	return containsErrorMessage(err, errServerError)
}

// IsRateLimit returns is whether it is "userRateLimitExceeded" or "rateLimitExceeded" server errors or not.
func IsRateLimit(
	err error,
) bool {
	return containsErrorMessage(err, errRateLimit)
}

func containsErrorMessage(
	err error,
	messages []string,
) bool {
	if err == nil {
		return false
	}
	errorMessage := err.Error()
	for _, message := range messages {
		if strings.Contains(errorMessage, message) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package flags

import (
	"fmt"
)

// ErrorType represents the type of error.
type ErrorType uint

const (
	// ErrUnknown indicates a generic error.
	ErrUnknown ErrorType = iota

	// ErrExpectedArgument indicates that an argument was expected.
	ErrExpectedArgument

	// ErrUnknownFlag indicates an unknown flag.
	ErrUnknownFlag

	// ErrUnknownGroup indicates an unknown group.
	ErrUnknownGroup

	// ErrMarshal indicates a marshalling error while converting values.
	ErrMarshal

	// ErrHelp indicates that the builtin help was shown (the error
	// contains the help message).
	ErrHelp

	// ErrNoArgumentForBool indicates that an argument was given for a
	// boolean flag (which don't not take any arguments).
	ErrNoArgumentForBool

	// ErrRequired indicates that a required flag was not provided.
	ErrRequired

	// ErrShortNameTooLong indicates that a short flag name was specified,
	// longer than one character.
	ErrShortNameTooLong

	// ErrDuplicatedFlag indicates that a short or long flag has been
	// defined more than once
	ErrDuplicatedFlag

	// ErrTag indicates an error while parsing flag tags.
	ErrTag
)

// String returns a string representation of the error type.
func (e ErrorType) String() string {
	switch e {
	case ErrUnknown:
		return "unknown"
	case ErrExpectedArgument:
		return "expected argument"
	case ErrUnknownFlag:
		return "unknown flag"
	case ErrUnknownGroup:
		return "unknown group"
	case ErrMarshal:
		return "marshal"
	case ErrHelp:
		return "help"
	case ErrNoArgumentForBool:
		return "no argument for bool"
	case ErrRequired:
		return "required"
	case ErrDuplicatedFlag:
		return "duplicated flag"
	}

	return "unknown"
}

// Error represents a parser error. The error returned from Parse is of this
// type. The error contains both a Type and Message.
type Error struct {
	// The type of error
	Type ErrorType

	// The error message
	Message string
}

// Error returns the error's message
func (e *Error) Error() string {
	return e.Message
}

func newError(tp ErrorType, message string) *Error {
	return &Error{
		Type:    tp,
		Message: message,
	}
}

func newErrorf(tp ErrorType, format string, args ...interface{}) *Error {
	return newError(tp, fmt.Sprintf(format, args...))
}

func wrapError(err error) *Error {
	ret, ok := err.(*Error)

	if !ok {
		return newError(ErrUnknown, err.Error())
	}

	return ret
}
<commit_msg>Add ErrorType string for ErrTag<commit_after>package flags

import (
	"fmt"
)

// ErrorType represents the type of error.
type ErrorType uint

const (
	// ErrUnknown indicates a generic error.
	ErrUnknown ErrorType = iota

	// ErrExpectedArgument indicates that an argument was expected.
	ErrExpectedArgument

	// ErrUnknownFlag indicates an unknown flag.
	ErrUnknownFlag

	// ErrUnknownGroup indicates an unknown group.
	ErrUnknownGroup

	// ErrMarshal indicates a marshalling error while converting values.
	ErrMarshal

	// ErrHelp indicates that the builtin help was shown (the error
	// contains the help message).
	ErrHelp

	// ErrNoArgumentForBool indicates that an argument was given for a
	// boolean flag (which don't not take any arguments).
	ErrNoArgumentForBool

	// ErrRequired indicates that a required flag was not provided.
	ErrRequired

	// ErrShortNameTooLong indicates that a short flag name was specified,
	// longer than one character.
	ErrShortNameTooLong

	// ErrDuplicatedFlag indicates that a short or long flag has been
	// defined more than once
	ErrDuplicatedFlag

	// ErrTag indicates an error while parsing flag tags.
	ErrTag
)

// String returns a string representation of the error type.
func (e ErrorType) String() string {
	switch e {
	case ErrUnknown:
		return "unknown"
	case ErrExpectedArgument:
		return "expected argument"
	case ErrUnknownFlag:
		return "unknown flag"
	case ErrUnknownGroup:
		return "unknown group"
	case ErrMarshal:
		return "marshal"
	case ErrHelp:
		return "help"
	case ErrNoArgumentForBool:
		return "no argument for bool"
	case ErrRequired:
		return "required"
	case ErrDuplicatedFlag:
		return "duplicated flag"
	case ErrTag:
		return "tag"
	}

	return "unknown"
}

// Error represents a parser error. The error returned from Parse is of this
// type. The error contains both a Type and Message.
type Error struct {
	// The type of error
	Type ErrorType

	// The error message
	Message string
}

// Error returns the error's message
func (e *Error) Error() string {
	return e.Message
}

func newError(tp ErrorType, message string) *Error {
	return &Error{
		Type:    tp,
		Message: message,
	}
}

func newErrorf(tp ErrorType, format string, args ...interface{}) *Error {
	return newError(tp, fmt.Sprintf(format, args...))
}

func wrapError(err error) *Error {
	ret, ok := err.(*Error)

	if !ok {
		return newError(ErrUnknown, err.Error())
	}

	return ret
}
<|endoftext|>


<commit_before>// Package depinject implements a simple
// Dependency Injector
package depinject

import (
	"errors"
	"log"
	"reflect"
)

var (
	ConstructorErr     = errors.New("Constructor must be a function and output 1 parameter")
	ConstructorArgsErr = errors.New("Can't resolve function arguments")
)

// DependencyInjector is a simple IOC container
// that allows registering constructor functions
// and creating them
type DependencyInjector struct {
	registry map[reflect.Type]interface{}
}

// Register registers a constructor function
// with the DI container
func (di *DependencyInjector) Register(constructorFunc interface{}) error {
	constructorType := reflect.TypeOf(constructorFunc)

	if (constructorType.Kind() != reflect.Func) || (constructorType.NumOut() != 1) {
		return ConstructorErr
	}
	outType := constructorType.Out(0)

	// make sure we can resolve the constuctor arguments
	for i := 0; i < constructorType.NumIn(); i++ {
		inType := constructorType.In(i)
		_, ok := di.registry[inType]
		if !ok {
			log.Printf("Can't find a %s for a %s\n", inType, outType)
			return ConstructorArgsErr
		}
	}

	di.registry[outType] = constructorFunc

	return nil
}

// Create creates an instance of the type of the given parameter
func (di *DependencyInjector) Create(avar interface{}) interface{} {
	return di.CreateFromType(reflect.TypeOf(avar)).Interface()
}

// CreateFromType creates an instance of the given type
func (di *DependencyInjector) CreateFromType(atype reflect.Type) reflect.Value {
	constructor, exists := di.registry[atype]
	if !exists {
		log.Panicf("Can't find a mapping to create a %s", atype)
	}

	constructorType := reflect.TypeOf(constructor)
	constructorArgs := []reflect.Value{}

	for i := 0; i < constructorType.NumIn(); i++ {
		t := constructorType.In(i)
		v := di.CreateFromType(t)
		constructorArgs = append(constructorArgs, v)
	}

	newObj := reflect.ValueOf(constructor).Call(constructorArgs)

	return newObj[0]
}

func NewDependencyInjector() DependencyInjector {
	return DependencyInjector{
		registry: make(map[reflect.Type]interface{}),
	}
}
<commit_msg>Add MustRegister to depinjector<commit_after>// Package depinject implements a simple
// Dependency Injector
package depinject

import (
	"errors"
	"log"
	"reflect"
)

var (
	ConstructorErr     = errors.New("Constructor must be a function and output 1 parameter")
	ConstructorArgsErr = errors.New("Can't resolve function arguments")
)

// DependencyInjector is a simple IOC container
// that allows registering constructor functions
// and creating them
type DependencyInjector struct {
	registry map[reflect.Type]interface{}
}

// Register registers a constructor function
// with the DI container
func (di *DependencyInjector) Register(constructorFunc interface{}) error {
	constructorType := reflect.TypeOf(constructorFunc)

	if (constructorType.Kind() != reflect.Func) || (constructorType.NumOut() != 1) {
		return ConstructorErr
	}
	outType := constructorType.Out(0)

	// make sure we can resolve the constuctor arguments
	for i := 0; i < constructorType.NumIn(); i++ {
		inType := constructorType.In(i)
		_, ok := di.registry[inType]
		if !ok {
			log.Printf("Can't find a %s for a %s\n", inType, outType)
			return ConstructorArgsErr
		}
	}

	di.registry[outType] = constructorFunc

	return nil
}

func (di *DependencyInjector) MustRegister(constructorFunc interface{}) {
	err := di.Register(constructorFunc)
	if err != nil {
		panic(err)
	}
}

// Create creates an instance of the type of the given parameter
func (di *DependencyInjector) Create(avar interface{}) interface{} {
	return di.CreateFromType(reflect.TypeOf(avar)).Interface()
}

// CreateFromType creates an instance of the given type
func (di *DependencyInjector) CreateFromType(atype reflect.Type) reflect.Value {
	constructor, exists := di.registry[atype]
	if !exists {
		log.Panicf("Can't find a mapping to create a %s", atype)
	}

	constructorType := reflect.TypeOf(constructor)
	constructorArgs := []reflect.Value{}

	for i := 0; i < constructorType.NumIn(); i++ {
		t := constructorType.In(i)
		v := di.CreateFromType(t)
		constructorArgs = append(constructorArgs, v)
	}

	newObj := reflect.ValueOf(constructor).Call(constructorArgs)

	return newObj[0]
}

func NewDependencyInjector() DependencyInjector {
	return DependencyInjector{
		registry: make(map[reflect.Type]interface{}),
	}
}
<|endoftext|>


<commit_before>// Package depinject implements a simple
// Dependency Injector
package depinject

import (
	"errors"
	"log"
	"reflect"
)

var (
	ConstructorErr     = errors.New("Constructor must be a function and output 1 parameter")
	ConstructorArgsErr = errors.New("Can't resolve function arguments")
)

// DependencyInjector is a simple IOC container
// that allows registering constructor functions
// and creating them
type DependencyInjector struct {
	registry map[reflect.Type]interface{}
}

// Register registers a constructor function
// with the DI container
func (di *DependencyInjector) Register(constructorFunc interface{}) error {
	constructorType := reflect.TypeOf(constructorFunc)

	if (constructorType.Kind() != reflect.Func) || (constructorType.NumOut() != 1) {
		return ConstructorErr
	}
	outType := constructorType.Out(0)

	// make sure we can resolve the constuctor arguments
	for i := 0; i < constructorType.NumIn(); i++ {
		inType := constructorType.In(i)
		_, ok := di.registry[inType]
		if !ok {
			log.Printf("Can't find a %s for a %s\n", inType, outType)
			return ConstructorArgsErr
		}
	}

	di.registry[outType] = constructorFunc

	log.Printf("Registered %s\n", outType)

	return nil
}

// Create creates an instance of the type of the given parameter
func (di *DependencyInjector) Create(avar interface{}) interface{} {
	return di.CreateFromType(reflect.TypeOf(avar)).Interface()
}

// CreateFromType creates an instance of the given type
func (di *DependencyInjector) CreateFromType(atype reflect.Type) reflect.Value {
	constructor, exists := di.registry[atype]
	if !exists {
		panic("Can't find that type to create")
	}

	constructorType := reflect.TypeOf(constructor)
	constructorArgs := []reflect.Value{}

	for i := 0; i < constructorType.NumIn(); i++ {
		t := constructorType.In(i)
		v := di.CreateFromType(t)
		constructorArgs = append(constructorArgs, v)
	}

	newObj := reflect.ValueOf(constructor).Call(constructorArgs)

	return newObj[0]
}

func NewDependencyInjector() DependencyInjector {
	return DependencyInjector{
		registry: make(map[reflect.Type]interface{}),
	}
}
<commit_msg>Better panic message<commit_after>// Package depinject implements a simple
// Dependency Injector
package depinject

import (
	"errors"
	"log"
	"reflect"
)

var (
	ConstructorErr     = errors.New("Constructor must be a function and output 1 parameter")
	ConstructorArgsErr = errors.New("Can't resolve function arguments")
)

// DependencyInjector is a simple IOC container
// that allows registering constructor functions
// and creating them
type DependencyInjector struct {
	registry map[reflect.Type]interface{}
}

// Register registers a constructor function
// with the DI container
func (di *DependencyInjector) Register(constructorFunc interface{}) error {
	constructorType := reflect.TypeOf(constructorFunc)

	if (constructorType.Kind() != reflect.Func) || (constructorType.NumOut() != 1) {
		return ConstructorErr
	}
	outType := constructorType.Out(0)

	// make sure we can resolve the constuctor arguments
	for i := 0; i < constructorType.NumIn(); i++ {
		inType := constructorType.In(i)
		_, ok := di.registry[inType]
		if !ok {
			log.Printf("Can't find a %s for a %s\n", inType, outType)
			return ConstructorArgsErr
		}
	}

	di.registry[outType] = constructorFunc

	log.Printf("Registered %s\n", outType)

	return nil
}

// Create creates an instance of the type of the given parameter
func (di *DependencyInjector) Create(avar interface{}) interface{} {
	return di.CreateFromType(reflect.TypeOf(avar)).Interface()
}

// CreateFromType creates an instance of the given type
func (di *DependencyInjector) CreateFromType(atype reflect.Type) reflect.Value {
	constructor, exists := di.registry[atype]
	if !exists {
		log.Panicf("Can't find a mapping to create a %s", atype)
	}

	constructorType := reflect.TypeOf(constructor)
	constructorArgs := []reflect.Value{}

	for i := 0; i < constructorType.NumIn(); i++ {
		t := constructorType.In(i)
		v := di.CreateFromType(t)
		constructorArgs = append(constructorArgs, v)
	}

	newObj := reflect.ValueOf(constructor).Call(constructorArgs)

	return newObj[0]
}

func NewDependencyInjector() DependencyInjector {
	return DependencyInjector{
		registry: make(map[reflect.Type]interface{}),
	}
}
<|endoftext|>


<commit_before>package tui

import (
	"fmt"
	"image"
	"strings"
)

// ModMask is a mask of modifier keys.
type ModMask int16

// Modifiers that can be sent with a KeyEvent or a MouseEvent.
const (
	ModShift ModMask = 1 << iota
	ModCtrl
	ModAlt
	ModMeta
	ModNone ModMask = 0
)

// KeyEvent represents a key press.
type KeyEvent struct {
	Key       Key
	Rune      rune
	Modifiers ModMask
}

// Name returns a user-friendly description of the key press.
func (ev *KeyEvent) Name() string {
	s := ""
	m := []string{}
	if ev.Modifiers&ModShift != 0 {
		m = append(m, "Shift")
	}
	if ev.Modifiers&ModAlt != 0 {
		m = append(m, "Alt")
	}
	if ev.Modifiers&ModMeta != 0 {
		m = append(m, "Meta")
	}
	if ev.Modifiers&ModCtrl != 0 {
		m = append(m, "Ctrl")
	}

	ok := false
	if s, ok = keyNames[ev.Key]; !ok {
		if ev.Key == KeyRune {
			s = string(ev.Rune)
		} else {
			s = "Unknown"
		}
	}
	if len(m) != 0 {
		if ev.Modifiers&ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") {
			s = s[5:]
		}
		return fmt.Sprintf("%s+%s", strings.Join(m, "+"), s)
	}
	return s
}

// Key represents both normal and special keys. For normal letters, KeyRune is
// used together with the Rune field in the KeyEvent.
type Key int16

// These are named keys that can be handled.
const (
	KeyRune Key = iota + 256
	KeyUp
	KeyDown
	KeyRight
	KeyLeft
	KeyUpLeft
	KeyUpRight
	KeyDownLeft
	KeyDownRight
	KeyCenter
	KeyPgUp
	KeyPgDn
	KeyHome
	KeyEnd
	KeyInsert
	KeyDelete
	KeyHelp
	KeyExit
	KeyClear
	KeyCancel
	KeyPrint
	KeyPause
	KeyBacktab
	KeyF1
	KeyF2
	KeyF3
	KeyF4
	KeyF5
	KeyF6
	KeyF7
	KeyF8
	KeyF9
	KeyF10
	KeyF11
	KeyF12
	KeyF13
	KeyF14
	KeyF15
	KeyF16
	KeyF17
	KeyF18
	KeyF19
	KeyF20
	KeyF21
	KeyF22
	KeyF23
	KeyF24
	KeyF25
	KeyF26
	KeyF27
	KeyF28
	KeyF29
	KeyF30
	KeyF31
	KeyF32
	KeyF33
	KeyF34
	KeyF35
	KeyF36
	KeyF37
	KeyF38
	KeyF39
	KeyF40
	KeyF41
	KeyF42
	KeyF43
	KeyF44
	KeyF45
	KeyF46
	KeyF47
	KeyF48
	KeyF49
	KeyF50
	KeyF51
	KeyF52
	KeyF53
	KeyF54
	KeyF55
	KeyF56
	KeyF57
	KeyF58
	KeyF59
	KeyF60
	KeyF61
	KeyF62
	KeyF63
	KeyF64
)

// These are the supported control keys.
const (
	KeyCtrlSpace Key = iota
	KeyCtrlA
	KeyCtrlB
	KeyCtrlC
	KeyCtrlD
	KeyCtrlE
	KeyCtrlF
	KeyCtrlG
	KeyCtrlH
	KeyCtrlI
	KeyCtrlJ
	KeyCtrlK
	KeyCtrlL
	KeyCtrlM
	KeyCtrlN
	KeyCtrlO
	KeyCtrlP
	KeyCtrlQ
	KeyCtrlR
	KeyCtrlS
	KeyCtrlT
	KeyCtrlU
	KeyCtrlV
	KeyCtrlW
	KeyCtrlX
	KeyCtrlY
	KeyCtrlZ
	KeyCtrlLeftSq // Escape
	KeyCtrlBackslash
	KeyCtrlRightSq
	KeyCtrlCarat
	KeyCtrlUnderscore
)

// These are the defined ASCII values for key codes.
const (
	KeyNUL Key = iota
	KeySOH
	KeySTX
	KeyETX
	KeyEOT
	KeyENQ
	KeyACK
	KeyBEL
	KeyBS
	KeyTAB
	KeyLF
	KeyVT
	KeyFF
	KeyCR
	KeySO
	KeySI
	KeyDLE
	KeyDC1
	KeyDC2
	KeyDC3
	KeyDC4
	KeyNAK
	KeySYN
	KeyETB
	KeyCAN
	KeyEM
	KeySUB
	KeyESC
	KeyFS
	KeyGS
	KeyRS
	KeyUS
	KeyDEL Key = 0x7F
)

// These are aliases for other keys.
const (
	KeyBackspace  = KeyBS
	KeyTab        = KeyTAB
	KeyEsc        = KeyESC
	KeyEscape     = KeyESC
	KeyEnter      = KeyCR
	KeyBackspace2 = KeyDEL
)

var keyNames = map[Key]string{
	KeyEnter:      "Enter",
	KeyBackspace:  "Backspace",
	KeyTab:        "Tab",
	KeyBacktab:    "Backtab",
	KeyEsc:        "Esc",
	KeyBackspace2: "Backspace2",
	KeyDelete:     "Delete",
	KeyInsert:     "Insert",
	KeyUp:         "Up",
	KeyDown:       "Down",
	KeyLeft:       "Left",
	KeyRight:      "Right",
	KeyCtrlSpace:  "Ctrl-Space",
	KeyCtrlA:      "Ctrl-A",
	KeyCtrlB:      "Ctrl-B",
	KeyCtrlC:      "Ctrl-C",
	KeyCtrlD:      "Ctrl-D",
	KeyCtrlE:      "Ctrl-E",
	KeyCtrlF:      "Ctrl-F",
	KeyCtrlG:      "Ctrl-G",
	KeyCtrlJ:      "Ctrl-J",
	KeyCtrlK:      "Ctrl-K",
	KeyCtrlL:      "Ctrl-L",
	KeyCtrlN:      "Ctrl-N",
	KeyCtrlO:      "Ctrl-O",
	KeyCtrlP:      "Ctrl-P",
	KeyCtrlQ:      "Ctrl-Q",
	KeyCtrlR:      "Ctrl-R",
	KeyCtrlS:      "Ctrl-S",
	KeyCtrlT:      "Ctrl-T",
	KeyCtrlU:      "Ctrl-U",
	KeyCtrlV:      "Ctrl-V",
	KeyCtrlW:      "Ctrl-W",
	KeyCtrlX:      "Ctrl-X",
	KeyCtrlY:      "Ctrl-Y",
	KeyCtrlZ:      "Ctrl-Z",
}

// MouseEvent represents the event where a mouse button was pressed or
// released.
type MouseEvent struct {
	Pos image.Point
}

type paintEvent struct{}

// callbackEvent holds a user-defined function which has been submitted
// to be called on the render thread.
type callbackEvent struct {
	cbFn func()
}

type event interface{}
<commit_msg>Bring key mappings up to date with tcell<commit_after>package tui

import (
	"fmt"
	"image"
	"strings"
)

// ModMask is a mask of modifier keys.
type ModMask int16

// Modifiers that can be sent with a KeyEvent or a MouseEvent.
const (
	ModShift ModMask = 1 << iota
	ModCtrl
	ModAlt
	ModMeta
	ModNone ModMask = 0
)

// KeyEvent represents a key press.
type KeyEvent struct {
	Key       Key
	Rune      rune
	Modifiers ModMask
}

// Name returns a user-friendly description of the key press.
func (ev *KeyEvent) Name() string {
	s := ""
	m := []string{}
	if ev.Modifiers&ModShift != 0 {
		m = append(m, "Shift")
	}
	if ev.Modifiers&ModAlt != 0 {
		m = append(m, "Alt")
	}
	if ev.Modifiers&ModMeta != 0 {
		m = append(m, "Meta")
	}
	if ev.Modifiers&ModCtrl != 0 {
		m = append(m, "Ctrl")
	}

	ok := false
	if s, ok = keyNames[ev.Key]; !ok {
		if ev.Key == KeyRune {
			s = string(ev.Rune)
		} else {
			s = "Unknown"
		}
	}
	if len(m) != 0 {
		if ev.Modifiers&ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") {
			s = s[5:]
		}
		return fmt.Sprintf("%s+%s", strings.Join(m, "+"), s)
	}
	return s
}

// Key represents both normal and special keys. For normal letters, KeyRune is
// used together with the Rune field in the KeyEvent.
type Key int16

// These are named keys that can be handled.
const (
	KeyRune Key = iota + 256
	KeyUp
	KeyDown
	KeyRight
	KeyLeft
	KeyUpLeft
	KeyUpRight
	KeyDownLeft
	KeyDownRight
	KeyCenter
	KeyPgUp
	KeyPgDn
	KeyHome
	KeyEnd
	KeyInsert
	KeyDelete
	KeyHelp
	KeyExit
	KeyClear
	KeyCancel
	KeyPrint
	KeyPause
	KeyBacktab
	KeyF1
	KeyF2
	KeyF3
	KeyF4
	KeyF5
	KeyF6
	KeyF7
	KeyF8
	KeyF9
	KeyF10
	KeyF11
	KeyF12
	KeyF13
	KeyF14
	KeyF15
	KeyF16
	KeyF17
	KeyF18
	KeyF19
	KeyF20
	KeyF21
	KeyF22
	KeyF23
	KeyF24
	KeyF25
	KeyF26
	KeyF27
	KeyF28
	KeyF29
	KeyF30
	KeyF31
	KeyF32
	KeyF33
	KeyF34
	KeyF35
	KeyF36
	KeyF37
	KeyF38
	KeyF39
	KeyF40
	KeyF41
	KeyF42
	KeyF43
	KeyF44
	KeyF45
	KeyF46
	KeyF47
	KeyF48
	KeyF49
	KeyF50
	KeyF51
	KeyF52
	KeyF53
	KeyF54
	KeyF55
	KeyF56
	KeyF57
	KeyF58
	KeyF59
	KeyF60
	KeyF61
	KeyF62
	KeyF63
	KeyF64
)

// These are the supported control keys.
const (
	KeyCtrlSpace Key = iota
	KeyCtrlA
	KeyCtrlB
	KeyCtrlC
	KeyCtrlD
	KeyCtrlE
	KeyCtrlF
	KeyCtrlG
	KeyCtrlH
	KeyCtrlI
	KeyCtrlJ
	KeyCtrlK
	KeyCtrlL
	KeyCtrlM
	KeyCtrlN
	KeyCtrlO
	KeyCtrlP
	KeyCtrlQ
	KeyCtrlR
	KeyCtrlS
	KeyCtrlT
	KeyCtrlU
	KeyCtrlV
	KeyCtrlW
	KeyCtrlX
	KeyCtrlY
	KeyCtrlZ
	KeyCtrlLeftSq // Escape
	KeyCtrlBackslash
	KeyCtrlRightSq
	KeyCtrlCarat
	KeyCtrlUnderscore
)

// These are the defined ASCII values for key codes.
const (
	KeyNUL Key = iota
	KeySOH
	KeySTX
	KeyETX
	KeyEOT
	KeyENQ
	KeyACK
	KeyBEL
	KeyBS
	KeyTAB
	KeyLF
	KeyVT
	KeyFF
	KeyCR
	KeySO
	KeySI
	KeyDLE
	KeyDC1
	KeyDC2
	KeyDC3
	KeyDC4
	KeyNAK
	KeySYN
	KeyETB
	KeyCAN
	KeyEM
	KeySUB
	KeyESC
	KeyFS
	KeyGS
	KeyRS
	KeyUS
	KeyDEL Key = 0x7F
)

// These are aliases for other keys.
const (
	KeyBackspace  = KeyBS
	KeyTab        = KeyTAB
	KeyEsc        = KeyESC
	KeyEscape     = KeyESC
	KeyEnter      = KeyCR
	KeyBackspace2 = KeyDEL
)

var keyNames = map[Key]string{
	KeyEnter:          "Enter",
	KeyBackspace:      "Backspace",
	KeyTab:            "Tab",
	KeyBacktab:        "Backtab",
	KeyEsc:            "Esc",
	KeyBackspace2:     "Backspace2",
	KeyInsert:         "Insert",
	KeyDelete:         "Delete",
	KeyHelp:           "Help",
	KeyUp:             "Up",
	KeyDown:           "Down",
	KeyLeft:           "Left",
	KeyRight:          "Right",
	KeyHome:           "Home",
	KeyEnd:            "End",
	KeyUpLeft:         "UpLeft",
	KeyUpRight:        "UpRight",
	KeyDownLeft:       "DownLeft",
	KeyDownRight:      "DownRight",
	KeyCenter:         "Center",
	KeyPgDn:           "PgDn",
	KeyPgUp:           "PgUp",
	KeyClear:          "Clear",
	KeyExit:           "Exit",
	KeyCancel:         "Cancel",
	KeyPause:          "Pause",
	KeyPrint:          "Print",
	KeyF1:             "F1",
	KeyF2:             "F2",
	KeyF3:             "F3",
	KeyF4:             "F4",
	KeyF5:             "F5",
	KeyF6:             "F6",
	KeyF7:             "F7",
	KeyF8:             "F8",
	KeyF9:             "F9",
	KeyF10:            "F10",
	KeyF11:            "F11",
	KeyF12:            "F12",
	KeyF13:            "F13",
	KeyF14:            "F14",
	KeyF15:            "F15",
	KeyF16:            "F16",
	KeyF17:            "F17",
	KeyF18:            "F18",
	KeyF19:            "F19",
	KeyF20:            "F20",
	KeyF21:            "F21",
	KeyF22:            "F22",
	KeyF23:            "F23",
	KeyF24:            "F24",
	KeyF25:            "F25",
	KeyF26:            "F26",
	KeyF27:            "F27",
	KeyF28:            "F28",
	KeyF29:            "F29",
	KeyF30:            "F30",
	KeyF31:            "F31",
	KeyF32:            "F32",
	KeyF33:            "F33",
	KeyF34:            "F34",
	KeyF35:            "F35",
	KeyF36:            "F36",
	KeyF37:            "F37",
	KeyF38:            "F38",
	KeyF39:            "F39",
	KeyF40:            "F40",
	KeyF41:            "F41",
	KeyF42:            "F42",
	KeyF43:            "F43",
	KeyF44:            "F44",
	KeyF45:            "F45",
	KeyF46:            "F46",
	KeyF47:            "F47",
	KeyF48:            "F48",
	KeyF49:            "F49",
	KeyF50:            "F50",
	KeyF51:            "F51",
	KeyF52:            "F52",
	KeyF53:            "F53",
	KeyF54:            "F54",
	KeyF55:            "F55",
	KeyF56:            "F56",
	KeyF57:            "F57",
	KeyF58:            "F58",
	KeyF59:            "F59",
	KeyF60:            "F60",
	KeyF61:            "F61",
	KeyF62:            "F62",
	KeyF63:            "F63",
	KeyF64:            "F64",
	KeyCtrlUnderscore: "Ctrl-_",
	KeyCtrlRightSq:    "Ctrl-]",
	KeyCtrlBackslash:  "Ctrl-\\",
	KeyCtrlCarat:      "Ctrl-^",
	KeyCtrlSpace:      "Ctrl-Space",
	KeyCtrlA:          "Ctrl-A",
	KeyCtrlB:          "Ctrl-B",
	KeyCtrlC:          "Ctrl-C",
	KeyCtrlD:          "Ctrl-D",
	KeyCtrlE:          "Ctrl-E",
	KeyCtrlF:          "Ctrl-F",
	KeyCtrlG:          "Ctrl-G",
	KeyCtrlJ:          "Ctrl-J",
	KeyCtrlK:          "Ctrl-K",
	KeyCtrlL:          "Ctrl-L",
	KeyCtrlN:          "Ctrl-N",
	KeyCtrlO:          "Ctrl-O",
	KeyCtrlP:          "Ctrl-P",
	KeyCtrlQ:          "Ctrl-Q",
	KeyCtrlR:          "Ctrl-R",
	KeyCtrlS:          "Ctrl-S",
	KeyCtrlT:          "Ctrl-T",
	KeyCtrlU:          "Ctrl-U",
	KeyCtrlV:          "Ctrl-V",
	KeyCtrlW:          "Ctrl-W",
	KeyCtrlX:          "Ctrl-X",
	KeyCtrlY:          "Ctrl-Y",
	KeyCtrlZ:          "Ctrl-Z",
}

// MouseEvent represents the event where a mouse button was pressed or
// released.
type MouseEvent struct {
	Pos image.Point
}

type paintEvent struct{}

// callbackEvent holds a user-defined function which has been submitted
// to be called on the render thread.
type callbackEvent struct {
	cbFn func()
}

type event interface{}
<|endoftext|>


<commit_before>package discordgo

import ()

// EventHandler is an interface for Discord events.
type EventHandler interface {
	// Type returns the type of event this handler belongs to.
	Type() string

	// Handle is called whenever an event of Type() happens.
	// It is the receivers responsibility to type assert that the interface
	// is the expected struct.
	Handle(*Session, interface{})
}

// EventInterfaceProvider is an interface for providing empty interfaces for
// Discord events.
type EventInterfaceProvider interface {
	// Type is the type of event this handler belongs to.
	Type() string

	// New returns a new instance of the struct this event handler handles.
	// This is called once per event.
	// The struct is provided to all handlers of the same Type().
	New() interface{}
}

// interfaceEventType is the event handler type for interface{} events.
const interfaceEventType = "__INTERFACE__"

// interfaceEventHandler is an event handler for interface{} events.
type interfaceEventHandler func(*Session, interface{})

// Type returns the event type for interface{} events.
func (eh interfaceEventHandler) Type() string {
	return interfaceEventType
}

// Handle is the handler for an interface{} event.
func (eh interfaceEventHandler) Handle(s *Session, i interface{}) {
	eh(s, i)
}

var registeredInterfaceProviders = map[string]EventInterfaceProvider{}

// registerInterfaceProvider registers a provider so that DiscordGo can
// access it's New() method.
func registerInterfaceProvider(eh EventInterfaceProvider) {
	if _, ok := registeredInterfaceProviders[eh.Type()]; ok {
		return
		// XXX:
		// if we should error here, we need to do something with it.
		// fmt.Errorf("event %s already registered", eh.Type())
	}
	registeredInterfaceProviders[eh.Type()] = eh

	// inst := eh.New()
	// if _, ok := inst.(ChannelEvent); ok {
	// 	fmt.Println(eh.Type(), " is channel event")
	// }

	// if _, ok := inst.(GuildEvent); ok {
	// 	fmt.Println(eh.Type(), " is guild event")
	// }
	// fmt.Println("--")

	return
}

func GetEventInterface(evtType string) interface{} {
	if provider, ok := registeredInterfaceProviders[evtType]; ok {
		return provider.New()
	}

	return nil
}

// eventHandlerInstance is a wrapper around an event handler, as functions
// cannot be compared directly.
type eventHandlerInstance struct {
	eventHandler EventHandler
}

// addEventHandler adds an event handler that will be fired anytime
// the Discord WSAPI matching eventHandler.Type() fires.
func (s *Session) addEventHandler(eventHandler EventHandler) func() {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	if s.handlers == nil {
		s.handlers = map[string][]*eventHandlerInstance{}
	}

	ehi := &eventHandlerInstance{eventHandler}
	s.handlers[eventHandler.Type()] = append(s.handlers[eventHandler.Type()], ehi)

	return func() {
		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
	}
}

// addEventHandler adds an event handler that will be fired the next time
// the Discord WSAPI matching eventHandler.Type() fires.
func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	if s.onceHandlers == nil {
		s.onceHandlers = map[string][]*eventHandlerInstance{}
	}

	ehi := &eventHandlerInstance{eventHandler}
	s.onceHandlers[eventHandler.Type()] = append(s.onceHandlers[eventHandler.Type()], ehi)

	return func() {
		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
	}
}

// AddHandler allows you to add an event handler that will be fired anytime
// the Discord WSAPI event that matches the function fires.
// The first parameter is a *Session, and the second parameter is a pointer
// to a struct corresponding to the event for which you want to listen.
//
// eg:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
//     })
//
// or:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
//     })
//
// List of events can be found at this page, with corresponding names in the
// library for each event: https://discordapp.com/developers/docs/topics/gateway#event-names
// There are also synthetic events fired by the library internally which are
// available for handling, like Connect, Disconnect, and RateLimit.
// events.go contains all of the Discord WSAPI and synthetic events that can be handled.
//
// The return value of this method is a function, that when called will remove the
// event handler.
func (s *Session) AddHandler(handler interface{}) func() {
	eh := handlerForInterface(handler)

	if eh == nil {
		s.log(LogError, "Invalid handler type, handler will never be called")
		return func() {}
	}

	return s.addEventHandler(eh)
}

// AddHandlerOnce allows you to add an event handler that will be fired the next time
// the Discord WSAPI event that matches the function fires.
// See AddHandler for more details.
func (s *Session) AddHandlerOnce(handler interface{}) func() {
	eh := handlerForInterface(handler)

	if eh == nil {
		s.log(LogError, "Invalid handler type, handler will never be called")
		return func() {}
	}

	return s.addEventHandlerOnce(eh)
}

// removeEventHandler instance removes an event handler instance.
func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance) {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	handlers := s.handlers[t]
	for i := range handlers {
		if handlers[i] == ehi {
			s.handlers[t] = append(handlers[:i], handlers[i+1:]...)
		}
	}

	onceHandlers := s.onceHandlers[t]
	for i := range onceHandlers {
		if onceHandlers[i] == ehi {
			s.onceHandlers[t] = append(onceHandlers[:i], handlers[i+1:]...)
		}
	}
}

// Handles calling permanent and once handlers for an event type.
func (s *Session) handle(t string, i interface{}) {
	for _, eh := range s.handlers[t] {
		if s.SyncEvents {
			eh.eventHandler.Handle(s, i)
		} else {
			go eh.eventHandler.Handle(s, i)
		}
	}

	if len(s.onceHandlers[t]) > 0 {
		for _, eh := range s.onceHandlers[t] {
			if s.SyncEvents {
				eh.eventHandler.Handle(s, i)
			} else {
				go eh.eventHandler.Handle(s, i)
			}
		}
		s.onceHandlers[t] = nil
	}
}

// Handles an event type by calling internal methods, firing handlers and firing the
// interface{} event.
func (s *Session) handleEvent(t string, i interface{}) {
	s.handlersMu.RLock()
	defer s.handlersMu.RUnlock()

	// All events are dispatched internally first.
	s.onInterface(i)

	// Then they are dispatched to anyone handling interface{} events.
	s.handle(interfaceEventType, i)

	// Finally they are dispatched to any typed handlers.
	s.handle(t, i)
}

// setGuildIds will set the GuildID on all the members of a guild.
// This is done as event data does not have it set.
func setGuildIds(g *Guild) {
	for _, c := range g.Channels {
		c.GuildID = g.ID
	}

	for _, m := range g.Members {
		m.GuildID = g.ID
	}

	for _, vs := range g.VoiceStates {
		vs.GuildID = g.ID
	}
}

// onInterface handles all internal events and routes them to the appropriate internal handler.
func (s *Session) onInterface(i interface{}) {
	switch t := i.(type) {
	case *Ready:
		for _, g := range t.Guilds {
			setGuildIds(g)
		}
	case *GuildCreate:
		setGuildIds(t.Guild)
	case *GuildUpdate:
		setGuildIds(t.Guild)
	case *VoiceServerUpdate:
		go s.GatewayManager.onVoiceServerUpdate(t)
	case *VoiceStateUpdate:
		go s.GatewayManager.onVoiceStateUpdate(t)
	}
	err := s.State.OnInterface(s, i)
	if err != nil {
		s.log(LogDebug, "error dispatching internal event, %s", err)
	}
}
<commit_msg>added exposed HandleEvent function<commit_after>package discordgo

import ()

// EventHandler is an interface for Discord events.
type EventHandler interface {
	// Type returns the type of event this handler belongs to.
	Type() string

	// Handle is called whenever an event of Type() happens.
	// It is the receivers responsibility to type assert that the interface
	// is the expected struct.
	Handle(*Session, interface{})
}

// EventInterfaceProvider is an interface for providing empty interfaces for
// Discord events.
type EventInterfaceProvider interface {
	// Type is the type of event this handler belongs to.
	Type() string

	// New returns a new instance of the struct this event handler handles.
	// This is called once per event.
	// The struct is provided to all handlers of the same Type().
	New() interface{}
}

// interfaceEventType is the event handler type for interface{} events.
const interfaceEventType = "__INTERFACE__"

// interfaceEventHandler is an event handler for interface{} events.
type interfaceEventHandler func(*Session, interface{})

// Type returns the event type for interface{} events.
func (eh interfaceEventHandler) Type() string {
	return interfaceEventType
}

// Handle is the handler for an interface{} event.
func (eh interfaceEventHandler) Handle(s *Session, i interface{}) {
	eh(s, i)
}

var registeredInterfaceProviders = map[string]EventInterfaceProvider{}

// registerInterfaceProvider registers a provider so that DiscordGo can
// access it's New() method.
func registerInterfaceProvider(eh EventInterfaceProvider) {
	if _, ok := registeredInterfaceProviders[eh.Type()]; ok {
		return
		// XXX:
		// if we should error here, we need to do something with it.
		// fmt.Errorf("event %s already registered", eh.Type())
	}
	registeredInterfaceProviders[eh.Type()] = eh

	// inst := eh.New()
	// if _, ok := inst.(ChannelEvent); ok {
	// 	fmt.Println(eh.Type(), " is channel event")
	// }

	// if _, ok := inst.(GuildEvent); ok {
	// 	fmt.Println(eh.Type(), " is guild event")
	// }
	// fmt.Println("--")

	return
}

func GetEventInterface(evtType string) interface{} {
	if provider, ok := registeredInterfaceProviders[evtType]; ok {
		return provider.New()
	}

	return nil
}

// eventHandlerInstance is a wrapper around an event handler, as functions
// cannot be compared directly.
type eventHandlerInstance struct {
	eventHandler EventHandler
}

// addEventHandler adds an event handler that will be fired anytime
// the Discord WSAPI matching eventHandler.Type() fires.
func (s *Session) addEventHandler(eventHandler EventHandler) func() {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	if s.handlers == nil {
		s.handlers = map[string][]*eventHandlerInstance{}
	}

	ehi := &eventHandlerInstance{eventHandler}
	s.handlers[eventHandler.Type()] = append(s.handlers[eventHandler.Type()], ehi)

	return func() {
		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
	}
}

// addEventHandler adds an event handler that will be fired the next time
// the Discord WSAPI matching eventHandler.Type() fires.
func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	if s.onceHandlers == nil {
		s.onceHandlers = map[string][]*eventHandlerInstance{}
	}

	ehi := &eventHandlerInstance{eventHandler}
	s.onceHandlers[eventHandler.Type()] = append(s.onceHandlers[eventHandler.Type()], ehi)

	return func() {
		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
	}
}

// AddHandler allows you to add an event handler that will be fired anytime
// the Discord WSAPI event that matches the function fires.
// The first parameter is a *Session, and the second parameter is a pointer
// to a struct corresponding to the event for which you want to listen.
//
// eg:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
//     })
//
// or:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
//     })
//
// List of events can be found at this page, with corresponding names in the
// library for each event: https://discordapp.com/developers/docs/topics/gateway#event-names
// There are also synthetic events fired by the library internally which are
// available for handling, like Connect, Disconnect, and RateLimit.
// events.go contains all of the Discord WSAPI and synthetic events that can be handled.
//
// The return value of this method is a function, that when called will remove the
// event handler.
func (s *Session) AddHandler(handler interface{}) func() {
	eh := handlerForInterface(handler)

	if eh == nil {
		s.log(LogError, "Invalid handler type, handler will never be called")
		return func() {}
	}

	return s.addEventHandler(eh)
}

// AddHandlerOnce allows you to add an event handler that will be fired the next time
// the Discord WSAPI event that matches the function fires.
// See AddHandler for more details.
func (s *Session) AddHandlerOnce(handler interface{}) func() {
	eh := handlerForInterface(handler)

	if eh == nil {
		s.log(LogError, "Invalid handler type, handler will never be called")
		return func() {}
	}

	return s.addEventHandlerOnce(eh)
}

// removeEventHandler instance removes an event handler instance.
func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance) {
	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	handlers := s.handlers[t]
	for i := range handlers {
		if handlers[i] == ehi {
			s.handlers[t] = append(handlers[:i], handlers[i+1:]...)
		}
	}

	onceHandlers := s.onceHandlers[t]
	for i := range onceHandlers {
		if onceHandlers[i] == ehi {
			s.onceHandlers[t] = append(onceHandlers[:i], handlers[i+1:]...)
		}
	}
}

// Handles calling permanent and once handlers for an event type.
func (s *Session) handle(t string, i interface{}) {
	for _, eh := range s.handlers[t] {
		if s.SyncEvents {
			eh.eventHandler.Handle(s, i)
		} else {
			go eh.eventHandler.Handle(s, i)
		}
	}

	if len(s.onceHandlers[t]) > 0 {
		for _, eh := range s.onceHandlers[t] {
			if s.SyncEvents {
				eh.eventHandler.Handle(s, i)
			} else {
				go eh.eventHandler.Handle(s, i)
			}
		}
		s.onceHandlers[t] = nil
	}
}

// Handles an event type by calling internal methods, firing handlers and firing the
// interface{} event.
func (s *Session) HandleEvent(t string, i interface{}) {
	s.handleEvent(t, i)
}

// Handles an event type by calling internal methods, firing handlers and firing the
// interface{} event.
func (s *Session) handleEvent(t string, i interface{}) {
	s.handlersMu.RLock()
	defer s.handlersMu.RUnlock()

	// All events are dispatched internally first.
	s.onInterface(i)

	// Then they are dispatched to anyone handling interface{} events.
	s.handle(interfaceEventType, i)

	// Finally they are dispatched to any typed handlers.
	s.handle(t, i)
}

// setGuildIds will set the GuildID on all the members of a guild.
// This is done as event data does not have it set.
func setGuildIds(g *Guild) {
	for _, c := range g.Channels {
		c.GuildID = g.ID
	}

	for _, m := range g.Members {
		m.GuildID = g.ID
	}

	for _, vs := range g.VoiceStates {
		vs.GuildID = g.ID
	}
}

// onInterface handles all internal events and routes them to the appropriate internal handler.
func (s *Session) onInterface(i interface{}) {
	switch t := i.(type) {
	case *Ready:
		for _, g := range t.Guilds {
			setGuildIds(g)
		}
	case *GuildCreate:
		setGuildIds(t.Guild)
	case *GuildUpdate:
		setGuildIds(t.Guild)
	case *VoiceServerUpdate:
		go s.GatewayManager.onVoiceServerUpdate(t)
	case *VoiceStateUpdate:
		go s.GatewayManager.onVoiceStateUpdate(t)
	}
	err := s.State.OnInterface(s, i)
	if err != nil {
		s.log(LogDebug, "error dispatching internal event, %s", err)
	}
}
<|endoftext|>


<commit_before>package faidx

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/biogo/biogo/io/seqio/fai"
	"github.com/edsrzf/mmap-go"
)

// Faidx is used to provide random access to the sequence data.
type Faidx struct {
	rdr   io.ReadSeeker
	Index fai.Index
	mmap  mmap.MMap
}

// ErrorNoFai is returned if the fasta doesn't have an associated .fai
var ErrorNoFai = errors.New("no fai for fasta")

func notExists(path string) error {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return err
	}
	return nil
}

// New returns a faidx object from a fasta file that has an existing index.
func New(fasta string) (*Faidx, error) {
	err := notExists(fasta + ".fai")
	if err != nil {
		return nil, ErrorNoFai
	}
	fh, err := os.Open(fasta + ".fai")
	if err != nil {
		return nil, err
	}
	idx, err := fai.ReadFrom(fh)
	if err != nil {
		return nil, err
	}
	rdr, err := os.Open(fasta)
	if err != nil {
		return nil, err
	}

	smap, err := mmap.Map(rdr, mmap.RDONLY, 0)
	if err != nil {
		return nil, err
	}

	return &Faidx{rdr, idx, smap}, nil
}

func position(r fai.Record, p int) int64 {
	if p < 0 || r.Length < p {
		panic(fmt.Sprintf("fai: index [%d] out of range in %s which has length: %d", p, r.Name, r.Length))
	}
	return r.Start + int64(p/r.BasesPerLine*r.BytesPerLine+p%r.BasesPerLine)
}

// Get takes a position and returns the string sequence. Start and end are 0-based.
func (f *Faidx) Get(chrom string, start int, end int) (string, error) {
	idx, ok := f.Index[chrom]
	if !ok {
		return "", fmt.Errorf("unknown sequence %s", chrom)
	}

	pstart := position(idx, start)
	pend := position(idx, end)
	buf := f.mmap[pstart:pend]
	buf = bytes.Replace(buf, []byte{'\n'}, []byte{}, -1)
	return string(buf), nil
}

// Stats hold sequenc information.
type Stats struct {
	// GC content fraction
	GC float64
	// CpG content fraction
	CpG float64
	// masked (lower-case fraction
	Masked float64
}

func min(a, b float64) float64 {
	if b < a {
		return b
	}
	return a
}

// Stats returns the proportion of GC's (GgCc), the CpG content (Cc follow by Gg)
// and the proportion of lower-case bases (masked).
// CpG will be 1.0 if the requested sequence is CGC and the base that follows is G
func (f *Faidx) Stats(chrom string, start int, end int) (Stats, error) {
	// copied from cnvkit.
	idx, ok := f.Index[chrom]
	if !ok {
		return Stats{}, fmt.Errorf("unknown sequence %s", chrom)
	}
	pstart := position(idx, start)
	pend := position(idx, end)
	oend := pend
	if pend < int64(len(f.mmap)) {
		oend++
	}

	var gcUp, gcLo, atUp, atLo, cpg int
	buf := f.mmap[pstart:oend]
	for i, v := range buf {
		// we added 1 to do the GC content...
		if i == len(buf)-1 {
			break
		}
		if v == 'G' || v == 'C' {
			if v == 'C' && (buf[i+1] == 'G' || buf[i+1] == 'g') {
				cpg++
			}
			gcUp++
		} else if v == 'A' || v == 'T' {
			atUp++
		} else if v == 'g' || v == 'c' {
			if v == 'c' && (buf[i+1] == 'G' || buf[i+1] == 'g') {
				cpg++
			}
			gcLo++
		} else if v == 'a' || v == 't' {
			atLo++
		}
	}
	tot := float64(gcUp + gcLo + atUp + atLo)
	if tot == 0.0 {
		return Stats{}, nil
	}
	return Stats{
		GC:     float64(gcLo+gcUp) / tot,
		Masked: float64(atLo+gcLo) / tot,
		CpG:    min(1.0, float64(2*cpg)/tot)}, nil
}

// GcPosition allows the user to specify the position and internally, faidx will
// store information in it to speed GC calcs to adjacent regions. Useful for, when
// we sweep along the genome 1 base at a time, but we want to know the GC content for
// a window around each base.
type GcPosition struct {
	Chrom string
	Start int
	End   int

	lastChrom string
	lastStart int
	lastEnd   int
	lastCount int
}

// GC gets only the count of GC GC-content it can do the calculation quickly for
// repeated calls marching to higher bases along the genome.
func (f *Faidx) GC(pos *GcPosition) (int, error) {
	// we can't use any info from the cache
	idx, ok := f.Index[pos.Chrom]
	if !ok {
		return 0, fmt.Errorf("GC: unknown sequence %s", pos.Chrom)
	}

	if pos.lastStart > pos.Start || pos.Start >= pos.lastEnd || pos.lastEnd > pos.End || pos.Chrom != pos.lastChrom {
		pos.lastChrom = pos.Chrom
		pos.lastCount = 0
		for i := position(idx, pos.Start); i < position(idx, pos.End); i++ {
			if b := f.mmap[i]; b == 'G' || b == 'C' || b == 'c' || b == 'g' {
				pos.lastCount++
			}
		}
	} else {
		/*
		 ls -------------- le
		       s----------------e
		*/
		for _, b := range f.mmap[position(idx, pos.lastStart):position(idx, pos.Start)] {
			if b == 'G' || b == 'C' || b == 'c' || b == 'g' {
				pos.lastCount--
			}
		}
		for _, b := range f.mmap[position(idx, pos.lastEnd):position(idx, pos.End)] {
			if b == 'G' || b == 'C' || b == 'c' || b == 'g' {
				pos.lastCount++
			}
		}

	}
	pos.lastStart = pos.Start
	pos.lastEnd = pos.End
	return pos.lastCount, nil
}

// At takes a single point and returns the single base.
func (f *Faidx) At(chrom string, pos int) (byte, error) {
	idx, ok := f.Index[chrom]
	if !ok {
		return '*', fmt.Errorf("unknown sequence %s", chrom)
	}

	ppos := position(idx, pos)
	return f.mmap[ppos], nil
}

// Close the associated Reader.
func (f *Faidx) Close() {
	f.rdr.(io.Closer).Close()
	f.mmap.Unmap()
}
<commit_msg>use uint32 and more efficient access when re-starting<commit_after>package faidx

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/biogo/biogo/io/seqio/fai"
	"github.com/edsrzf/mmap-go"
)

// Faidx is used to provide random access to the sequence data.
type Faidx struct {
	rdr   io.ReadSeeker
	Index fai.Index
	mmap  mmap.MMap
}

// ErrorNoFai is returned if the fasta doesn't have an associated .fai
var ErrorNoFai = errors.New("no fai for fasta")

func notExists(path string) error {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return err
	}
	return nil
}

// New returns a faidx object from a fasta file that has an existing index.
func New(fasta string) (*Faidx, error) {
	err := notExists(fasta + ".fai")
	if err != nil {
		return nil, ErrorNoFai
	}
	fh, err := os.Open(fasta + ".fai")
	if err != nil {
		return nil, err
	}
	idx, err := fai.ReadFrom(fh)
	if err != nil {
		return nil, err
	}
	rdr, err := os.Open(fasta)
	if err != nil {
		return nil, err
	}

	smap, err := mmap.Map(rdr, mmap.RDONLY, 0)
	if err != nil {
		return nil, err
	}

	return &Faidx{rdr, idx, smap}, nil
}

func position(r fai.Record, p int) int64 {
	if p < 0 || r.Length < p {
		panic(fmt.Sprintf("fai: index [%d] out of range in %s which has length: %d", p, r.Name, r.Length))
	}
	return r.Start + int64(p/r.BasesPerLine*r.BytesPerLine+p%r.BasesPerLine)
}

// Get takes a position and returns the string sequence. Start and end are 0-based.
func (f *Faidx) Get(chrom string, start int, end int) (string, error) {
	idx, ok := f.Index[chrom]
	if !ok {
		return "", fmt.Errorf("unknown sequence %s", chrom)
	}

	pstart := position(idx, start)
	pend := position(idx, end)
	buf := f.mmap[pstart:pend]
	buf = bytes.Replace(buf, []byte{'\n'}, []byte{}, -1)
	return string(buf), nil
}

// Stats hold sequenc information.
type Stats struct {
	// GC content fraction
	GC float64
	// CpG content fraction
	CpG float64
	// masked (lower-case fraction
	Masked float64
}

func min(a, b float64) float64 {
	if b < a {
		return b
	}
	return a
}

// Stats returns the proportion of GC's (GgCc), the CpG content (Cc follow by Gg)
// and the proportion of lower-case bases (masked).
// CpG will be 1.0 if the requested sequence is CGC and the base that follows is G
func (f *Faidx) Stats(chrom string, start int, end int) (Stats, error) {
	// copied from cnvkit.
	idx, ok := f.Index[chrom]
	if !ok {
		return Stats{}, fmt.Errorf("unknown sequence %s", chrom)
	}
	pstart := position(idx, start)
	pend := position(idx, end)
	oend := pend
	if pend < int64(len(f.mmap)) {
		oend++
	}

	var gcUp, gcLo, atUp, atLo, cpg int
	buf := f.mmap[pstart:oend]
	for i, v := range buf {
		// we added 1 to do the GC content...
		if i == len(buf)-1 {
			break
		}
		if v == 'G' || v == 'C' {
			if v == 'C' && (buf[i+1] == 'G' || buf[i+1] == 'g') {
				cpg++
			}
			gcUp++
		} else if v == 'A' || v == 'T' {
			atUp++
		} else if v == 'g' || v == 'c' {
			if v == 'c' && (buf[i+1] == 'G' || buf[i+1] == 'g') {
				cpg++
			}
			gcLo++
		} else if v == 'a' || v == 't' {
			atLo++
		}
	}
	tot := float64(gcUp + gcLo + atUp + atLo)
	if tot == 0.0 {
		return Stats{}, nil
	}
	return Stats{
		GC:     float64(gcLo+gcUp) / tot,
		Masked: float64(atLo+gcLo) / tot,
		CpG:    min(1.0, float64(2*cpg)/tot)}, nil
}

// GcPosition allows the user to specify the position and internally, faidx will
// store information in it to speed GC calcs to adjacent regions. Useful for, when
// we sweep along the genome 1 base at a time, but we want to know the GC content for
// a window around each base.
type GcPosition struct {
	Chrom string
	Start int
	End   int

	lastChrom string
	lastStart int
	lastEnd   int
	lastCount uint32
}

// GC gets only the count of GC GC-content it can do the calculation quickly for
// repeated calls marching to higher bases along the genome.
func (f *Faidx) GC(pos *GcPosition) (uint32, error) {
	// we can't use any info from the cache
	idx, ok := f.Index[pos.Chrom]
	if !ok {
		return 0, fmt.Errorf("GC: unknown sequence %s", pos.Chrom)
	}

	if pos.lastStart > pos.Start || pos.Start >= pos.lastEnd || pos.lastEnd > pos.End || pos.Chrom != pos.lastChrom {
		pos.lastChrom = pos.Chrom
		pos.lastCount = 0
		for _, b := range f.mmap[position(idx, pos.Start):position(idx, pos.End)] {
			if b == 'G' || b == 'C' || b == 'c' || b == 'g' {
				pos.lastCount++
			}
		}
	} else {
		/*
		 ls -------------- le
		       s----------------e
		*/
		for _, b := range f.mmap[position(idx, pos.lastStart):position(idx, pos.Start)] {
			if b == 'G' || b == 'C' || b == 'c' || b == 'g' {
				pos.lastCount--
			}
		}
		for _, b := range f.mmap[position(idx, pos.lastEnd):position(idx, pos.End)] {
			if b == 'G' || b == 'C' || b == 'c' || b == 'g' {
				pos.lastCount++
			}
		}

	}
	pos.lastStart = pos.Start
	pos.lastEnd = pos.End
	return pos.lastCount, nil
}

// At takes a single point and returns the single base.
func (f *Faidx) At(chrom string, pos int) (byte, error) {
	idx, ok := f.Index[chrom]
	if !ok {
		return '*', fmt.Errorf("unknown sequence %s", chrom)
	}

	ppos := position(idx, pos)
	return f.mmap[ppos], nil
}

// Close the associated Reader.
func (f *Faidx) Close() {
	f.rdr.(io.Closer).Close()
	f.mmap.Unmap()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"go/build"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"

	. "github.com/AlekSi/nut"
)

var (
	cmdGet = &Command{
		Run:       runGet,
		UsageLine: "get [-p prefix] [-v] [name or URL]",
		Short:     "download and install nut and dependencies",
	}

	getP string
	getV bool
)

func init() {
	cmdGet.Long = `
Download and install nut and dependencies from http://gonuts.io/ or specified URL.
	`

	cmdGet.Flag.StringVar(&getP, "p", "", "install prefix in workspace, uses hostname if omitted")
	cmdGet.Flag.BoolVar(&getV, "v", false, vHelp)
}

func ArgToURL(s string) *url.URL {
	var p []string
	var host string
	var ok bool

	// full URL - as is
	if strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://") {
		goto parse
	}

	p = strings.Split(s, "/")
	if len(p) > 0 {
		host, ok = NutImportPrefixes[p[0]]
	}
	if ok {
		// import path style
		p[0] = "http://" + host
		s = strings.Join(p, "/")
	} else {
		// short style
		s = fmt.Sprintf("http://%s/%s", NutImportPrefixes["gonuts.io"], s)
	}

parse:
	u, err := url.Parse(s)
	PanicIfErr(err)
	return u
}

func get(url *url.URL) (b []byte, err error) {
	if getV {
		log.Printf("Getting %s ...", url)
	}

	req, err := http.NewRequest("GET", url.String(), nil)
	if err != nil {
		return
	}
	req.Header.Set("User-Agent", "nut getter")
	req.Header.Set("Accept", "application/zip")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	defer res.Body.Close()

	b, err = ioutil.ReadAll(res.Body)
	if err != nil {
		return
	}

	if res.StatusCode/100 != 2 {
		err = fmt.Errorf("Status code %d", res.StatusCode)
		return
	}

	if getV {
		log.Printf("Status code %d", res.StatusCode)
	}

	return
}

func runGet(cmd *Command) {
	if !getV {
		getV = config.V
	}

	args := cmd.Flag.Args()

	// zero arguments is a special case – install dependencies for package in current directory
	if len(args) == 0 {
		pack, err := build.ImportDir(".", 0)
		PanicIfErr(err)
		args = NutImports(pack.Imports)
		if getV && len(args) != 0 {
			log.Printf("%s depends on nuts: %s", pack.Name, strings.Join(args, ","))
		}
	}

	installPaths := make([]string, 0, len(args))
	for len(args) != 0 {
		arg := args[0]
		args = args[1:]

		url := ArgToURL(arg)
		b, err := get(url)
		PanicIfErr(err)

		nf := new(NutFile)
		nf.ReadFrom(bytes.NewReader(b))
		deps := NutImports(nf.Imports)
		if getV && len(deps) != 0 {
			log.Printf("%s depends on nuts: %s", nf.Name, strings.Join(deps, ","))
		}
		args = append(args, deps...)

		p := getP
		if p == "" {
			if strings.Contains(url.Host, ":") {
				p, _, err = net.SplitHostPort(url.Host)
				PanicIfErr(err)
			} else {
				p = url.Host
			}
			if strings.HasPrefix(p, "www.") {
				p = p[4:]
			}
		}
		fileName := WriteNut(b, p, getV)
		path := filepath.Join(p, nf.Name, nf.Version.String())

		UnpackNut(fileName, filepath.Join(SrcDir, path), true, getV)
		installPaths = append(installPaths, path)
	}

	for _, path := range installPaths {
		InstallPackage(path, getV)
	}
}
<commit_msg>Run go install only once for each package.<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/build"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"

	. "github.com/AlekSi/nut"
)

var (
	cmdGet = &Command{
		Run:       runGet,
		UsageLine: "get [-p prefix] [-v] [name or URL]",
		Short:     "download and install nut and dependencies",
	}

	getP string
	getV bool
)

func init() {
	cmdGet.Long = `
Download and install nut and dependencies from http://gonuts.io/ or specified URL.
	`

	cmdGet.Flag.StringVar(&getP, "p", "", "install prefix in workspace, uses hostname if omitted")
	cmdGet.Flag.BoolVar(&getV, "v", false, vHelp)
}

func ArgToURL(s string) *url.URL {
	var p []string
	var host string
	var ok bool

	// full URL - as is
	if strings.HasPrefix(s, "http://") || strings.HasPrefix(s, "https://") {
		goto parse
	}

	p = strings.Split(s, "/")
	if len(p) > 0 {
		host, ok = NutImportPrefixes[p[0]]
	}
	if ok {
		// import path style
		p[0] = "http://" + host
		s = strings.Join(p, "/")
	} else {
		// short style
		s = fmt.Sprintf("http://%s/%s", NutImportPrefixes["gonuts.io"], s)
	}

parse:
	u, err := url.Parse(s)
	PanicIfErr(err)
	return u
}

func get(url *url.URL) (b []byte, err error) {
	if getV {
		log.Printf("Getting %s ...", url)
	}

	req, err := http.NewRequest("GET", url.String(), nil)
	if err != nil {
		return
	}
	req.Header.Set("User-Agent", "nut getter")
	req.Header.Set("Accept", "application/zip")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	defer res.Body.Close()

	b, err = ioutil.ReadAll(res.Body)
	if err != nil {
		return
	}

	if res.StatusCode/100 != 2 {
		err = fmt.Errorf("Status code %d", res.StatusCode)
		return
	}

	if getV {
		log.Printf("Status code %d", res.StatusCode)
	}

	return
}

func runGet(cmd *Command) {
	if !getV {
		getV = config.V
	}

	args := cmd.Flag.Args()

	// zero arguments is a special case – install dependencies for package in current directory
	if len(args) == 0 {
		pack, err := build.ImportDir(".", 0)
		PanicIfErr(err)
		args = NutImports(pack.Imports)
		if getV && len(args) != 0 {
			log.Printf("%s depends on nuts: %s", pack.Name, strings.Join(args, ","))
		}
	}

	installPaths := make(map[string]bool, len(args))
	for len(args) != 0 {
		arg := args[0]
		args = args[1:]

		url := ArgToURL(arg)
		b, err := get(url)
		PanicIfErr(err)

		nf := new(NutFile)
		nf.ReadFrom(bytes.NewReader(b))
		deps := NutImports(nf.Imports)
		if getV && len(deps) != 0 {
			log.Printf("%s depends on nuts: %s", nf.Name, strings.Join(deps, ","))
		}
		args = append(args, deps...)

		p := getP
		if p == "" {
			if strings.Contains(url.Host, ":") {
				p, _, err = net.SplitHostPort(url.Host)
				PanicIfErr(err)
			} else {
				p = url.Host
			}
			if strings.HasPrefix(p, "www.") {
				p = p[4:]
			}
		}
		fileName := WriteNut(b, p, getV)
		path := filepath.Join(p, nf.Name, nf.Version.String())

		UnpackNut(fileName, filepath.Join(SrcDir, path), true, getV)
		installPaths[path] = true
	}

	for path := range installPaths {
		InstallPackage(path, getV)
	}
}
<|endoftext|>