<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 (
	"syscall"
	"sync"
	"os"
)

// BUG(brainman): The Windows implementation assumes that
// this year's rules for daylight savings time apply to all previous
// and future years as well.

// TODO(brainman): use GetDynamicTimeZoneInformation, whenever possible (Vista and up),
// to improve on situation described in the bug above.

type zone struct {
	name                  string
	offset                int
	year                  int64
	month, day, dayofweek int
	hour, minute, second  int
	abssec                int64
	prev                  *zone
}

// BUG(rsc): On Windows, time zone abbreviations are unavailable.
// This package constructs them using the capital letters from a longer
// time zone description.

// Populate zone struct with Windows supplied information. Returns true, if data is valid.
func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) {
	// name is 'Pacific Standard Time' but we want 'PST'.
	// Extract just capital letters.  It's not perfect but the
	// information we need is not available from the kernel.
	// Because time zone abbreviations are not unique,
	// Windows refuses to expose them.
	//
	// http://social.msdn.microsoft.com/Forums/eu/vclanguage/thread/a87e1d25-fb71-4fe0-ae9c-a9578c9753eb
	// http://stackoverflow.com/questions/4195948/windows-time-zone-abbreviations-in-asp-net
	short := make([]uint16, len(name))
	w := 0
	for _, c := range name {
		if 'A' <= c && c <= 'Z' {
			short[w] = c
			w++
		}
	}
	z.name = syscall.UTF16ToString(short[:w])

	z.offset = int(bias)
	z.year = int64(d.Year)
	z.month = int(d.Month)
	z.day = int(d.Day)
	z.dayofweek = int(d.DayOfWeek)
	z.hour = int(d.Hour)
	z.minute = int(d.Minute)
	z.second = int(d.Second)
	dateisgood = d.Month != 0
	if dateisgood {
		z.offset += int(biasdelta)
	}
	z.offset = -z.offset * 60
	return
}

// Pre-calculate cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
func (z *zone) preCalculateAbsSec() {
	if z.year != 0 {
		z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 0, 0, ""}).Seconds()
		// Time given is in "local" time. Adjust it for "utc".
		z.abssec -= int64(z.prev.offset)
	}
}

// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particular year.
func (z *zone) cutoffSeconds(year int64) int64 {
	// Windows specifies daylight savings information in "day in month" format:
	// z.month is month number (1-12)
	// z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6)
	// z.day is week within the month (1 to 5, where 5 is last week of the month)
	// z.hour, z.minute and z.second are absolute time
	t := &Time{year, int(z.month), 1, int(z.hour), int(z.minute), int(z.second), 0, 0, 0, ""}
	t = SecondsToUTC(t.Seconds())
	i := int(z.dayofweek) - t.Weekday
	if i < 0 {
		i += 7
	}
	t.Day += i
	if week := int(z.day) - 1; week < 4 {
		t.Day += week * 7
	} else {
		// "Last" instance of the day.
		t.Day += 4 * 7
		if t.Day > months(year)[t.Month] {
			t.Day -= 7
		}
	}
	// Result is in "local" time. Adjust it for "utc".
	return t.Seconds() - int64(z.prev.offset)
}

// Is t before the cutoff for switching to z?
func (z *zone) isBeforeCutoff(t *Time) bool {
	var coff int64
	if z.year == 0 {
		// "day in month" format used
		coff = z.cutoffSeconds(t.Year)
	} else {
		// "absolute" format used
		coff = z.abssec
	}
	return t.Seconds() < coff
}

type zoneinfo struct {
	disabled         bool // daylight saving time is not used locally
	offsetIfDisabled int
	januaryIsStd     bool // is january 1 standard time?
	std, dst         zone
}

// Pick zone (std or dst) t time belongs to.
func (zi *zoneinfo) pickZone(t *Time) *zone {
	z := &zi.std
	if tz.januaryIsStd {
		if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) {
			// after switch to daylight time and before the switch back to standard
			z = &zi.dst
		}
	} else {
		if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) {
			// before switch to standard time or after the switch back to daylight
			z = &zi.dst
		}
	}
	return z
}

var tz zoneinfo
var initError os.Error
var onceSetupZone sync.Once

func setupZone() {
	var i syscall.Timezoneinformation
	if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
		initError = os.NewSyscallError("GetTimeZoneInformation", e)
		return
	}
	setupZoneFromTZI(&i)
}

func setupZoneFromTZI(i *syscall.Timezoneinformation) {
	if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) {
		tz.disabled = true
		tz.offsetIfDisabled = tz.std.offset
		return
	}
	tz.std.prev = &tz.dst
	tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:])
	tz.dst.prev = &tz.std
	tz.std.preCalculateAbsSec()
	tz.dst.preCalculateAbsSec()
	// Is january 1 standard time this year?
	t := UTC()
	tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year)
}

var usPacific = syscall.Timezoneinformation{
	Bias: 8 * 60,
	StandardName: [32]uint16{
		'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e',
	},
	StandardDate: syscall.Systemtime{Month: 11, Day: 1, Hour: 2},
	DaylightName: [32]uint16{
		'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e',
	},
	DaylightDate: syscall.Systemtime{Month: 3, Day: 2, Hour: 2},
	DaylightBias: -60,
}

func setupTestingZone() {
	setupZoneFromTZI(&usPacific)
}

// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
func lookupTimezone(sec int64) (zone string, offset int) {
	onceSetupZone.Do(setupZone)
	if initError != nil {
		return "", 0
	}
	if tz.disabled {
		return "", tz.offsetIfDisabled
	}
	t := SecondsToUTC(sec)
	z := &tz.std
	if tz.std.year == 0 {
		// "day in month" format used
		z = tz.pickZone(t)
	} else {
		// "absolute" format used
		if tz.std.year == t.Year {
			// we have rule for the year in question
			z = tz.pickZone(t)
		} else {
			// we do not have any information for that year,
			// will assume standard offset all year around
		}
	}
	return z.name, z.offset
}

// lookupByName returns the time offset for the
// time zone with the given abbreviation. It only considers
// time zones that apply to the current system.
func lookupByName(name string) (off int, found bool) {
	onceSetupZone.Do(setupZone)
	if initError != nil {
		return 0, false
	}
	if tz.disabled {
		return tz.offsetIfDisabled, false
	}
	switch name {
	case tz.std.name:
		return tz.std.offset, true
	case tz.dst.name:
		return tz.dst.offset, true
	}
	return 0, false
}
<commit_msg>time: fix Windows build after ceeedb519c4a<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 (
	"syscall"
	"sync"
	"os"
)

// BUG(brainman): The Windows implementation assumes that
// this year's rules for daylight savings time apply to all previous
// and future years as well.

// TODO(brainman): use GetDynamicTimeZoneInformation, whenever possible (Vista and up),
// to improve on situation described in the bug above.

type zone struct {
	name                  string
	offset                int
	year                  int64
	month, day, dayofweek int
	hour, minute, second  int
	abssec                int64
	prev                  *zone
}

// BUG(rsc): On Windows, time zone abbreviations are unavailable.
// This package constructs them using the capital letters from a longer
// time zone description.

// Populate zone struct with Windows supplied information. Returns true, if data is valid.
func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) {
	// name is 'Pacific Standard Time' but we want 'PST'.
	// Extract just capital letters.  It's not perfect but the
	// information we need is not available from the kernel.
	// Because time zone abbreviations are not unique,
	// Windows refuses to expose them.
	//
	// http://social.msdn.microsoft.com/Forums/eu/vclanguage/thread/a87e1d25-fb71-4fe0-ae9c-a9578c9753eb
	// http://stackoverflow.com/questions/4195948/windows-time-zone-abbreviations-in-asp-net
	short := make([]uint16, len(name))
	w := 0
	for _, c := range name {
		if 'A' <= c && c <= 'Z' {
			short[w] = c
			w++
		}
	}
	z.name = syscall.UTF16ToString(short[:w])

	z.offset = int(bias)
	z.year = int64(d.Year)
	z.month = int(d.Month)
	z.day = int(d.Day)
	z.dayofweek = int(d.DayOfWeek)
	z.hour = int(d.Hour)
	z.minute = int(d.Minute)
	z.second = int(d.Second)
	dateisgood = d.Month != 0
	if dateisgood {
		z.offset += int(biasdelta)
	}
	z.offset = -z.offset * 60
	return
}

// Pre-calculate cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
func (z *zone) preCalculateAbsSec() {
	if z.year != 0 {
		z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 0, ""}).Seconds()
		// Time given is in "local" time. Adjust it for "utc".
		z.abssec -= int64(z.prev.offset)
	}
}

// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particular year.
func (z *zone) cutoffSeconds(year int64) int64 {
	// Windows specifies daylight savings information in "day in month" format:
	// z.month is month number (1-12)
	// z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6)
	// z.day is week within the month (1 to 5, where 5 is last week of the month)
	// z.hour, z.minute and z.second are absolute time
	t := &Time{year, int(z.month), 1, int(z.hour), int(z.minute), int(z.second), 0, 0, ""}
	t = SecondsToUTC(t.Seconds())
	i := int(z.dayofweek) - t.Weekday
	if i < 0 {
		i += 7
	}
	t.Day += i
	if week := int(z.day) - 1; week < 4 {
		t.Day += week * 7
	} else {
		// "Last" instance of the day.
		t.Day += 4 * 7
		if t.Day > months(year)[t.Month] {
			t.Day -= 7
		}
	}
	// Result is in "local" time. Adjust it for "utc".
	return t.Seconds() - int64(z.prev.offset)
}

// Is t before the cutoff for switching to z?
func (z *zone) isBeforeCutoff(t *Time) bool {
	var coff int64
	if z.year == 0 {
		// "day in month" format used
		coff = z.cutoffSeconds(t.Year)
	} else {
		// "absolute" format used
		coff = z.abssec
	}
	return t.Seconds() < coff
}

type zoneinfo struct {
	disabled         bool // daylight saving time is not used locally
	offsetIfDisabled int
	januaryIsStd     bool // is january 1 standard time?
	std, dst         zone
}

// Pick zone (std or dst) t time belongs to.
func (zi *zoneinfo) pickZone(t *Time) *zone {
	z := &zi.std
	if tz.januaryIsStd {
		if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) {
			// after switch to daylight time and before the switch back to standard
			z = &zi.dst
		}
	} else {
		if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) {
			// before switch to standard time or after the switch back to daylight
			z = &zi.dst
		}
	}
	return z
}

var tz zoneinfo
var initError os.Error
var onceSetupZone sync.Once

func setupZone() {
	var i syscall.Timezoneinformation
	if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
		initError = os.NewSyscallError("GetTimeZoneInformation", e)
		return
	}
	setupZoneFromTZI(&i)
}

func setupZoneFromTZI(i *syscall.Timezoneinformation) {
	if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) {
		tz.disabled = true
		tz.offsetIfDisabled = tz.std.offset
		return
	}
	tz.std.prev = &tz.dst
	tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:])
	tz.dst.prev = &tz.std
	tz.std.preCalculateAbsSec()
	tz.dst.preCalculateAbsSec()
	// Is january 1 standard time this year?
	t := UTC()
	tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year)
}

var usPacific = syscall.Timezoneinformation{
	Bias: 8 * 60,
	StandardName: [32]uint16{
		'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e',
	},
	StandardDate: syscall.Systemtime{Month: 11, Day: 1, Hour: 2},
	DaylightName: [32]uint16{
		'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e',
	},
	DaylightDate: syscall.Systemtime{Month: 3, Day: 2, Hour: 2},
	DaylightBias: -60,
}

func setupTestingZone() {
	setupZoneFromTZI(&usPacific)
}

// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
func lookupTimezone(sec int64) (zone string, offset int) {
	onceSetupZone.Do(setupZone)
	if initError != nil {
		return "", 0
	}
	if tz.disabled {
		return "", tz.offsetIfDisabled
	}
	t := SecondsToUTC(sec)
	z := &tz.std
	if tz.std.year == 0 {
		// "day in month" format used
		z = tz.pickZone(t)
	} else {
		// "absolute" format used
		if tz.std.year == t.Year {
			// we have rule for the year in question
			z = tz.pickZone(t)
		} else {
			// we do not have any information for that year,
			// will assume standard offset all year around
		}
	}
	return z.name, z.offset
}

// lookupByName returns the time offset for the
// time zone with the given abbreviation. It only considers
// time zones that apply to the current system.
func lookupByName(name string) (off int, found bool) {
	onceSetupZone.Do(setupZone)
	if initError != nil {
		return 0, false
	}
	if tz.disabled {
		return tz.offsetIfDisabled, false
	}
	switch name {
	case tz.std.name:
		return tz.std.offset, true
	case tz.dst.name:
		return tz.dst.offset, true
	}
	return 0, false
}
<|endoftext|>


<commit_before>// Copyright 2015 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package query

import (
	"fmt"

	"github.com/square/metrics/api"
	"github.com/square/metrics/query/aggregate"
)

var functionRegistry = map[string]MetricFunction{}

func GetFunction(name string) (MetricFunction, bool) {
	fun, ok := functionRegistry[name]
	return fun, ok
}

func RegisterFunction(fun MetricFunction) error {
	_, ok := functionRegistry[fun.Name]
	if ok {
		return fmt.Errorf("function %s has already been registered", fun.Name)
	}
	functionRegistry[fun.Name] = fun
	return nil
}

func MustRegister(fun MetricFunction) {
	err := RegisterFunction(fun)
	if err != nil {
		panic(fmt.Sprintf("function %s in failed to register", fun.Name))
	}
}

type MetricFunction struct {
	Name        string
	MinArgument int
	MaxArgument int
	Groups      bool // Whether the function allows a 'group by' clause.
	Compute     func(EvaluationContext, []Expression, []string) (value, error)
}

func (f MetricFunction) Evaluate(
	context EvaluationContext,
	arguments []Expression,
	groupBy []string,
) (value, error) {
	// preprocessing
	length := len(arguments)
	if length < f.MinArgument || (f.MaxArgument != -1 && f.MaxArgument < length) {
		return nil, ArgumentLengthError{f.Name, f.MinArgument, f.MaxArgument, length}
	}
	if len(groupBy) > 0 && !f.Groups {
		return nil, fmt.Errorf("function %s doesn't allow a group-by clause", f.Name)
	}
	return f.Compute(context, arguments, groupBy)
}

func MakeOperatorMetricFunction(op string, operator func(float64, float64) float64) MetricFunction {
	return MetricFunction{
		Name:        op,
		MinArgument: 2,
		MaxArgument: 2,
		Compute: func(context EvaluationContext, args []Expression, groups []string) (value, error) {
			leftValue, err := args[0].Evaluate(context)
			if err != nil {
				return nil, err
			}
			rightValue, err := args[1].Evaluate(context)
			if err != nil {
				return nil, err
			}
			leftList, err := leftValue.toSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			rightList, err := rightValue.toSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}

			joined := join([]api.SeriesList{leftList, rightList})

			result := make([]api.Timeseries, len(joined.Rows))

			for i, row := range joined.Rows {
				left := row.Row[0]
				right := row.Row[1]
				array := make([]float64, len(left.Values))
				for j := 0; j < len(left.Values); j++ {
					array[j] = operator(left.Values[j], right.Values[j])
				}
				result[i] = api.Timeseries{array, row.TagSet}
			}

			return seriesListValue(api.SeriesList{
				Series:    result,
				Timerange: context.Timerange,
			}), nil
		},
	}
}

// MakeAggregateMetricFunction takes a named aggregating function `[float64] => float64` and makes it into a MetricFunction.
func MakeAggregateMetricFunction(name string, aggregator func([]float64) float64) MetricFunction {
	return MetricFunction{
		Name:        name,
		MinArgument: 1,
		MaxArgument: 1,
		Compute: func(context EvaluationContext, args []Expression, groups []string) (value, error) {
			argument := args[0]
			value, err := argument.Evaluate(context)
			if err != nil {
				return nil, err
			}
			seriesList, err := value.toSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			result := aggregate.AggregateBy(seriesList, aggregator, groups)
			return seriesListValue(result), nil
		},
	}
}

// MakeTransformMetircFunction takes a named transforming function `[float64], [value] => [float64]` and makes it into a MetricFunction.
func MakeTransformMetricFunction(name string, parameterCount int, transformer func([]float64, []value, float64) ([]float64, error)) MetricFunction {
	return MetricFunction{
		Name:        name,
		MinArgument: parameterCount + 1,
		MaxArgument: parameterCount + 1,
		Groups:      true,
		Compute: func(context EvaluationContext, args []Expression, groups []string) (value, error) {
			// ApplyTransform(list api.SeriesList, transform transform, parameters []value) (api.SeriesList, error)
			listValue, err := args[0].Evaluate(context)
			if err != nil {
				return nil, err
			}
			list, err := listValue.toSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			parameters := make([]value, parameterCount)
			for i := range parameters {
				parameters[i], err = args[i+1].Evaluate(context)
				if err != nil {
					return nil, err
				}
			}
			result, err := ApplyTransform(list, transformer, parameters)
			if err != nil {
				return nil, err
			}
			return seriesListValue(result), nil
		},
	}
}

var TimeshiftFunction = MetricFunction{
	Name:        "timeshift",
	MinArgument: 2,
	MaxArgument: 2,
	Compute: func(context EvaluationContext, arguments []Expression, groups []string) (value, error) {
		value, err := arguments[1].Evaluate(context)
		if err != nil {
			return nil, err
		}
		millis, err := toDuration(value)
		if err != nil {
			return nil, err
		}
		newContext := context
		newContext.Timerange = newContext.Timerange.Shift(millis)

		result, err := arguments[0].Evaluate(newContext)
		if err != nil {
			return nil, err
		}

		if seriesValue, ok := result.(seriesListValue); ok {
			seriesValue.Timerange = context.Timerange
			return seriesValue, nil
		}
		return result, nil

	},
}
<commit_msg>remove objectionable whitespace<commit_after>// Copyright 2015 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package query

import (
	"fmt"

	"github.com/square/metrics/api"
	"github.com/square/metrics/query/aggregate"
)

var functionRegistry = map[string]MetricFunction{}

func GetFunction(name string) (MetricFunction, bool) {
	fun, ok := functionRegistry[name]
	return fun, ok
}

func RegisterFunction(fun MetricFunction) error {
	_, ok := functionRegistry[fun.Name]
	if ok {
		return fmt.Errorf("function %s has already been registered", fun.Name)
	}
	functionRegistry[fun.Name] = fun
	return nil
}

func MustRegister(fun MetricFunction) {
	err := RegisterFunction(fun)
	if err != nil {
		panic(fmt.Sprintf("function %s in failed to register", fun.Name))
	}
}

type MetricFunction struct {
	Name        string
	MinArgument int
	MaxArgument int
	Groups      bool // Whether the function allows a 'group by' clause.
	Compute     func(EvaluationContext, []Expression, []string) (value, error)
}

func (f MetricFunction) Evaluate(
	context EvaluationContext,
	arguments []Expression,
	groupBy []string,
) (value, error) {
	// preprocessing
	length := len(arguments)
	if length < f.MinArgument || (f.MaxArgument != -1 && f.MaxArgument < length) {
		return nil, ArgumentLengthError{f.Name, f.MinArgument, f.MaxArgument, length}
	}
	if len(groupBy) > 0 && !f.Groups {
		return nil, fmt.Errorf("function %s doesn't allow a group-by clause", f.Name)
	}
	return f.Compute(context, arguments, groupBy)
}

func MakeOperatorMetricFunction(op string, operator func(float64, float64) float64) MetricFunction {
	return MetricFunction{
		Name:        op,
		MinArgument: 2,
		MaxArgument: 2,
		Compute: func(context EvaluationContext, args []Expression, groups []string) (value, error) {
			leftValue, err := args[0].Evaluate(context)
			if err != nil {
				return nil, err
			}
			rightValue, err := args[1].Evaluate(context)
			if err != nil {
				return nil, err
			}
			leftList, err := leftValue.toSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			rightList, err := rightValue.toSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}

			joined := join([]api.SeriesList{leftList, rightList})

			result := make([]api.Timeseries, len(joined.Rows))

			for i, row := range joined.Rows {
				left := row.Row[0]
				right := row.Row[1]
				array := make([]float64, len(left.Values))
				for j := 0; j < len(left.Values); j++ {
					array[j] = operator(left.Values[j], right.Values[j])
				}
				result[i] = api.Timeseries{array, row.TagSet}
			}

			return seriesListValue(api.SeriesList{
				Series:    result,
				Timerange: context.Timerange,
			}), nil
		},
	}
}

// MakeAggregateMetricFunction takes a named aggregating function `[float64] => float64` and makes it into a MetricFunction.
func MakeAggregateMetricFunction(name string, aggregator func([]float64) float64) MetricFunction {
	return MetricFunction{
		Name:        name,
		MinArgument: 1,
		MaxArgument: 1,
		Compute: func(context EvaluationContext, args []Expression, groups []string) (value, error) {
			argument := args[0]
			value, err := argument.Evaluate(context)
			if err != nil {
				return nil, err
			}
			seriesList, err := value.toSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			result := aggregate.AggregateBy(seriesList, aggregator, groups)
			return seriesListValue(result), nil
		},
	}
}

// MakeTransformMetircFunction takes a named transforming function `[float64], [value] => [float64]` and makes it into a MetricFunction.
func MakeTransformMetricFunction(name string, parameterCount int, transformer func([]float64, []value, float64) ([]float64, error)) MetricFunction {
	return MetricFunction{
		Name:        name,
		MinArgument: parameterCount + 1,
		MaxArgument: parameterCount + 1,
		Groups:      true,
		Compute: func(context EvaluationContext, args []Expression, groups []string) (value, error) {
			// ApplyTransform(list api.SeriesList, transform transform, parameters []value) (api.SeriesList, error)
			listValue, err := args[0].Evaluate(context)
			if err != nil {
				return nil, err
			}
			list, err := listValue.toSeriesList(context.Timerange)
			if err != nil {
				return nil, err
			}
			parameters := make([]value, parameterCount)
			for i := range parameters {
				parameters[i], err = args[i+1].Evaluate(context)
				if err != nil {
					return nil, err
				}
			}
			result, err := ApplyTransform(list, transformer, parameters)
			if err != nil {
				return nil, err
			}
			return seriesListValue(result), nil
		},
	}
}

var TimeshiftFunction = MetricFunction{
	Name:        "timeshift",
	MinArgument: 2,
	MaxArgument: 2,
	Compute: func(context EvaluationContext, arguments []Expression, groups []string) (value, error) {
		value, err := arguments[1].Evaluate(context)
		if err != nil {
			return nil, err
		}
		millis, err := toDuration(value)
		if err != nil {
			return nil, err
		}
		newContext := context
		newContext.Timerange = newContext.Timerange.Shift(millis)

		result, err := arguments[0].Evaluate(newContext)
		if err != nil {
			return nil, err
		}

		if seriesValue, ok := result.(seriesListValue); ok {
			seriesValue.Timerange = context.Timerange
			return seriesValue, nil
		}
		return result, nil
	},
}
<|endoftext|>


<commit_before>package queue

import (
	"crypto/tls"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/mundipagg/boleto-api/config"
	"github.com/mundipagg/boleto-api/util"

	"github.com/streadway/amqp"
)

const HEARTBEAT_DEFAULT = 10

func openChannel(conn *amqp.Connection, op string) (*amqp.Channel, error) {
	var channel *amqp.Channel
	var err error

	if conn == nil {
		err = errors.New("Failed to open a channel. The connection is closed")
		failOnError(err, "Failed to open a channel. The connection is closed", op)
		return nil, err
	}

	if channel, err = conn.Channel(); err != nil {
		failOnError(err, "Failed to open a channel", op)
		return nil, err
	}

	if err = channel.Confirm(false); err != nil {
		failOnError(err, "Failed to set channel into Confirm Mode", op)
		return nil, err
	}

	if err = channel.Qos(1, 0, false); err != nil {
		failOnError(err, "Error setting qos", op)
		return nil, err
	}

	return channel, err
}

func closeChannel(channel *amqp.Channel, op string) {
	if channel != nil {
		err := channel.Close()
		failOnError(err, "Failed to close a channel", op)
	}
}

func exchangeDeclare(channel *amqp.Channel, exchange, kind string) bool {
	err := channel.ExchangeDeclare(exchange, kind, true, false, false, false, nil)
	hdr := fmt.Sprintf("[{Application}: {Operation}] - Error Declaring RabbitMQ Exchange %s", exchange)
	failOnError(err, hdr, "ExchangeDeclare")
	return err == nil
}

func queueDeclare(channel *amqp.Channel, q amqp.Queue, queueName string) bool {

	q, err := channel.QueueDeclare(queueName, true, false, false, false, nil)
	hdr := fmt.Sprintf("[{Application}: {Operation}] - Error Declaring RabbitMQ Queue %s", queueName)
	failOnError(err, hdr, "QueueDeclare")
	return err == nil
}

func queueBinding(channel *amqp.Channel, queue, exchange, key string) bool {
	err := channel.QueueBind(queue, key, exchange, false, nil)
	hdr := fmt.Sprintf("[{Application}: {Operation}] - Error Binding RabbitMQ Queue %s into Exchange %s", queue, exchange)
	failOnError(err, hdr, "QueueBinding")
	return err == nil
}

func writeMessage(channel *amqp.Channel, p PublisherInterface) error {
	notifyConfirm := make(chan amqp.Confirmation)
	channel.NotifyPublish(notifyConfirm)

	err := channel.Publish(
		p.GetExchangeName(),
		p.GetRoutingKey(), // queue
		false,             // mandatory
		false,             // immediate
		amqp.Publishing{
			DeliveryMode: amqp.Persistent,
			ContentType:  "text/plain, charset=UTF-8",
			Body:         p.GetMessageToPublish(),
		})

	if err == nil {
		select {
		case confirm := <-notifyConfirm:
			if !confirm.Ack {
				err = errors.New("Nack received from the server during message posting")
			}
		}
	}

	failOnError(err, "Failed to publish a message", "WriteMessage")
	return err
}

func openConnection() (*amqp.Connection, error) {

	var hb int
	var err error

	if hb, err = strconv.Atoi(config.Get().Heartbeat); err != nil {
		hb = HEARTBEAT_DEFAULT
	}

	conn, err := amqp.DialConfig(config.Get().ConnQueue, amqp.Config{
		Heartbeat: time.Duration(hb) * time.Second,
		TLSClientConfig: &tls.Config{
			MinVersion:         util.GetTLSVersion(config.Get().QueueMinTLS),
			MaxVersion:         util.GetTLSVersion(config.Get().QueueMaxTLS),
			InsecureSkipVerify: config.Get().QueueByPassCertificate,
		},
	})

	return conn, err
}

func closeConnection(conn *amqp.Connection, op string) {
	if conn != nil {
		err := conn.Close()
		failOnError(err, "Failed to close connection to RabbitMQ", op)
	}
}
<commit_msg>:rotating_light: Remove CodeSmells<commit_after>package queue

import (
	"crypto/tls"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/mundipagg/boleto-api/config"
	"github.com/mundipagg/boleto-api/util"

	"github.com/streadway/amqp"
)

const HEARTBEAT_DEFAULT = 10

func openChannel(conn *amqp.Connection, op string) (*amqp.Channel, error) {
	var channel *amqp.Channel
	var err error

	if conn == nil {
		err = errors.New("failed to open a channel. The connection is closed")
		failOnError(err, "Failed to open a channel. The connection is closed", op)
		return nil, err
	}

	if channel, err = conn.Channel(); err != nil {
		failOnError(err, "Failed to open a channel", op)
		return nil, err
	}

	if err = channel.Confirm(false); err != nil {
		failOnError(err, "Failed to set channel into Confirm Mode", op)
		return nil, err
	}

	if err = channel.Qos(1, 0, false); err != nil {
		failOnError(err, "Error setting qos", op)
		return nil, err
	}

	return channel, err
}

func closeChannel(channel *amqp.Channel, op string) {
	if channel != nil {
		err := channel.Close()
		failOnError(err, "Failed to close a channel", op)
	}
}

func exchangeDeclare(channel *amqp.Channel, exchange, kind string) bool {
	err := channel.ExchangeDeclare(exchange, kind, true, false, false, false, nil)
	hdr := fmt.Sprintf("[{Application}: {Operation}] - Error Declaring RabbitMQ Exchange %s", exchange)
	failOnError(err, hdr, "ExchangeDeclare")
	return err == nil
}

func queueDeclare(channel *amqp.Channel, q amqp.Queue, queueName string) bool {

	q, err := channel.QueueDeclare(queueName, true, false, false, false, nil)
	hdr := fmt.Sprintf("[{Application}: {Operation}] - Error Declaring RabbitMQ Queue %s", queueName)
	failOnError(err, hdr, "QueueDeclare")
	return err == nil
}

func queueBinding(channel *amqp.Channel, queue, exchange, key string) bool {
	err := channel.QueueBind(queue, key, exchange, false, nil)
	hdr := fmt.Sprintf("[{Application}: {Operation}] - Error Binding RabbitMQ Queue %s into Exchange %s", queue, exchange)
	failOnError(err, hdr, "QueueBinding")
	return err == nil
}

func writeMessage(channel *amqp.Channel, p PublisherInterface) error {
	notifyConfirm := make(chan amqp.Confirmation)
	channel.NotifyPublish(notifyConfirm)

	err := channel.Publish(
		p.GetExchangeName(),
		p.GetRoutingKey(), // queue
		false,             // mandatory
		false,             // immediate
		amqp.Publishing{
			DeliveryMode: amqp.Persistent,
			ContentType:  "text/plain, charset=UTF-8",
			Body:         p.GetMessageToPublish(),
		})

	if err == nil {
		if confirm := <-notifyConfirm; !confirm.Ack {
			err = errors.New("nack received from the server during message posting")
		}
	}

	failOnError(err, "Failed to publish a message", "WriteMessage")
	return err
}

func openConnection() (*amqp.Connection, error) {

	var hb int
	var err error

	if hb, err = strconv.Atoi(config.Get().Heartbeat); err != nil {
		hb = HEARTBEAT_DEFAULT
	}

	conn, err := amqp.DialConfig(config.Get().ConnQueue, amqp.Config{
		Heartbeat: time.Duration(hb) * time.Second,
		TLSClientConfig: &tls.Config{
			MinVersion:         util.GetTLSVersion(config.Get().QueueMinTLS),
			MaxVersion:         util.GetTLSVersion(config.Get().QueueMaxTLS),
			InsecureSkipVerify: config.Get().QueueByPassCertificate,
		},
	})

	return conn, err
}

func closeConnection(conn *amqp.Connection, op string) {
	if conn != nil {
		err := conn.Close()
		failOnError(err, "Failed to close connection to RabbitMQ", op)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 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 runtime_test

import (
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"testing"
)

var lldbPath string

func checkLldbPython(t *testing.T) {
	cmd := exec.Command("lldb", "-P")
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Skipf("skipping due to issue running lldb: %v\n%s", err, out)
	}
	lldbPath = strings.TrimSpace(string(out))

	cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath)
	out, err = cmd.CombinedOutput()

	if err != nil {
		t.Skipf("skipping due to issue running python: %v\n%s", err, out)
	}
	if string(out) != "go lldb python support\n" {
		t.Skipf("skipping due to lack of python lldb support: %s", out)
	}

	if runtime.GOOS == "darwin" {
		// Try to see if we have debugging permissions.
		cmd = exec.Command("/usr/sbin/DevToolsSecurity", "-status")
		out, err = cmd.CombinedOutput()
		if err != nil {
			t.Skipf("DevToolsSecurity failed: %v", err)
		} else if !strings.Contains(string(out), "enabled") {
			t.Skip(string(out))
		}
		cmd = exec.Command("/usr/bin/groups")
		out, err = cmd.CombinedOutput()
		if err != nil {
			t.Skipf("groups failed: %v", err)
		} else if !strings.Contains(string(out), "_developer") {
			t.Skip("Not in _developer group")
		}
	}
}

const lldbHelloSource = `
package main
import "fmt"
func main() {
	mapvar := make(map[string]string,5)
	mapvar["abc"] = "def"
	mapvar["ghi"] = "jkl"
	intvar := 42
	ptrvar := &intvar
	fmt.Println("hi") // line 10
	_ = ptrvar
}
`

const lldbScriptSource = `
import sys
sys.path.append(sys.argv[1])
import lldb
import os

TIMEOUT_SECS = 5

debugger = lldb.SBDebugger.Create()
debugger.SetAsync(True)
target = debugger.CreateTargetWithFileAndArch("a.exe", None)
if target:
  print "Created target"
  main_bp = target.BreakpointCreateByLocation("main.go", 10)
  if main_bp.GetNumLocations() != 0:
    print "Created breakpoint"
  else:
    # This happens if lldb can't read the program's DWARF. See https://golang.org/issue/25925.
    print "SKIP: no matching locations for breakpoint"
    exit(1)
  process = target.LaunchSimple(None, None, os.getcwd())
  if process:
    print "Process launched"
    listener = debugger.GetListener()
    process.broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
    while True:
      event = lldb.SBEvent()
      if listener.WaitForEvent(TIMEOUT_SECS, event):
        if lldb.SBProcess.GetRestartedFromEvent(event):
          continue
        state = process.GetState()
        if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]:
          continue
      else:
        print "SKIP: Timeout launching"
      break
    if state == lldb.eStateStopped:
      for t in process.threads:
        if t.GetStopReason() == lldb.eStopReasonBreakpoint:
          print "Hit breakpoint"
          frame = t.GetFrameAtIndex(0)
          if frame:
            if frame.line_entry:
              print "Stopped at %s:%d" % (frame.line_entry.file.basename, frame.line_entry.line)
            if frame.function:
              print "Stopped in %s" % (frame.function.name,)
            var = frame.FindVariable('intvar')
            if var:
              print "intvar = %s" % (var.GetValue(),)
            else:
              print "no intvar"
    else:
      print "Process state", state
    process.Destroy()
else:
  print "Failed to create target a.exe"

lldb.SBDebugger.Destroy(debugger)
sys.exit()
`

const expectedLldbOutput = `Created target
Created breakpoint
Process launched
Hit breakpoint
Stopped at main.go:10
Stopped in main.main
intvar = 42
`

func TestLldbPython(t *testing.T) {
	testenv.MustHaveGoBuild(t)
	if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
		t.Skip("gdb test can fail with GOROOT_FINAL pending")
	}

	checkLldbPython(t)

	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}

	// As of 2018-07-17, lldb doesn't support compressed DWARF, so
	// disable it for this test.
	cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=all=-N -l", "-ldflags=-compressdwarf=false", "-o", "a.exe")
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("building source %v\n%s", err, out)
	}

	src = filepath.Join(dir, "script.py")
	err = ioutil.WriteFile(src, []byte(lldbScriptSource), 0755)
	if err != nil {
		t.Fatalf("failed to create script: %v", err)
	}

	cmd = exec.Command("/usr/bin/python2.7", "script.py", lldbPath)
	cmd.Dir = dir
	got, _ := cmd.CombinedOutput()

	if string(got) != expectedLldbOutput {
		skipReason := regexp.MustCompile("SKIP: .*\n").Find(got)
		if skipReason != nil {
			t.Skip(string(skipReason))
		}
		t.Fatalf("Unexpected lldb output:\n%s", got)
	}
}
<commit_msg>Revert "runtime: fix lldb test after DWARF compression"<commit_after>// Copyright 2016 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 runtime_test

import (
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

var lldbPath string

func checkLldbPython(t *testing.T) {
	cmd := exec.Command("lldb", "-P")
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Skipf("skipping due to issue running lldb: %v\n%s", err, out)
	}
	lldbPath = strings.TrimSpace(string(out))

	cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath)
	out, err = cmd.CombinedOutput()

	if err != nil {
		t.Skipf("skipping due to issue running python: %v\n%s", err, out)
	}
	if string(out) != "go lldb python support\n" {
		t.Skipf("skipping due to lack of python lldb support: %s", out)
	}

	if runtime.GOOS == "darwin" {
		// Try to see if we have debugging permissions.
		cmd = exec.Command("/usr/sbin/DevToolsSecurity", "-status")
		out, err = cmd.CombinedOutput()
		if err != nil {
			t.Skipf("DevToolsSecurity failed: %v", err)
		} else if !strings.Contains(string(out), "enabled") {
			t.Skip(string(out))
		}
		cmd = exec.Command("/usr/bin/groups")
		out, err = cmd.CombinedOutput()
		if err != nil {
			t.Skipf("groups failed: %v", err)
		} else if !strings.Contains(string(out), "_developer") {
			t.Skip("Not in _developer group")
		}
	}
}

const lldbHelloSource = `
package main
import "fmt"
func main() {
	mapvar := make(map[string]string,5)
	mapvar["abc"] = "def"
	mapvar["ghi"] = "jkl"
	intvar := 42
	ptrvar := &intvar
	fmt.Println("hi") // line 10
	_ = ptrvar
}
`

const lldbScriptSource = `
import sys
sys.path.append(sys.argv[1])
import lldb
import os

TIMEOUT_SECS = 5

debugger = lldb.SBDebugger.Create()
debugger.SetAsync(True)
target = debugger.CreateTargetWithFileAndArch("a.exe", None)
if target:
  print "Created target"
  main_bp = target.BreakpointCreateByLocation("main.go", 10)
  if main_bp:
    print "Created breakpoint"
  process = target.LaunchSimple(None, None, os.getcwd())
  if process:
    print "Process launched"
    listener = debugger.GetListener()
    process.broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
    while True:
      event = lldb.SBEvent()
      if listener.WaitForEvent(TIMEOUT_SECS, event):
        if lldb.SBProcess.GetRestartedFromEvent(event):
          continue
        state = process.GetState()
        if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]:
          continue
      else:
        print "Timeout launching"
      break
    if state == lldb.eStateStopped:
      for t in process.threads:
        if t.GetStopReason() == lldb.eStopReasonBreakpoint:
          print "Hit breakpoint"
          frame = t.GetFrameAtIndex(0)
          if frame:
            if frame.line_entry:
              print "Stopped at %s:%d" % (frame.line_entry.file.basename, frame.line_entry.line)
            if frame.function:
              print "Stopped in %s" % (frame.function.name,)
            var = frame.FindVariable('intvar')
            if var:
              print "intvar = %s" % (var.GetValue(),)
            else:
              print "no intvar"
    else:
      print "Process state", state
    process.Destroy()
else:
  print "Failed to create target a.exe"

lldb.SBDebugger.Destroy(debugger)
sys.exit()
`

const expectedLldbOutput = `Created target
Created breakpoint
Process launched
Hit breakpoint
Stopped at main.go:10
Stopped in main.main
intvar = 42
`

func TestLldbPython(t *testing.T) {
	testenv.MustHaveGoBuild(t)
	if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
		t.Skip("gdb test can fail with GOROOT_FINAL pending")
	}

	checkLldbPython(t)

	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}

	// As of 2018-07-17, lldb doesn't support compressed DWARF, so
	// disable it for this test.
	cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=all=-N -l", "-ldflags=-compressdwarf=false", "-o", "a.exe")
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("building source %v\n%s", err, out)
	}

	src = filepath.Join(dir, "script.py")
	err = ioutil.WriteFile(src, []byte(lldbScriptSource), 0755)
	if err != nil {
		t.Fatalf("failed to create script: %v", err)
	}

	cmd = exec.Command("/usr/bin/python2.7", "script.py", lldbPath)
	cmd.Dir = dir
	got, _ := cmd.CombinedOutput()

	if string(got) != expectedLldbOutput {
		if strings.Contains(string(got), "Timeout launching") {
			t.Skip("Timeout launching")
		}
		t.Fatalf("Unexpected lldb output:\n%s", got)
	}
}
<|endoftext|>


<commit_before>package sentinel

import (
	"time"

	"github.com/mdevilliers/redishappy/configuration"
	"github.com/mdevilliers/redishappy/services/logger"
	"github.com/mdevilliers/redishappy/services/redis"
	"github.com/mdevilliers/redishappy/types"
	"github.com/mdevilliers/redishappy/util"
)

const (
	SentinelMarkedUp    = 1
	SentinelMarkedDown  = 2
	SentinelMarkedAlive = 3
)

const (
	SentinelReconnectionPeriod        = time.Second * 5
	SentinelTopologyExplorationPeriod = time.Second * 60
)

type Manager interface {
	Notify(event SentinelEvent)
}

type SentinelManager struct {
	eventsChannel          chan SentinelEvent
	topologyRequestChannel chan TopologyRequest
	switchmasterchannel    chan types.MasterSwitchedEvent
	redisConnection        redis.RedisConnection
	configurationManager   *configuration.ConfigurationManager
	throttle               *Throttle
}

var topologyState = SentinelTopology{Sentinels: map[string]*SentinelInfo{}}

func NewManager(switchmasterchannel chan types.MasterSwitchedEvent, cm *configuration.ConfigurationManager) *SentinelManager {

	events := make(chan SentinelEvent)
	requests := make(chan TopologyRequest)
	unthrottled := make(chan types.MasterSwitchedEvent)

	throttle := NewThrottle(unthrottled, switchmasterchannel)

	manager := &SentinelManager{eventsChannel: events,
		topologyRequestChannel: requests,
		switchmasterchannel:    unthrottled,
		redisConnection:        redis.RadixRedisConnection{},
		configurationManager:   cm,
		throttle:               throttle}

	go manager.loopEvents(events, requests)
	go manager.bootstrap()
	return manager
}

func (m *SentinelManager) Notify(event SentinelEvent) {
	m.eventsChannel <- event
}

func (m *SentinelManager) GetState(request TopologyRequest) {
	m.topologyRequestChannel <- request
}

func (m *SentinelManager) ClearState() {
	topologyState = SentinelTopology{Sentinels: map[string]*SentinelInfo{}}
}

func (m *SentinelManager) GetCurrentTopology() types.MasterDetailsCollection {
	stateChannel := make(chan types.MasterDetailsCollection)
	go m.getTopology(stateChannel)
	return <-stateChannel
}

func (m *SentinelManager) getTopology(stateChannel chan types.MasterDetailsCollection) {

	topology := types.NewMasterDetailsCollection()
	configuration := m.configurationManager.GetCurrentConfiguration()

	for _, sentinel := range configuration.Sentinels {
		client, err := NewSentinelClient(sentinel, m.redisConnection)

		if err != nil {
			logger.Info.Printf("Error starting sentinel (%s) client : %s", sentinel.GetLocation(), err.Error())
			continue
		}
		defer client.Close()

		for _, clusterDetails := range configuration.Clusters {

			details, err := client.DiscoverMasterForCluster(clusterDetails.Name)
			if err != nil {
				continue
			}

			details.ExternalPort = clusterDetails.ExternalPort
			// TODO : last one wins?
			topology.AddOrReplace(details)
		}
	}
	stateChannel <- topology
}

func (m *SentinelManager) bootstrap() {

	configuration := m.configurationManager.GetCurrentConfiguration()

	for _, sentinel := range configuration.Sentinels {
		m.Notify(&SentinelAdded{Sentinel: sentinel})
	}

	util.Schedule(func() { m.bootstrap() }, SentinelTopologyExplorationPeriod)
}

func (m *SentinelManager) exploreSentinelTopology(sentinel types.Sentinel) {

	client, err := NewSentinelClient(sentinel, m.redisConnection)

	if err != nil {
		logger.Info.Printf("Error starting sentinel (%s) client : %s", sentinel.GetLocation(), err.Error())
		m.Notify(&SentinelLost{Sentinel: connectedsentinel})
		return
	}
	defer client.Close()

	knownClusters := client.FindKnownClusters()

	m.Notify(&SentinelClustersMonitoredUpdate{Sentinel: sentinel, Clusters: knownClusters})

	for _, clustername := range knownClusters {

		sentinels := client.FindConnectedSentinels(clustername)

		for _, connectedsentinel := range sentinels {
			m.Notify(&SentinelAdded{Sentinel: connectedsentinel})
		}
	}
}

func (m *SentinelManager) startNewMonitor(sentinel types.Sentinel) (*Monitor, error) {

	monitor, err := NewMonitor(sentinel, m, m.redisConnection)

	if err != nil {
		logger.Error.Printf("Error starting monitor %s : %s", sentinel.GetLocation(), err.Error())
		m.Notify(&SentinelLost{Sentinel: sentinel})
		return nil, err
	}

	go monitor.StartMonitoringMasterEvents(m.switchmasterchannel)

	return monitor, nil
}

func (m *SentinelManager) loopEvents(events chan SentinelEvent, topology chan TopologyRequest) {
	for {
		select {
		case event := <-events:
			m.updateState(event)
		case read := <-topology:
			read.ReplyChannel <- topologyState
		}
	}
}

func (m *SentinelManager) updateState(event interface{}) {

	switch e := event.(type) {
	case *SentinelAdded:

		sentinel := e.GetSentinel()
		uid := topologyState.createKey(sentinel)

		//if we don't know about the sentinel start monitoring it
		if _, exists := topologyState.Sentinels[uid]; !exists {

			info := &SentinelInfo{SentinelLocation: uid,
				LastUpdated: time.Now().UTC(),
				State:       SentinelMarkedUp}

			topologyState.Sentinels[uid] = info

			go m.startNewMonitor(sentinel)
			go m.exploreSentinelTopology(sentinel)

			logger.Trace.Printf("Sentinel added : %s", util.String(topologyState))
		}

	case *SentinelLost:

		sentinel := e.GetSentinel()
		uid := topologyState.createKey(sentinel)
		currentInfo, ok := topologyState.Sentinels[uid]

		if ok {
			currentInfo.State = SentinelMarkedDown
			currentInfo.LastUpdated = time.Now().UTC()
		}

		util.Schedule(func() { m.startNewMonitor(sentinel) }, SentinelReconnectionPeriod)

		logger.Trace.Printf("Sentinel lost : %s (scheduling new client and monitor).", util.String(topologyState))

	case *SentinelPing:
		sentinel := e.GetSentinel()
		uid := topologyState.createKey(sentinel)
		currentInfo, ok := topologyState.Sentinels[uid]

		if ok {
			currentInfo.State = SentinelMarkedAlive
			currentInfo.LastUpdated = time.Now().UTC()
		}

	case *SentinelClustersMonitoredUpdate:
		sentinel := e.GetSentinel()
		uid := topologyState.createKey(sentinel)

		if info, exists := topologyState.Sentinels[uid]; exists {

			info.Clusters = e.Clusters
		}

	default:
		logger.Error.Println("Unknown sentinel event : ", util.String(e))
	}
}
<commit_msg>log as error when cannot connect to sentinel<commit_after>package sentinel

import (
	"time"

	"github.com/mdevilliers/redishappy/configuration"
	"github.com/mdevilliers/redishappy/services/logger"
	"github.com/mdevilliers/redishappy/services/redis"
	"github.com/mdevilliers/redishappy/types"
	"github.com/mdevilliers/redishappy/util"
)

const (
	SentinelMarkedUp    = 1
	SentinelMarkedDown  = 2
	SentinelMarkedAlive = 3
)

const (
	SentinelReconnectionPeriod        = time.Second * 5
	SentinelTopologyExplorationPeriod = time.Second * 60
)

type Manager interface {
	Notify(event SentinelEvent)
}

type SentinelManager struct {
	eventsChannel          chan SentinelEvent
	topologyRequestChannel chan TopologyRequest
	switchmasterchannel    chan types.MasterSwitchedEvent
	redisConnection        redis.RedisConnection
	configurationManager   *configuration.ConfigurationManager
	throttle               *Throttle
}

var topologyState = SentinelTopology{Sentinels: map[string]*SentinelInfo{}}

func NewManager(switchmasterchannel chan types.MasterSwitchedEvent, cm *configuration.ConfigurationManager) *SentinelManager {

	events := make(chan SentinelEvent)
	requests := make(chan TopologyRequest)
	unthrottled := make(chan types.MasterSwitchedEvent)

	throttle := NewThrottle(unthrottled, switchmasterchannel)

	manager := &SentinelManager{eventsChannel: events,
		topologyRequestChannel: requests,
		switchmasterchannel:    unthrottled,
		redisConnection:        redis.RadixRedisConnection{},
		configurationManager:   cm,
		throttle:               throttle}

	go manager.loopEvents(events, requests)
	go manager.bootstrap()
	return manager
}

func (m *SentinelManager) Notify(event SentinelEvent) {
	m.eventsChannel <- event
}

func (m *SentinelManager) GetState(request TopologyRequest) {
	m.topologyRequestChannel <- request
}

func (m *SentinelManager) ClearState() {
	topologyState = SentinelTopology{Sentinels: map[string]*SentinelInfo{}}
}

func (m *SentinelManager) GetCurrentTopology() types.MasterDetailsCollection {
	stateChannel := make(chan types.MasterDetailsCollection)
	go m.getTopology(stateChannel)
	return <-stateChannel
}

func (m *SentinelManager) getTopology(stateChannel chan types.MasterDetailsCollection) {

	topology := types.NewMasterDetailsCollection()
	configuration := m.configurationManager.GetCurrentConfiguration()

	for _, sentinel := range configuration.Sentinels {
		client, err := NewSentinelClient(sentinel, m.redisConnection)

		if err != nil {
			logger.Info.Printf("Error starting sentinel (%s) client : %s", sentinel.GetLocation(), err.Error())
			continue
		}
		defer client.Close()

		for _, clusterDetails := range configuration.Clusters {

			details, err := client.DiscoverMasterForCluster(clusterDetails.Name)
			if err != nil {
				continue
			}

			details.ExternalPort = clusterDetails.ExternalPort
			// TODO : last one wins?
			topology.AddOrReplace(details)
		}
	}
	stateChannel <- topology
}

func (m *SentinelManager) bootstrap() {

	configuration := m.configurationManager.GetCurrentConfiguration()

	for _, sentinel := range configuration.Sentinels {
		m.Notify(&SentinelAdded{Sentinel: sentinel})
	}

	util.Schedule(func() { m.bootstrap() }, SentinelTopologyExplorationPeriod)
}

func (m *SentinelManager) exploreSentinelTopology(sentinel types.Sentinel) {

	client, err := NewSentinelClient(sentinel, m.redisConnection)

	if err != nil {

		logger.Error.Printf("Error starting sentinel (%s) client : %s", sentinel.GetLocation(), err.Error())
		m.Notify(&SentinelLost{Sentinel: sentinel})

		return
	}
	defer client.Close()

	knownClusters := client.FindKnownClusters()

	m.Notify(&SentinelClustersMonitoredUpdate{Sentinel: sentinel, Clusters: knownClusters})

	for _, clustername := range knownClusters {

		sentinels := client.FindConnectedSentinels(clustername)

		for _, connectedsentinel := range sentinels {
			m.Notify(&SentinelAdded{Sentinel: connectedsentinel})
		}
	}
}

func (m *SentinelManager) startNewMonitor(sentinel types.Sentinel) (*Monitor, error) {

	monitor, err := NewMonitor(sentinel, m, m.redisConnection)

	if err != nil {
		logger.Error.Printf("Error starting monitor %s : %s", sentinel.GetLocation(), err.Error())
		m.Notify(&SentinelLost{Sentinel: sentinel})
		return nil, err
	}

	go monitor.StartMonitoringMasterEvents(m.switchmasterchannel)

	return monitor, nil
}

func (m *SentinelManager) loopEvents(events chan SentinelEvent, topology chan TopologyRequest) {
	for {
		select {
		case event := <-events:
			m.updateState(event)
		case read := <-topology:
			read.ReplyChannel <- topologyState
		}
	}
}

func (m *SentinelManager) updateState(event interface{}) {

	switch e := event.(type) {
	case *SentinelAdded:

		sentinel := e.GetSentinel()
		uid := topologyState.createKey(sentinel)

		//if we don't know about the sentinel start monitoring it
		if _, exists := topologyState.Sentinels[uid]; !exists {

			info := &SentinelInfo{SentinelLocation: uid,
				LastUpdated: time.Now().UTC(),
				State:       SentinelMarkedUp}

			topologyState.Sentinels[uid] = info

			go m.startNewMonitor(sentinel)
			go m.exploreSentinelTopology(sentinel)

			logger.Trace.Printf("Sentinel added : %s", util.String(topologyState))
		}

	case *SentinelLost:

		sentinel := e.GetSentinel()
		uid := topologyState.createKey(sentinel)
		currentInfo, ok := topologyState.Sentinels[uid]

		if ok {
			currentInfo.State = SentinelMarkedDown
			currentInfo.LastUpdated = time.Now().UTC()
		}

		util.Schedule(func() { m.startNewMonitor(sentinel) }, SentinelReconnectionPeriod)

		logger.Trace.Printf("Sentinel lost : %s (scheduling new client and monitor).", util.String(topologyState))

	case *SentinelPing:
		sentinel := e.GetSentinel()
		uid := topologyState.createKey(sentinel)
		currentInfo, ok := topologyState.Sentinels[uid]

		if ok {
			currentInfo.State = SentinelMarkedAlive
			currentInfo.LastUpdated = time.Now().UTC()
		}

	case *SentinelClustersMonitoredUpdate:
		sentinel := e.GetSentinel()
		uid := topologyState.createKey(sentinel)

		if info, exists := topologyState.Sentinels[uid]; exists {

			info.Clusters = e.Clusters
		}

	default:
		logger.Error.Println("Unknown sentinel event : ", util.String(e))
	}
}
<|endoftext|>


<commit_before>package regex

import (
	"fmt"
	"github.com/hydroo/gomochex/automaton/nfa"
	"github.com/hydroo/gomochex/basic/set"
	"strings"
	"unicode/utf8"
)

type Expression interface {
	String() string
	Nfa() nfa.Nfa
}

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

type concatExpression struct {
	l, r Expression
}

func (e concatExpression) String() string {
	return fmt.Sprint("(", e.l, ".", e.r, ")")
}

func (e concatExpression) Nfa() nfa.Nfa {
	L := e.l.Nfa()
	R := e.r.Nfa()
	A := nfa.NewNfa()

	A.SetAlphabet(set.Join(L.Alphabet(), R.Alphabet()))

	//add R as it is with a 1 prepended to all states
	//add L as it is with a 0 prepended to all states
	for k, T := range []nfa.Nfa{L, R} {
		for i := 0; i < T.States().Size(); i += 1 {
			s, _ := T.States().At(i)
			s_ := nfa.State(fmt.Sprint(k, s))

			A.States().Add(s_)

			if k == 1 && T.FinalStates().Probe(s) == true { //R
				A.FinalStates().Add(s_)
			} else if k == 0 && T.InitialStates().Probe(s) == true { //L
				A.InitialStates().Add(s_)
			}

			for j := 0; j < T.Alphabet().Size(); j += 1 {
				a, _ := T.Alphabet().At(j)
				S := T.Transition(s.(nfa.State), a.(nfa.Letter))

				S_ := set.NewSet()
				for l := 0; l < S.Size(); l += 1 {
					t, _ := S.At(l)
					S_.Add(nfa.State(fmt.Sprint(k, t)))
				}

				A.SetTransition(s_, a.(nfa.Letter), S_)
			}
		}
	}

	// add transititons from before final states in L to all initial states in R
	S_ := set.NewSet()
	for i := 0; i < R.InitialStates().Size(); i += 1 {
		s, _ := R.InitialStates().At(i)
		S_.Add(nfa.State(fmt.Sprint(1, s)))
	}

	for i := 0; i < L.States().Size(); i += 1 {
		s, _ := L.States().At(i)
		s_ := nfa.State(fmt.Sprint(0, s))

		for j := 0; j < L.Alphabet().Size(); j += 1 {
			a, _ := L.Alphabet().At(j)
			S := L.Transition(s.(nfa.State), a.(nfa.Letter))

			if set.Intersect(L.FinalStates(), S).Size() > 0 {
				A.SetTransition(s_, a.(nfa.Letter), set.Join(A.Transition(s_, a.(nfa.Letter)), S_))
			}
		}
	}

	return A
}

type letterExpression struct {
	l string
}

func (e letterExpression) String() string {
	return e.l
}

func (e letterExpression) Nfa() nfa.Nfa {
	A := nfa.NewNfa()

	l := nfa.Letter(e.l)
	q0 := nfa.State("0")
	qf := nfa.State("f")

	A.Alphabet().Add(l)
	A.States().Add(q0, qf)
	A.InitialStates().Add(q0)
	A.FinalStates().Add(qf)

	A.SetTransition(q0, l, set.NewSet(qf))

	return A
}

type orExpression struct {
	l, r Expression
}

func (e orExpression) String() string {
	return fmt.Sprint("(", e.l, "+", e.r, ")")
}

func (e orExpression) Nfa() nfa.Nfa {
	L := e.l.Nfa()
	R := e.r.Nfa()
	A := nfa.NewNfa()

	A.SetAlphabet(set.Join(L.Alphabet(), R.Alphabet()))

	for k, T := range []nfa.Nfa{L, R} {

		for i := 0; i < T.States().Size(); i += 1 {
			s, _ := T.States().At(i)
			ss := nfa.State(fmt.Sprint(k, s))
			A.States().Add(ss)

			if T.InitialStates().Probe(s) == true {
				A.InitialStates().Add(ss)
			}
			if T.FinalStates().Probe(s) == true {
				A.FinalStates().Add(ss)
			}

			for j := 0; j < T.Alphabet().Size(); j += 1 {
				a, _ := T.Alphabet().At(j)

				S := T.Transition(s.(nfa.State), a.(nfa.Letter))
				SS := set.NewSet()
				for l := 0; l < S.Size(); l += 1 {
					t, _ := S.At(l)
					SS.Add(nfa.State(fmt.Sprint(k, t)))
				}

				A.SetTransition(ss, a.(nfa.Letter), SS)
			}
		}

	}

	return A
}

type starExpression struct {
	f Expression
}

func (e starExpression) String() string {
	return fmt.Sprint("(", e.f, ")*")
}

func (e starExpression) Nfa() nfa.Nfa {

	A := e.f.Nfa()

	var q0 nfa.State
	for i := 0; ; i += 1 {
		q0 = nfa.State(fmt.Sprint(i))
		if A.States().Probe(q0) == false {
			break
		}
	}

	A.States().Add(q0)

	// add transitions from before final states to the new initial state
	for i := 0; i < A.States().Size(); i += 1 {
		for j := 0; j < A.Alphabet().Size(); j += 1 {

			q_, _ := A.States().At(i)
			q := q_.(nfa.State)

			a_, _ := A.Alphabet().At(j)
			a := a_.(nfa.Letter)

			Q := A.Transition(q, a)

			if set.Intersect(Q, A.FinalStates()).Size() != 0 {
				Q.Add(q0)
				A.SetTransition(q, a, Q)
			}
		}
	}

	// add transitions from the new initial state
	// to the destinations of the old initial states
	for i := 0; i < A.InitialStates().Size(); i += 1 {
		for j := 0; j < A.Alphabet().Size(); j += 1 {

			q_, _ := A.InitialStates().At(i)
			q := q_.(nfa.State)

			a_, _ := A.Alphabet().At(j)
			a := a_.(nfa.Letter)

			Q := A.Transition(q, a)
			Q0 := A.Transition(q0, a)

			A.SetTransition(q0, a, set.Join(Q, Q0))
		}
	}

	A.InitialStates().Clear()
	A.InitialStates().Add(q0)
	A.FinalStates().Clear()
	A.FinalStates().Add(q0)

	return A
}

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

func Concat(l, r Expression) Expression {
	return &concatExpression{l, r}
}

func Letter(l string) Expression {
	return &letterExpression{l}
}

func Or(l, r Expression) Expression {
	return &orExpression{l, r}
}

func Star(e Expression) Expression {
	return &starExpression{e}
}

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

func ExpressionFromString(s string) (Expression, bool) {
	return expressionFromStringRecursively(strings.Replace(s, " ", "", -1))
}

func expressionFromStringRecursively(s string) (Expression, bool) {
	firstRune, _ := utf8.DecodeRune([]byte(s))

	if firstRune == '(' {
		bracketCount := 0
		for i := 1; i < len(s); {
			r, runeSize := utf8.DecodeRune([]byte(s[i:]))
			if r == '(' {
				bracketCount += 1
			} else if r == ')' {
				bracketCount -= 1
			} else if bracketCount == 0 && (r == '.' || r == '+') {
				subL, okL := expressionFromStringRecursively(s[1:i])
				subR, okR := expressionFromStringRecursively(s[i+runeSize : len(s)-1])
				if r == '.' {
					return Concat(subL, subR), okL && okR
				} else { // '+'
					return Or(subL, subR), okL && okR
				}
			} else if bracketCount == -1 && r == '*' { // star
				sub, ok := expressionFromStringRecursively(s[1 : i-1])
				return Star(sub), ok
			} else if bracketCount == -1 && r != '*' {
				return nil, false
			}

			i += runeSize
		}

	} else { //letter
		for i := 0; i < len(s); {
			r, runeSize := utf8.DecodeRune([]byte(s[i:]))
			if r == '(' || r == ')' || r == '.' || r == '+' || r == '*' {
				return nil, false
			}
			i += runeSize
		}
		return Letter(s), true
	}

	return nil, false
}
<commit_msg>add IsEqual to regex types<commit_after>package regex

import (
	"fmt"
	"github.com/hydroo/gomochex/automaton/nfa"
	"github.com/hydroo/gomochex/basic/set"
	"strings"
	"unicode/utf8"
)

type Expression interface {
	String() string
	IsEqual(Expression) bool
	Nfa() nfa.Nfa
}

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

type concatExpression struct {
	l, r Expression
}

func (e concatExpression) String() string {
	return fmt.Sprint("(", e.l, ".", e.r, ")")
}

func (e concatExpression) IsEqual(f_ Expression) bool {
	if f, ok := f_.(concatExpression); ok == true {
		return e.l.IsEqual(f.l) && e.r.IsEqual(f.r)
	} // else {
	return false
	//}
}

func (e concatExpression) Nfa() nfa.Nfa {
	L := e.l.Nfa()
	R := e.r.Nfa()
	A := nfa.NewNfa()

	A.SetAlphabet(set.Join(L.Alphabet(), R.Alphabet()))

	//add R as it is with a 1 prepended to all states
	//add L as it is with a 0 prepended to all states
	for k, T := range []nfa.Nfa{L, R} {
		for i := 0; i < T.States().Size(); i += 1 {
			s, _ := T.States().At(i)
			s_ := nfa.State(fmt.Sprint(k, s))

			A.States().Add(s_)

			if k == 1 && T.FinalStates().Probe(s) == true { //R
				A.FinalStates().Add(s_)
			} else if k == 0 && T.InitialStates().Probe(s) == true { //L
				A.InitialStates().Add(s_)
			}

			for j := 0; j < T.Alphabet().Size(); j += 1 {
				a, _ := T.Alphabet().At(j)
				S := T.Transition(s.(nfa.State), a.(nfa.Letter))

				S_ := set.NewSet()
				for l := 0; l < S.Size(); l += 1 {
					t, _ := S.At(l)
					S_.Add(nfa.State(fmt.Sprint(k, t)))
				}

				A.SetTransition(s_, a.(nfa.Letter), S_)
			}
		}
	}

	// add transititons from before final states in L to all initial states in R
	S_ := set.NewSet()
	for i := 0; i < R.InitialStates().Size(); i += 1 {
		s, _ := R.InitialStates().At(i)
		S_.Add(nfa.State(fmt.Sprint(1, s)))
	}

	for i := 0; i < L.States().Size(); i += 1 {
		s, _ := L.States().At(i)
		s_ := nfa.State(fmt.Sprint(0, s))

		for j := 0; j < L.Alphabet().Size(); j += 1 {
			a, _ := L.Alphabet().At(j)
			S := L.Transition(s.(nfa.State), a.(nfa.Letter))

			if set.Intersect(L.FinalStates(), S).Size() > 0 {
				A.SetTransition(s_, a.(nfa.Letter), set.Join(A.Transition(s_, a.(nfa.Letter)), S_))
			}
		}
	}

	return A
}

type letterExpression struct {
	l string
}

func (e letterExpression) String() string {
	return e.l
}

func (e letterExpression) IsEqual(f_ Expression) bool {
	if f, ok := f_.(letterExpression); ok == true {
		return e == f
	} // else {
	return false
	//}
}

func (e letterExpression) Nfa() nfa.Nfa {
	A := nfa.NewNfa()

	l := nfa.Letter(e.l)
	q0 := nfa.State("0")
	qf := nfa.State("f")

	A.Alphabet().Add(l)
	A.States().Add(q0, qf)
	A.InitialStates().Add(q0)
	A.FinalStates().Add(qf)

	A.SetTransition(q0, l, set.NewSet(qf))

	return A
}

type orExpression struct {
	l, r Expression
}

func (e orExpression) String() string {
	return fmt.Sprint("(", e.l, "+", e.r, ")")
}

func (e orExpression) IsEqual(f_ Expression) bool {
	if f, ok := f_.(orExpression); ok == true {
		return (e.l.IsEqual(f.l) && e.r.IsEqual(f.r)) || (e.l.IsEqual(f.r) && e.r.IsEqual(f.l))
	} // else {
	return false
	//}
}

func (e orExpression) Nfa() nfa.Nfa {
	L := e.l.Nfa()
	R := e.r.Nfa()
	A := nfa.NewNfa()

	A.SetAlphabet(set.Join(L.Alphabet(), R.Alphabet()))

	for k, T := range []nfa.Nfa{L, R} {

		for i := 0; i < T.States().Size(); i += 1 {
			s, _ := T.States().At(i)
			ss := nfa.State(fmt.Sprint(k, s))
			A.States().Add(ss)

			if T.InitialStates().Probe(s) == true {
				A.InitialStates().Add(ss)
			}
			if T.FinalStates().Probe(s) == true {
				A.FinalStates().Add(ss)
			}

			for j := 0; j < T.Alphabet().Size(); j += 1 {
				a, _ := T.Alphabet().At(j)

				S := T.Transition(s.(nfa.State), a.(nfa.Letter))
				SS := set.NewSet()
				for l := 0; l < S.Size(); l += 1 {
					t, _ := S.At(l)
					SS.Add(nfa.State(fmt.Sprint(k, t)))
				}

				A.SetTransition(ss, a.(nfa.Letter), SS)
			}
		}

	}

	return A
}

type starExpression struct {
	f Expression
}

func (e starExpression) String() string {
	return fmt.Sprint("(", e.f, ")*")
}

func (e starExpression) IsEqual(f_ Expression) bool {
	if f, ok := f_.(starExpression); ok == true {
		return e.f.IsEqual(f.f)
	} // else {
	return false
	//}
}

func (e starExpression) Nfa() nfa.Nfa {

	A := e.f.Nfa()

	var q0 nfa.State
	for i := 0; ; i += 1 {
		q0 = nfa.State(fmt.Sprint(i))
		if A.States().Probe(q0) == false {
			break
		}
	}

	A.States().Add(q0)

	// add transitions from before final states to the new initial state
	for i := 0; i < A.States().Size(); i += 1 {
		for j := 0; j < A.Alphabet().Size(); j += 1 {

			q_, _ := A.States().At(i)
			q := q_.(nfa.State)

			a_, _ := A.Alphabet().At(j)
			a := a_.(nfa.Letter)

			Q := A.Transition(q, a)

			if set.Intersect(Q, A.FinalStates()).Size() != 0 {
				Q.Add(q0)
				A.SetTransition(q, a, Q)
			}
		}
	}

	// add transitions from the new initial state
	// to the destinations of the old initial states
	for i := 0; i < A.InitialStates().Size(); i += 1 {
		for j := 0; j < A.Alphabet().Size(); j += 1 {

			q_, _ := A.InitialStates().At(i)
			q := q_.(nfa.State)

			a_, _ := A.Alphabet().At(j)
			a := a_.(nfa.Letter)

			Q := A.Transition(q, a)
			Q0 := A.Transition(q0, a)

			A.SetTransition(q0, a, set.Join(Q, Q0))
		}
	}

	A.InitialStates().Clear()
	A.InitialStates().Add(q0)
	A.FinalStates().Clear()
	A.FinalStates().Add(q0)

	return A
}

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

func Concat(l, r Expression) Expression {
	return &concatExpression{l, r}
}

func Letter(l string) Expression {
	return &letterExpression{l}
}

func Or(l, r Expression) Expression {
	return &orExpression{l, r}
}

func Star(e Expression) Expression {
	return &starExpression{e}
}

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

func ExpressionFromString(s string) (Expression, bool) {
	return expressionFromStringRecursively(strings.Replace(s, " ", "", -1))
}

func expressionFromStringRecursively(s string) (Expression, bool) {
	firstRune, _ := utf8.DecodeRune([]byte(s))

	if firstRune == '(' {
		bracketCount := 0
		for i := 1; i < len(s); {
			r, runeSize := utf8.DecodeRune([]byte(s[i:]))
			if r == '(' {
				bracketCount += 1
			} else if r == ')' {
				bracketCount -= 1
			} else if bracketCount == 0 && (r == '.' || r == '+') {
				subL, okL := expressionFromStringRecursively(s[1:i])
				subR, okR := expressionFromStringRecursively(s[i+runeSize : len(s)-1])
				if r == '.' {
					return Concat(subL, subR), okL && okR
				} else { // '+'
					return Or(subL, subR), okL && okR
				}
			} else if bracketCount == -1 && r == '*' { // star
				sub, ok := expressionFromStringRecursively(s[1 : i-1])
				return Star(sub), ok
			} else if bracketCount == -1 && r != '*' {
				return nil, false
			}

			i += runeSize
		}

	} else { //letter
		for i := 0; i < len(s); {
			r, runeSize := utf8.DecodeRune([]byte(s[i:]))
			if r == '(' || r == ')' || r == '.' || r == '+' || r == '*' {
				return nil, false
			}
			i += runeSize
		}
		return Letter(s), true
	}

	return nil, false
}
<|endoftext|>


<commit_before>// Package provides the client the ability to connect to pulse and add
// metrics/stats to be collected.
package relay

import (
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"

	// when implementing relay, set `lumber.Level(lumber.LvlInt("TRACE"))` in client to view logs
	"github.com/jcelliott/lumber"
)

var (
	UnableToIdentify   = errors.New("unable to identify with pulse")
	ReservedName       = errors.New("cannot use - or : or , or _connected in your name")
	DuplicateCollector = errors.New("cannot add a duplicate collector to the set")
	beatInterval       = 30
)

type (
	// Relay is a pulse client
	Relay struct {
		conn       net.Conn
		dataChan   chan string
		errChan    chan error
		collectors map[string]taggedCollector
		connected  bool
		hostAddr   string
		myId       string
	}

	// stores the collector and its associated tags
	taggedCollector struct {
		collector Collector
		tags      []string
	}
)

func (relay *Relay) readData() {
	zero := time.Time{}
	for {
		// make a temporary bytes var to read from the connection
		tmp := make([]byte, 128)
		// make 0 length data bytes (since we'll be appending)
		data := make([]byte, 0)

		// loop through the connection stream, appending tmp to data
		for {
			// read to the tmp var
			n, err := relay.conn.Read(tmp)
			if err != nil {
				relay.errChan <- err
				return
			}

			// append read data to full data
			data = append(data, tmp[:n]...)

			// break if ends with '\n' (todo: need to ensure writing w/o "\n" works)
			if tmp[n-1] == '\n' { //|| tmp[n-1] == 'EOF' {
				break
			}
		}

		relay.conn.SetReadDeadline(zero)

		// return strings.TrimSuffix(string(data), "\n"), nil
		datas := strings.Split(strings.TrimSuffix(string(data), "\n"), "\n")
		for i := range datas {
			relay.dataChan <- datas[i]
		}
	}
}

// beat allows the detection and handling of stale tcp connections
func (relay *Relay) beat() {
	for {
		time.Sleep(time.Duration(beatInterval) * time.Second)
		// since we're always reading, lets set a timeout for the pong to come back in 1/2 beat time
		relay.conn.SetReadDeadline(time.Now().Add(time.Duration(beatInterval/2) * time.Second))
		lumber.Trace("[PULSE :: RELAY] PULSE pinging...")
		_, err := relay.conn.Write([]byte("ping\n"))
		if err != nil {
			lumber.Trace("[PULSE :: RELAY] PULSE ping failed - %s", err)
			relay.errChan <- err
			return
		}
		lumber.Trace("[PULSE :: RELAY] PULSE pinged!")
	}
}

// establishConnection establishes a connection and id's with the server
func (relay *Relay) establishConnection() error {
	conn, err := net.DialTimeout("tcp", relay.hostAddr, 10*time.Second)
	if err != nil {
		return err
	}

	// send id
	conn.Write([]byte(fmt.Sprintf("id %s\n", relay.myId)))

	// hand over connection to client (relay)
	relay.conn = conn

	relay.dataChan = make(chan string)
	relay.errChan = make(chan error)

	// start data reader
	go relay.readData()

	var line string

	select {
	case line = <-relay.dataChan:
	case err := <-relay.errChan:
		return err
	}

	if line != "ok" {
		return UnableToIdentify
	}

	// add relay's known collectors
	for name, value := range relay.collectors {
		relay.conn.Write([]byte(fmt.Sprintf("add %s:%s\n", name, strings.Join(value.tags, ","))))
	}

	return nil
}

// NewRelay creates a new client (relay)
func NewRelay(address, id string) (*Relay, error) {
	newRelay := &Relay{
		connected:  true,
		collectors: make(map[string]taggedCollector, 0),
		hostAddr:   address,
		myId:       id,
	}
	err := newRelay.establishConnection()
	if err != nil {
		return nil, err
	}

	go newRelay.runLoop()

	// start heartbeat
	go newRelay.beat()

	return newRelay, nil
}

// runLoop handles communication from the server
func (relay *Relay) runLoop() {
	for {
		select {
		case err := <-relay.errChan:
			lumber.Error("[PULSE :: RELAY] Disconnected from host %s!", relay.hostAddr)
			relay.conn.Close()
			// retry indefinitely
			for {
				if err = relay.establishConnection(); err == nil {
					lumber.Info("[PULSE :: RELAY] Reconnected to host %s!", relay.hostAddr)
					break
				}
				lumber.Debug("[PULSE :: RELAY] Reconnecting to host %s...  Fail!", relay.hostAddr)
				<-time.After(5 * time.Second)
			}
			// we won't have anything in 'line' so continue
			continue
		case line := <-relay.dataChan:
			line = strings.TrimSuffix(line, "\n")
			split := strings.SplitN(line, " ", 2)

			cmd := split[0]
			switch cmd {
			case "ok":
				lumber.Trace("[PULSE :: RELAY] OK: %s", split)
				// just an ack
			case "pong":
				lumber.Trace("[PULSE :: RELAY] PONG: %s", split)
			case "beat":
				lumber.Trace("[PULSE :: RELAY] BEAT: %s", split)
				if len(split) != 2 {
					continue
				}
				num, err := strconv.Atoi(split[1])
				if err == nil {
					beatInterval = num
				}
			case "get":
				if len(split) != 2 {
					continue
				}
				lumber.Trace("[PULSE :: RELAY] GET: %s", split)
				stats := strings.Split(split[1], ",")
				results := make([]string, 0)
				for _, stat := range stats {
					tagCollector, ok := relay.collectors[stat]
					if !ok {
						lumber.Trace("[PULSE :: RELAY] stat %s !ok", stat)
						continue
					}
					for name, value := range tagCollector.collector.Collect() {
						formatted := strconv.FormatFloat(value, 'f', 4, 64)
						if name == "" {
							name = stat
						}
						results = append(results, fmt.Sprintf("%s-%s:%s", stat, name, formatted))
					}
				}
				if len(results) > 0 {
					response := fmt.Sprintf("got %s\n", strings.Join(results, ","))
					_, err := relay.conn.Write([]byte(response))
					if err != nil {
						lumber.Trace("[PULSE :: RELAY] GET response write error - %s", err)
					}
				}
			default:
				lumber.Trace("[PULSE :: RELAY] BAD: %s", split)
				// causes network spam if we write anything to connection
			}
		}
	}
}

func (relay *Relay) Info() map[string]float64 {
	stats := make(map[string]float64, 2)
	stats["_connected"] = 0
	if relay.connected {
		stats["_connected"] = 1
	}
	for collection, stat := range relay.collectors {
		values := stat.collector.Collect()
		for name, value := range values {
			switch {
			case name == "":
				stats[collection] = value
			default:
				stats[collection+"-"+name] = value
			}
		}
	}
	return stats
}

// AddCollector adds a collector to relay
func (relay *Relay) AddCollector(name string, tags []string, collector Collector) error {
	if name == "_connected" || strings.ContainsAny(name, ":,") {
		lumber.Trace("[PULSE :: RELAY] Reserved name!")
		return ReservedName
	}
	if _, ok := relay.collectors[name]; ok {
		lumber.Trace("[PULSE :: RELAY] Duplicate collector!")
		return DuplicateCollector
	}
	if _, err := relay.conn.Write([]byte(fmt.Sprintf("add %s:%s\n", name, strings.Join(tags, ",")))); err != nil {
		lumber.Trace("[PULSE :: RELAY] Failed to add collector to server - %s", err)
		return err
	}

	// if successfully added collector, add it to relay's known collectors
	// todo: lock
	relay.collectors[name] = taggedCollector{collector: collector, tags: tags}
	lumber.Trace("[PULSE :: RELAY] Added '%s' as collector.", name)
	return nil
}

func (relay *Relay) RemoveCollector(name string) {
	_, found := relay.collectors[name]
	if found {
		// todo: lock
		delete(relay.collectors, name)
		lumber.Trace("[PULSE :: RELAY] Removed '%s' as collector.", name)
		if _, err := relay.conn.Write([]byte(fmt.Sprintf("remove %s\n", name))); err != nil {
			lumber.Trace("[PULSE :: RELAY] Failed to remove collector from server - %s", err)
		}
	}
}

func (relay *Relay) Close() error {
	for name := range relay.collectors {
		relay.RemoveCollector(name)
	}
	relay.conn.Write([]byte("close\n"))
	return relay.conn.Close()
}
<commit_msg>Revert identifier filtering and add note as to why<commit_after>// Package provides the client the ability to connect to pulse and add
// metrics/stats to be collected.
package relay

import (
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"

	// when implementing relay, set `lumber.Level(lumber.LvlInt("TRACE"))` in client to view logs
	"github.com/jcelliott/lumber"
)

var (
	UnableToIdentify   = errors.New("unable to identify with pulse")
	ReservedName       = errors.New("cannot use - or : or , or _connected in your name")
	DuplicateCollector = errors.New("cannot add a duplicate collector to the set")
	beatInterval       = 30
)

type (
	// Relay is a pulse client
	Relay struct {
		conn       net.Conn
		dataChan   chan string
		errChan    chan error
		collectors map[string]taggedCollector
		connected  bool
		hostAddr   string
		myId       string
	}

	// stores the collector and its associated tags
	taggedCollector struct {
		collector Collector
		tags      []string
	}
)

func (relay *Relay) readData() {
	zero := time.Time{}
	for {
		// make a temporary bytes var to read from the connection
		tmp := make([]byte, 128)
		// make 0 length data bytes (since we'll be appending)
		data := make([]byte, 0)

		// loop through the connection stream, appending tmp to data
		for {
			// read to the tmp var
			n, err := relay.conn.Read(tmp)
			if err != nil {
				relay.errChan <- err
				return
			}

			// append read data to full data
			data = append(data, tmp[:n]...)

			// break if ends with '\n' (todo: need to ensure writing w/o "\n" works)
			if tmp[n-1] == '\n' { //|| tmp[n-1] == 'EOF' {
				break
			}
		}

		relay.conn.SetReadDeadline(zero)

		// return strings.TrimSuffix(string(data), "\n"), nil
		datas := strings.Split(strings.TrimSuffix(string(data), "\n"), "\n")
		for i := range datas {
			relay.dataChan <- datas[i]
		}
	}
}

// beat allows the detection and handling of stale tcp connections
func (relay *Relay) beat() {
	for {
		time.Sleep(time.Duration(beatInterval) * time.Second)
		// since we're always reading, lets set a timeout for the pong to come back in 1/2 beat time
		relay.conn.SetReadDeadline(time.Now().Add(time.Duration(beatInterval/2) * time.Second))
		lumber.Trace("[PULSE :: RELAY] PULSE pinging...")
		_, err := relay.conn.Write([]byte("ping\n"))
		if err != nil {
			lumber.Trace("[PULSE :: RELAY] PULSE ping failed - %s", err)
			relay.errChan <- err
			return
		}
		lumber.Trace("[PULSE :: RELAY] PULSE pinged!")
	}
}

// establishConnection establishes a connection and id's with the server
func (relay *Relay) establishConnection() error {
	conn, err := net.DialTimeout("tcp", relay.hostAddr, 10*time.Second)
	if err != nil {
		return err
	}

	// send id
	conn.Write([]byte(fmt.Sprintf("id %s\n", relay.myId)))

	// hand over connection to client (relay)
	relay.conn = conn

	relay.dataChan = make(chan string)
	relay.errChan = make(chan error)

	// start data reader
	go relay.readData()

	var line string

	select {
	case line = <-relay.dataChan:
	case err := <-relay.errChan:
		return err
	}

	if line != "ok" {
		return UnableToIdentify
	}

	// add relay's known collectors
	for name, value := range relay.collectors {
		relay.conn.Write([]byte(fmt.Sprintf("add %s:%s\n", name, strings.Join(value.tags, ","))))
	}

	return nil
}

// NewRelay creates a new client (relay)
func NewRelay(address, id string) (*Relay, error) {
	newRelay := &Relay{
		connected:  true,
		collectors: make(map[string]taggedCollector, 0),
		hostAddr:   address,
		myId:       id,
	}
	err := newRelay.establishConnection()
	if err != nil {
		return nil, err
	}

	go newRelay.runLoop()

	// start heartbeat
	go newRelay.beat()

	return newRelay, nil
}

// runLoop handles communication from the server
func (relay *Relay) runLoop() {
	for {
		select {
		case err := <-relay.errChan:
			lumber.Error("[PULSE :: RELAY] Disconnected from host %s!", relay.hostAddr)
			relay.conn.Close()
			// retry indefinitely
			for {
				if err = relay.establishConnection(); err == nil {
					lumber.Info("[PULSE :: RELAY] Reconnected to host %s!", relay.hostAddr)
					break
				}
				lumber.Debug("[PULSE :: RELAY] Reconnecting to host %s...  Fail!", relay.hostAddr)
				<-time.After(5 * time.Second)
			}
			// we won't have anything in 'line' so continue
			continue
		case line := <-relay.dataChan:
			line = strings.TrimSuffix(line, "\n")
			split := strings.SplitN(line, " ", 2)

			cmd := split[0]
			switch cmd {
			case "ok":
				lumber.Trace("[PULSE :: RELAY] OK: %s", split)
				// just an ack
			case "pong":
				lumber.Trace("[PULSE :: RELAY] PONG: %s", split)
			case "beat":
				lumber.Trace("[PULSE :: RELAY] BEAT: %s", split)
				if len(split) != 2 {
					continue
				}
				num, err := strconv.Atoi(split[1])
				if err == nil {
					beatInterval = num
				}
			case "get":
				if len(split) != 2 {
					continue
				}
				lumber.Trace("[PULSE :: RELAY] GET: %s", split)
				stats := strings.Split(split[1], ",")
				results := make([]string, 0)
				for _, stat := range stats {
					tagCollector, ok := relay.collectors[stat]
					if !ok {
						lumber.Trace("[PULSE :: RELAY] stat %s !ok", stat)
						continue
					}
					for name, value := range tagCollector.collector.Collect() {
						formatted := strconv.FormatFloat(value, 'f', 4, 64)
						if name == "" {
							name = stat
						}
						results = append(results, fmt.Sprintf("%s-%s:%s", stat, name, formatted))
					}
				}
				if len(results) > 0 {
					response := fmt.Sprintf("got %s\n", strings.Join(results, ","))
					_, err := relay.conn.Write([]byte(response))
					if err != nil {
						lumber.Trace("[PULSE :: RELAY] GET response write error - %s", err)
					}
				}
			default:
				lumber.Trace("[PULSE :: RELAY] BAD: %s", split)
				// causes network spam if we write anything to connection
			}
		}
	}
}

func (relay *Relay) Info() map[string]float64 {
	stats := make(map[string]float64, 2)
	stats["_connected"] = 0
	if relay.connected {
		stats["_connected"] = 1
	}
	for collection, stat := range relay.collectors {
		values := stat.collector.Collect()
		for name, value := range values {
			switch {
			case name == "":
				stats[collection] = value
			default:
				stats[collection+"-"+name] = value
			}
		}
	}
	return stats
}

// AddCollector adds a collector to relay
func (relay *Relay) AddCollector(name string, tags []string, collector Collector) error {
	// These characters are reserved in pulse and may not be used as part of an identifier.
	if name == "_connected" || strings.ContainsAny(name, "-:,") {
		lumber.Trace("[PULSE :: RELAY] Reserved name!")
		return ReservedName
	}
	if _, ok := relay.collectors[name]; ok {
		lumber.Trace("[PULSE :: RELAY] Duplicate collector!")
		return DuplicateCollector
	}
	if _, err := relay.conn.Write([]byte(fmt.Sprintf("add %s:%s\n", name, strings.Join(tags, ",")))); err != nil {
		lumber.Trace("[PULSE :: RELAY] Failed to add collector to server - %s", err)
		return err
	}

	// if successfully added collector, add it to relay's known collectors
	// todo: lock
	relay.collectors[name] = taggedCollector{collector: collector, tags: tags}
	lumber.Trace("[PULSE :: RELAY] Added '%s' as collector.", name)
	return nil
}

func (relay *Relay) RemoveCollector(name string) {
	_, found := relay.collectors[name]
	if found {
		// todo: lock
		delete(relay.collectors, name)
		lumber.Trace("[PULSE :: RELAY] Removed '%s' as collector.", name)
		if _, err := relay.conn.Write([]byte(fmt.Sprintf("remove %s\n", name))); err != nil {
			lumber.Trace("[PULSE :: RELAY] Failed to remove collector from server - %s", err)
		}
	}
}

func (relay *Relay) Close() error {
	for name := range relay.collectors {
		relay.RemoveCollector(name)
	}
	relay.conn.Write([]byte("close\n"))
	return relay.conn.Close()
}
<|endoftext|>


<commit_before>package gitosis

import (
	"errors"
	"fmt"
	ini "github.com/kless/goconfig/config"
	"github.com/timeredbull/tsuru/config"
	"github.com/timeredbull/tsuru/log"
	"os"
	"os/exec"
	"path"
)

// Add a new group to gitosis.conf. Also commit and push changes.
func AddGroup(name string) error {
	confPath, err := ConfPath()
	if err != nil {
		log.Panic(err)
		return err
	}
	c, err := ini.ReadDefault(confPath)
	if err != nil {
		log.Panic(err)
		return err
	}

	sName := fmt.Sprintf("group %s", name)
	ok := c.AddSection(sName)
	if !ok {
		errStr := fmt.Sprintf(`Could not add section "group %s" in gitosis.conf, section already exists!`, name)
		log.Panic(errStr)
		return errors.New(errStr)
	}

	err = c.WriteFile(confPath, 0744, "gitosis configuration file")
	if err != nil {
		log.Panic(err)
		return err
	}

	commitMsg := fmt.Sprintf("Defining gitosis group for group %s", name)
	err = PushToGitosis(commitMsg)
	if err != nil {
		log.Panic(err)
		return err
	}

	return nil
}

// Removes a group section and all it's options.
func RemoveGroup(group string) error {
	confPath, err := ConfPath()
	if err != nil {
		log.Panic(err)
		return err
	}
	c, err := ini.ReadDefault(confPath)
	if err != nil {
		log.Panic(err)
		return err
	}

	c.RemoveSection()

	return nil
}

// Adds a member to the given group.
// member parameter should be the same as the key name in keypair/ dir.
func AddMember(group, member string) error {
	confPath, err := ConfPath()
	if err != nil {
		log.Panic(err)
		return err
	}
	c, err := ini.ReadDefault(confPath)
	if err != nil {
		log.Panic(err)
		return err
	}

	sName := fmt.Sprintf("group %s", group)
	c.AddOption(sName, "member", member)

	err = c.WriteFile(confPath, 0744, "gitosis configuration file")
	if err != nil {
		log.Panic(err)
		return err
	}

	commitMsg := fmt.Sprintf("Adding member %s for group %s", member, group)
	err = PushToGitosis(commitMsg)
	if err != nil {
		log.Panic(err)
		return err
	}

	return nil
}

// Add, commit and push all changes in gitosis repository to it's
// bare.
func PushToGitosis(cMsg string) error {
	repoPath, err := config.GetString("git:gitosis-repo")
	if err != nil {
		log.Panic(err)
		return err
	}

	pwd := os.Getenv("PWD")
	os.Chdir(repoPath)

	output, err := exec.Command("git", "add", ".").CombinedOutput()
	if err != nil {
		fmt.Println(string(output))
		log.Panic(output, err)
		return err
	}
	output, err = exec.Command("git", "commit", "-m", cMsg).CombinedOutput()
	if err != nil {
		fmt.Println(string(output))
		log.Panic(output, err)
		return err
	}

	output, err = exec.Command("git", "push", "origin", "master").CombinedOutput()
	if err != nil {
		fmt.Println(string(output))
		log.Panic(output, err)
		return err
	}

	os.Chdir(pwd)
	return nil
}

func ConfPath() (p string, err error) {
	p = ""
	repoPath, err := config.GetString("git:gitosis-repo")
	if err != nil {
		log.Panic(err)
		return
	}

	p = path.Join(repoPath, "gitosis.conf")
	return
}
<commit_msg>gitosis: fix option (members instead of member)<commit_after>package gitosis

import (
	"errors"
	"fmt"
	ini "github.com/kless/goconfig/config"
	"github.com/timeredbull/tsuru/config"
	"github.com/timeredbull/tsuru/log"
	"os"
	"os/exec"
	"path"
)

// Add a new group to gitosis.conf. Also commit and push changes.
func AddGroup(name string) error {
	confPath, err := ConfPath()
	if err != nil {
		log.Panic(err)
		return err
	}
	c, err := ini.ReadDefault(confPath)
	if err != nil {
		log.Panic(err)
		return err
	}

	sName := fmt.Sprintf("group %s", name)
	ok := c.AddSection(sName)
	if !ok {
		errStr := fmt.Sprintf(`Could not add section "group %s" in gitosis.conf, section already exists!`, name)
		log.Panic(errStr)
		return errors.New(errStr)
	}

	err = c.WriteFile(confPath, 0744, "gitosis configuration file")
	if err != nil {
		log.Panic(err)
		return err
	}

	commitMsg := fmt.Sprintf("Defining gitosis group for group %s", name)
	err = PushToGitosis(commitMsg)
	if err != nil {
		log.Panic(err)
		return err
	}

	return nil
}

// Removes a group section and all it's options.
func RemoveGroup(group string) error {
	confPath, err := ConfPath()
	if err != nil {
		log.Panic(err)
		return err
	}
	c, err := ini.ReadDefault(confPath)
	if err != nil {
		log.Panic(err)
		return err
	}

	c.RemoveSection()

	return nil
}

// Adds a member to the given group.
// member parameter should be the same as the key name in keypair/ dir.
func AddMember(group, member string) error {
	confPath, err := ConfPath()
	if err != nil {
		log.Panic(err)
		return err
	}
	c, err := ini.ReadDefault(confPath)
	if err != nil {
		log.Panic(err)
		return err
	}

	sName := fmt.Sprintf("group %s", group)
	c.AddOption(sName, "members", member)

	err = c.WriteFile(confPath, 0744, "gitosis configuration file")
	if err != nil {
		log.Panic(err)
		return err
	}

	commitMsg := fmt.Sprintf("Adding member %s for group %s", member, group)
	err = PushToGitosis(commitMsg)
	if err != nil {
		log.Panic(err)
		return err
	}

	return nil
}

// Add, commit and push all changes in gitosis repository to it's
// bare.
func PushToGitosis(cMsg string) error {
	repoPath, err := config.GetString("git:gitosis-repo")
	if err != nil {
		log.Panic(err)
		return err
	}

	pwd := os.Getenv("PWD")
	os.Chdir(repoPath)

	output, err := exec.Command("git", "add", ".").CombinedOutput()
	if err != nil {
		fmt.Println(string(output))
		log.Panic(output, err)
		return err
	}
	output, err = exec.Command("git", "commit", "-m", cMsg).CombinedOutput()
	if err != nil {
		fmt.Println(string(output))
		log.Panic(output, err)
		return err
	}

	output, err = exec.Command("git", "push", "origin", "master").CombinedOutput()
	if err != nil {
		fmt.Println(string(output))
		log.Panic(output, err)
		return err
	}

	os.Chdir(pwd)
	return nil
}

func ConfPath() (p string, err error) {
	p = ""
	repoPath, err := config.GetString("git:gitosis-repo")
	if err != nil {
		log.Panic(err)
		return
	}

	p = path.Join(repoPath, "gitosis.conf")
	return
}
<|endoftext|>


<commit_before>package render

import (
	"image"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/golang/freetype/truetype"
	"golang.org/x/image/colornames"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"

	"github.com/oakmound/oak/alg/intgeom"
	"github.com/oakmound/oak/dlog"
	"github.com/oakmound/oak/fileutil"
)

var (
	fontdir string

	defaultHinting              = font.HintingNone
	defaultSize                 = 12.0
	defaultDPI                  = 72.0
	defaultColor    image.Image = image.White
	defaultFontFile string

	// DefFontGenerator is a default font generator of no options
	DefFontGenerator = FontGenerator{}

	loadedFonts = make(map[string]*truetype.Font)
)

// A FontGenerator stores information that can be used to create a font
type FontGenerator struct {
	File    string
	Color   image.Image
	Size    float64
	Hinting string
	DPI     float64
}

// DefFont returns a font built of the parameters set by SetFontDefaults.
func DefFont() *Font {
	return DefFontGenerator.Generate()
}

// Generate creates a font from the FontGenerator. Any parameters not supplied
// will be filled in with defaults set through SetFontDefaults.
func (fg *FontGenerator) Generate() *Font {

	dir := fontdir
	// Replace zero values with defaults
	if fg.File == "" {
		if defaultFontFile != "" {
			fg.File = defaultFontFile
		} else {
			_, curFile, _, _ := runtime.Caller(1)
			dir = filepath.Join(filepath.Dir(curFile), "default_assets", "font")
			fg.File = "luxisr.ttf"
		}
	}
	if fg.Size == 0 {
		fg.Size = defaultSize
	}
	if fg.DPI == 0 {
		fg.DPI = defaultDPI
	}
	if fg.Color == nil {
		fg.Color = defaultColor
	}

	fnt := LoadFont(dir, fg.File)
	if fnt == nil {
		return nil
	}
	// This logic is copied from truetype for their face scaling
	scl := fixed.Int26_6(0.5 + (fg.Size * fg.DPI * 64 / 72))
	bds := fnt.Bounds(scl)
	intBds := intgeom.NewRect2(
		bds.Min.X.Round(),
		bds.Min.Y.Round(),
		bds.Max.X.Round(),
		bds.Max.Y.Round(),
	)

	return &Font{
		FontGenerator: *fg,
		Drawer: font.Drawer{
			// Color and hinting zero values are replaced
			// by their respective parse functions in the
			// zero case.
			Src: fg.Color,
			Face: truetype.NewFace(fnt, &truetype.Options{
				Size:    fg.Size,
				DPI:     fg.DPI,
				Hinting: parseFontHinting(fg.Hinting),
			}),
		},
		bounds: intBds,
	}

}

// Copy creates a copy of this FontGenerator
func (fg *FontGenerator) Copy() *FontGenerator {
	newFg := new(FontGenerator)
	*newFg = *fg
	return newFg
}

// A Font is obtained as the result of FontGenerator.Generate(). It's used to
// create text type renderables.
type Font struct {
	FontGenerator
	font.Drawer
	bounds intgeom.Rect2
}

// Refresh regenerates this font
func (f *Font) Refresh() {
	*f = *f.Generate()
}

// Copy returns a copy of this font
func (f *Font) Copy() *Font {
	return f.Generate()
}

// Reset sets the font to being a default font
func (f *Font) Reset() {
	// Generate will return all defaults with no args
	f.FontGenerator = FontGenerator{}
	*f = *f.Generate()
}

// SetFontDefaults updates the default font parameters with the passed in arguments
func SetFontDefaults(wd, assetPath, fontPath, hinting, color, file string, size, dpi float64) {
	fontdir = filepath.Join(
		wd,
		assetPath,
		fontPath)
	defaultHinting = parseFontHinting(hinting)
	defaultSize = size
	defaultDPI = dpi
	defaultColor = FontColor(color)
	defaultFontFile = file
}

func parseFontHinting(hintType string) (faceHinting font.Hinting) {
	hintType = strings.ToLower(hintType)
	switch hintType {
	case "none":
		faceHinting = font.HintingNone
	case "vertical":
		faceHinting = font.HintingVertical
	case "full":
		faceHinting = font.HintingFull
	default:
		dlog.Error("Unable to parse font hinting, ", hintType)
		fallthrough
	case "":
		faceHinting = font.HintingNone
	}
	return faceHinting
}

// FontColor accesses x/image/colornames and returns an image.Image for the input
// string. If the string is not defined in x/image/colornames, it will return defaultColor
// as defined by SetFontDefaults. The set of colors as defined by x/image/colornames matches
// the set of colors as defined by the SVG 1.1 spec.
func FontColor(s string) image.Image {
	s = strings.ToLower(s)
	if c, ok := colornames.Map[s]; ok {
		return image.NewUniform(c)
	}
	return defaultColor
}

// LoadFont loads in a font file and stores it with the given fontFile name.
// This is necessary before using that file in a generator, otherwise the default
// directory will be tried at generation time.
func LoadFont(dir string, fontFile string) *truetype.Font {
	if _, ok := loadedFonts[fontFile]; !ok {
		fontBytes, err := fileutil.ReadFile(filepath.Join(dir, fontFile))
		if err != nil {
			dlog.Error(err)
			return nil
		}
		font, err := truetype.Parse(fontBytes)
		if err != nil {
			dlog.Error(err)
			return nil
		}
		loadedFonts[fontFile] = font
	}
	return loadedFonts[fontFile]
}
<commit_msg>Correct default font generator to use runtime.Caller(0)<commit_after>package render

import (
	"image"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/golang/freetype/truetype"
	"golang.org/x/image/colornames"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"

	"github.com/oakmound/oak/alg/intgeom"
	"github.com/oakmound/oak/dlog"
	"github.com/oakmound/oak/fileutil"
)

var (
	fontdir string

	defaultHinting              = font.HintingNone
	defaultSize                 = 12.0
	defaultDPI                  = 72.0
	defaultColor    image.Image = image.White
	defaultFontFile string

	// DefFontGenerator is a default font generator of no options
	DefFontGenerator = FontGenerator{}

	loadedFonts = make(map[string]*truetype.Font)
)

// A FontGenerator stores information that can be used to create a font
type FontGenerator struct {
	File    string
	Color   image.Image
	Size    float64
	Hinting string
	DPI     float64
}

// DefFont returns a font built of the parameters set by SetFontDefaults.
func DefFont() *Font {
	return DefFontGenerator.Generate()
}

// Generate creates a font from the FontGenerator. Any parameters not supplied
// will be filled in with defaults set through SetFontDefaults.
func (fg *FontGenerator) Generate() *Font {

	dir := fontdir
	// Replace zero values with defaults
	if fg.File == "" {
		if defaultFontFile != "" {
			fg.File = defaultFontFile
		} else {
			_, curFile, _, _ := runtime.Caller(0)
			dir = filepath.Join(filepath.Dir(curFile), "default_assets", "font")
			fg.File = "luxisr.ttf"
		}
	}
	if fg.Size == 0 {
		fg.Size = defaultSize
	}
	if fg.DPI == 0 {
		fg.DPI = defaultDPI
	}
	if fg.Color == nil {
		fg.Color = defaultColor
	}

	fnt := LoadFont(dir, fg.File)
	if fnt == nil {
		return nil
	}
	// This logic is copied from truetype for their face scaling
	scl := fixed.Int26_6(0.5 + (fg.Size * fg.DPI * 64 / 72))
	bds := fnt.Bounds(scl)
	intBds := intgeom.NewRect2(
		bds.Min.X.Round(),
		bds.Min.Y.Round(),
		bds.Max.X.Round(),
		bds.Max.Y.Round(),
	)

	return &Font{
		FontGenerator: *fg,
		Drawer: font.Drawer{
			// Color and hinting zero values are replaced
			// by their respective parse functions in the
			// zero case.
			Src: fg.Color,
			Face: truetype.NewFace(fnt, &truetype.Options{
				Size:    fg.Size,
				DPI:     fg.DPI,
				Hinting: parseFontHinting(fg.Hinting),
			}),
		},
		bounds: intBds,
	}

}

// Copy creates a copy of this FontGenerator
func (fg *FontGenerator) Copy() *FontGenerator {
	newFg := new(FontGenerator)
	*newFg = *fg
	return newFg
}

// A Font is obtained as the result of FontGenerator.Generate(). It's used to
// create text type renderables.
type Font struct {
	FontGenerator
	font.Drawer
	bounds intgeom.Rect2
}

// Refresh regenerates this font
func (f *Font) Refresh() {
	*f = *f.Generate()
}

// Copy returns a copy of this font
func (f *Font) Copy() *Font {
	return f.Generate()
}

// Reset sets the font to being a default font
func (f *Font) Reset() {
	// Generate will return all defaults with no args
	f.FontGenerator = FontGenerator{}
	*f = *f.Generate()
}

// SetFontDefaults updates the default font parameters with the passed in arguments
func SetFontDefaults(wd, assetPath, fontPath, hinting, color, file string, size, dpi float64) {
	fontdir = filepath.Join(
		wd,
		assetPath,
		fontPath)
	defaultHinting = parseFontHinting(hinting)
	defaultSize = size
	defaultDPI = dpi
	defaultColor = FontColor(color)
	defaultFontFile = file
}

func parseFontHinting(hintType string) (faceHinting font.Hinting) {
	hintType = strings.ToLower(hintType)
	switch hintType {
	case "none":
		faceHinting = font.HintingNone
	case "vertical":
		faceHinting = font.HintingVertical
	case "full":
		faceHinting = font.HintingFull
	default:
		dlog.Error("Unable to parse font hinting, ", hintType)
		fallthrough
	case "":
		faceHinting = font.HintingNone
	}
	return faceHinting
}

// FontColor accesses x/image/colornames and returns an image.Image for the input
// string. If the string is not defined in x/image/colornames, it will return defaultColor
// as defined by SetFontDefaults. The set of colors as defined by x/image/colornames matches
// the set of colors as defined by the SVG 1.1 spec.
func FontColor(s string) image.Image {
	s = strings.ToLower(s)
	if c, ok := colornames.Map[s]; ok {
		return image.NewUniform(c)
	}
	return defaultColor
}

// LoadFont loads in a font file and stores it with the given fontFile name.
// This is necessary before using that file in a generator, otherwise the default
// directory will be tried at generation time.
func LoadFont(dir string, fontFile string) *truetype.Font {
	if _, ok := loadedFonts[fontFile]; !ok {
		fontBytes, err := fileutil.ReadFile(filepath.Join(dir, fontFile))
		if err != nil {
			dlog.Error(err)
			return nil
		}
		font, err := truetype.Parse(fontBytes)
		if err != nil {
			dlog.Error(err)
			return nil
		}
		loadedFonts[fontFile] = font
	}
	return loadedFonts[fontFile]
}
<|endoftext|>