<commit_before>package gofakeit

import (
	"errors"
	"math/rand"
	"strconv"
	"time"
)

// Date will generate a random time.Time struct
func Date() time.Time {
	return date(globalFaker.Rand)
}

// Date will generate a random time.Time struct
func (f *Faker) Date() time.Time {
	return date(f.Rand)
}

func date(r *rand.Rand) time.Time {
	return time.Date(year(r), time.Month(number(r,1, 12)), day(r), hour(r), minute(r), second(r), nanoSecond(r), time.UTC)
}

// DateRange will generate a random time.Time struct between a start and end date
func DateRange(start, end time.Time) time.Time {
	return dateRange(globalFaker.Rand, start, end)
}

// DateRange will generate a random time.Time struct between a start and end date
func (f *Faker) DateRange(start, end time.Time) time.Time {
	return dateRange(f.Rand, start, end)
}

func dateRange(r *rand.Rand, start time.Time, end time.Time) time.Time {
	return time.Unix(0, int64(number(r, int(start.UnixNano()), int(end.UnixNano())))).UTC()
}

// NanoSecond will generate a random nano second
func NanoSecond() int {
	return nanoSecond(globalFaker.Rand)
}

// NanoSecond will generate a random nano second
func (f *Faker) NanoSecond() int {
	return nanoSecond(f.Rand)
}

func nanoSecond(r *rand.Rand) int {
	return number(r,0, 999999999)
}

// Second will generate a random second
func Second() int {
	return second(globalFaker.Rand)
}

// Second will generate a random second
func (f *Faker) Second() int {
	return second(f.Rand)
}

func second(r *rand.Rand) int {
	return number(r,0, 59)
}

// Minute will generate a random minute
func Minute() int {
	return minute(globalFaker.Rand)
}

// Minute will generate a random minute
func (f *Faker) Minute() int {
	return minute(f.Rand)
}

func minute(r *rand.Rand) int {
	return number(r, 0, 59)
}

// Hour will generate a random hour - in military time
func Hour() int {
	return hour(globalFaker.Rand)
}

// Hour will generate a random hour - in military time
func (f *Faker) Hour() int {
	return hour(f.Rand)
}

func hour(r *rand.Rand) int {
	return number(r,0, 23)
}

// Day will generate a random day between 1 - 31
func Day() int {
	return day(globalFaker.Rand)
}

// Day will generate a random day between 1 - 31
func (f *Faker) Day() int {
	return day(f.Rand)
}

func day(r *rand.Rand) int {
	return number(r, 1, 31)
}

// WeekDay will generate a random weekday string (Monday-Sunday)
func WeekDay() string {
	return weekDay(globalFaker.Rand)
}

// WeekDay will generate a random weekday string (Monday-Sunday)
func (f *Faker) WeekDay() string {
	return weekDay(f.Rand)
}

func weekDay(r *rand.Rand) string {
	return time.Weekday(number(r,0, 6)).String()
}

// Month will generate a random month string
func Month() string {
	return month(globalFaker.Rand)
}

// Month will generate a random month string
func (f *Faker) Month() string {
	return month(f.Rand)
}

func month(r *rand.Rand) string {
	return time.Month(number(r,1, 12)).String()
}

// Year will generate a random year between 1900 - current year
func Year() int {
	return year(globalFaker.Rand)
}

// Year will generate a random year between 1900 - current year
func (f *Faker) Year() int {
	return year(f.Rand)
}

func year(r *rand.Rand) int {
	return number(r, 1900, time.Now().Year())
}

// TimeZone will select a random timezone string
func TimeZone() string {
	return timeZone(globalFaker.Rand)
}

// TimeZone will select a random timezone string
func (f *Faker) TimeZone() string {
	return timeZone(f.Rand)
}

func timeZone(r *rand.Rand) string {
	return getRandValue(r, []string{"timezone", "text"})
}

// TimeZoneFull will select a random full timezone string
func TimeZoneFull() string {
	return timeZoneFull(globalFaker.Rand)
}

// TimeZoneFull will select a random full timezone string
func (f *Faker) TimeZoneFull() string {
	return timeZoneFull(f.Rand)
}

func timeZoneFull(r *rand.Rand) string {
	return getRandValue(r, []string{"timezone", "full"})
}

// TimeZoneRegion will select a random region style timezone string, e.g. "America/Chicago"
func TimeZoneRegion() string {
	return timeZoneRegion(globalFaker.Rand)
}

// TimeZoneRegion will select a random region style timezone string, e.g. "America/Chicago"
func (f *Faker) TimeZoneRegion() string {
	return timeZoneRegion(f.Rand)
}

func timeZoneRegion(r *rand.Rand) string {
	return getRandValue(r, []string{"timezone", "region"})
}

// TimeZoneAbv will select a random timezone abbreviation string
func TimeZoneAbv() string {
	return timeZoneAbv(globalFaker.Rand)
}

// TimeZoneAbv will select a random timezone abbreviation string
func (f *Faker) TimeZoneAbv() string {
	return timeZoneAbv(f.Rand)
}

func timeZoneAbv(r *rand.Rand) string {
	return getRandValue(r, []string{"timezone", "abr"})
}

// TimeZoneOffset will select a random timezone offset
func TimeZoneOffset() float32 {
	return timeZoneOffset(globalFaker.Rand)
}

// TimeZoneOffset will select a random timezone offset
func (f *Faker) TimeZoneOffset() float32 {
	return timeZoneOffset(f.Rand)
}

func timeZoneOffset(r *rand.Rand) float32 {
	value, _ := strconv.ParseFloat(getRandValue(r, []string{"timezone", "offset"}), 32)
	return float32(value)
}

func addDateTimeLookup() {
	AddFuncLookup("date", Info{
		Display:     "Date",
		Category:    "time",
		Description: "Random date",
		Example:     "2006-01-02T15:04:05Z07:00",
		Output:      "string",
		Params: []Param{
			{
				Field:       "format",
				Display:     "Format",
				Type:        "string",
				Default:     "RFC3339",
				Options:     []string{"ANSIC", "UnixDate", "RubyDate", "RFC822", "RFC822Z", "RFC850", "RFC1123", "RFC1123Z", "RFC3339", "RFC3339Nano"},
				Description: "Date time string format output",
			},
		},
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			format, err := info.GetString(m, "format")
			if err != nil {
				return nil, err
			}

			switch format {
			case "ANSIC":
				return Date().Format(time.ANSIC), nil
			case "UnixDate":
				return Date().Format(time.UnixDate), nil
			case "RubyDate":
				return Date().Format(time.RubyDate), nil
			case "RFC822":
				return Date().Format(time.RFC822), nil
			case "RFC822Z":
				return Date().Format(time.RFC822Z), nil
			case "RFC850":
				return Date().Format(time.RFC850), nil
			case "RFC1123":
				return Date().Format(time.RFC1123), nil
			case "RFC1123Z":
				return Date().Format(time.RFC1123Z), nil
			case "RFC3339":
				return Date().Format(time.RFC3339), nil
			case "RFC3339Nano":
				return Date().Format(time.RFC3339Nano), nil
			}

			return "", errors.New("Invalid format")
		},
	})

	AddFuncLookup("nanosecond", Info{
		Display:     "Nanosecond",
		Category:    "time",
		Description: "Random nanosecond",
		Example:     "196446360",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return NanoSecond(), nil
		},
	})

	AddFuncLookup("second", Info{
		Display:     "Second",
		Category:    "time",
		Description: "Random second",
		Example:     "43",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Second(), nil
		},
	})

	AddFuncLookup("minute", Info{
		Display:     "Minute",
		Category:    "time",
		Description: "Random minute",
		Example:     "34",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Second(), nil
		},
	})

	AddFuncLookup("hour", Info{
		Display:     "Hour",
		Category:    "time",
		Description: "Random hour",
		Example:     "8",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Second(), nil
		},
	})

	AddFuncLookup("day", Info{
		Display:     "Day",
		Category:    "time",
		Description: "Random day",
		Example:     "12",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Day(), nil
		},
	})

	AddFuncLookup("weekday", Info{
		Display:     "Weekday",
		Category:    "time",
		Description: "Random week day",
		Example:     "Friday",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return WeekDay(), nil
		},
	})

	AddFuncLookup("year", Info{
		Display:     "Year",
		Category:    "time",
		Description: "Random year",
		Example:     "1900",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Year(), nil
		},
	})

	AddFuncLookup("timezone", Info{
		Display:     "Timezone",
		Category:    "time",
		Description: "Random timezone",
		Example:     "Kaliningrad Standard Time",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZone(), nil
		},
	})

	AddFuncLookup("timezoneabv", Info{
		Display:     "Timezone Abbreviation",
		Category:    "time",
		Description: "Random abbreviated timezone",
		Example:     "KST",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZoneAbv(), nil
		},
	})

	AddFuncLookup("timezonefull", Info{
		Display:     "Timezone Full",
		Category:    "time",
		Description: "Random full timezone",
		Example:     "(UTC+03:00) Kaliningrad, Minsk",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZoneFull(), nil
		},
	})

	AddFuncLookup("timezoneoffset", Info{
		Display:     "Timezone Offset",
		Category:    "time",
		Description: "Random timezone offset",
		Example:     "3",
		Output:      "float32",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZoneOffset(), nil
		},
	})

	AddFuncLookup("timezoneregion", Info{
		Display:     "Timezone Region",
		Category:    "time",
		Description: "Random region timezone",
		Example:     "America/Alaska",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZoneRegion(), nil
		},
	})

}
<commit_msg>time - tighten<commit_after>package gofakeit

import (
	"errors"
	"math/rand"
	"strconv"
	"time"
)

// Date will generate a random time.Time struct
func Date() time.Time { return date(globalFaker.Rand) }

// Date will generate a random time.Time struct
func (f *Faker) Date() time.Time { return date(f.Rand) }

func date(r *rand.Rand) time.Time {
	return time.Date(year(r), time.Month(number(r, 1, 12)), day(r), hour(r), minute(r), second(r), nanoSecond(r), time.UTC)
}

// DateRange will generate a random time.Time struct between a start and end date
func DateRange(start, end time.Time) time.Time { return dateRange(globalFaker.Rand, start, end) }

// DateRange will generate a random time.Time struct between a start and end date
func (f *Faker) DateRange(start, end time.Time) time.Time { return dateRange(f.Rand, start, end) }

func dateRange(r *rand.Rand, start time.Time, end time.Time) time.Time {
	return time.Unix(0, int64(number(r, int(start.UnixNano()), int(end.UnixNano())))).UTC()
}

// NanoSecond will generate a random nano second
func NanoSecond() int { return nanoSecond(globalFaker.Rand) }

// NanoSecond will generate a random nano second
func (f *Faker) NanoSecond() int { return nanoSecond(f.Rand) }

func nanoSecond(r *rand.Rand) int { return number(r, 0, 999999999) }

// Second will generate a random second
func Second() int { return second(globalFaker.Rand) }

// Second will generate a random second
func (f *Faker) Second() int { return second(f.Rand) }

func second(r *rand.Rand) int { return number(r, 0, 59) }

// Minute will generate a random minute
func Minute() int { return minute(globalFaker.Rand) }

// Minute will generate a random minute
func (f *Faker) Minute() int { return minute(f.Rand) }

func minute(r *rand.Rand) int { return number(r, 0, 59) }

// Hour will generate a random hour - in military time
func Hour() int { return hour(globalFaker.Rand) }

// Hour will generate a random hour - in military time
func (f *Faker) Hour() int { return hour(f.Rand) }

func hour(r *rand.Rand) int { return number(r, 0, 23) }

// Day will generate a random day between 1 - 31
func Day() int { return day(globalFaker.Rand) }

// Day will generate a random day between 1 - 31
func (f *Faker) Day() int { return day(f.Rand) }

func day(r *rand.Rand) int { return number(r, 1, 31) }

// WeekDay will generate a random weekday string (Monday-Sunday)
func WeekDay() string { return weekDay(globalFaker.Rand) }

// WeekDay will generate a random weekday string (Monday-Sunday)
func (f *Faker) WeekDay() string { return weekDay(f.Rand) }

func weekDay(r *rand.Rand) string { return time.Weekday(number(r, 0, 6)).String() }

// Month will generate a random month string
func Month() string { return month(globalFaker.Rand) }

// Month will generate a random month string
func (f *Faker) Month() string { return month(f.Rand) }

func month(r *rand.Rand) string { return time.Month(number(r, 1, 12)).String() }

// Year will generate a random year between 1900 - current year
func Year() int { return year(globalFaker.Rand) }

// Year will generate a random year between 1900 - current year
func (f *Faker) Year() int { return year(f.Rand) }

func year(r *rand.Rand) int { return number(r, 1900, time.Now().Year()) }

// TimeZone will select a random timezone string
func TimeZone() string { return timeZone(globalFaker.Rand) }

// TimeZone will select a random timezone string
func (f *Faker) TimeZone() string { return timeZone(f.Rand) }

func timeZone(r *rand.Rand) string { return getRandValue(r, []string{"timezone", "text"}) }

// TimeZoneFull will select a random full timezone string
func TimeZoneFull() string { return timeZoneFull(globalFaker.Rand) }

// TimeZoneFull will select a random full timezone string
func (f *Faker) TimeZoneFull() string { return timeZoneFull(f.Rand) }

func timeZoneFull(r *rand.Rand) string { return getRandValue(r, []string{"timezone", "full"}) }

// TimeZoneRegion will select a random region style timezone string, e.g. "America/Chicago"
func TimeZoneRegion() string { return timeZoneRegion(globalFaker.Rand) }

// TimeZoneRegion will select a random region style timezone string, e.g. "America/Chicago"
func (f *Faker) TimeZoneRegion() string { return timeZoneRegion(f.Rand) }

func timeZoneRegion(r *rand.Rand) string { return getRandValue(r, []string{"timezone", "region"}) }

// TimeZoneAbv will select a random timezone abbreviation string
func TimeZoneAbv() string { return timeZoneAbv(globalFaker.Rand) }

// TimeZoneAbv will select a random timezone abbreviation string
func (f *Faker) TimeZoneAbv() string { return timeZoneAbv(f.Rand) }

func timeZoneAbv(r *rand.Rand) string { return getRandValue(r, []string{"timezone", "abr"}) }

// TimeZoneOffset will select a random timezone offset
func TimeZoneOffset() float32 { return timeZoneOffset(globalFaker.Rand) }

// TimeZoneOffset will select a random timezone offset
func (f *Faker) TimeZoneOffset() float32 { return timeZoneOffset(f.Rand) }

func timeZoneOffset(r *rand.Rand) float32 {
	value, _ := strconv.ParseFloat(getRandValue(r, []string{"timezone", "offset"}), 32)
	return float32(value)
}

func addDateTimeLookup() {
	AddFuncLookup("date", Info{
		Display:     "Date",
		Category:    "time",
		Description: "Random date",
		Example:     "2006-01-02T15:04:05Z07:00",
		Output:      "string",
		Params: []Param{
			{
				Field:       "format",
				Display:     "Format",
				Type:        "string",
				Default:     "RFC3339",
				Options:     []string{"ANSIC", "UnixDate", "RubyDate", "RFC822", "RFC822Z", "RFC850", "RFC1123", "RFC1123Z", "RFC3339", "RFC3339Nano"},
				Description: "Date time string format output",
			},
		},
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			format, err := info.GetString(m, "format")
			if err != nil {
				return nil, err
			}

			switch format {
			case "ANSIC":
				return Date().Format(time.ANSIC), nil
			case "UnixDate":
				return Date().Format(time.UnixDate), nil
			case "RubyDate":
				return Date().Format(time.RubyDate), nil
			case "RFC822":
				return Date().Format(time.RFC822), nil
			case "RFC822Z":
				return Date().Format(time.RFC822Z), nil
			case "RFC850":
				return Date().Format(time.RFC850), nil
			case "RFC1123":
				return Date().Format(time.RFC1123), nil
			case "RFC1123Z":
				return Date().Format(time.RFC1123Z), nil
			case "RFC3339":
				return Date().Format(time.RFC3339), nil
			case "RFC3339Nano":
				return Date().Format(time.RFC3339Nano), nil
			}

			return "", errors.New("Invalid format")
		},
	})

	AddFuncLookup("nanosecond", Info{
		Display:     "Nanosecond",
		Category:    "time",
		Description: "Random nanosecond",
		Example:     "196446360",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return NanoSecond(), nil
		},
	})

	AddFuncLookup("second", Info{
		Display:     "Second",
		Category:    "time",
		Description: "Random second",
		Example:     "43",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Second(), nil
		},
	})

	AddFuncLookup("minute", Info{
		Display:     "Minute",
		Category:    "time",
		Description: "Random minute",
		Example:     "34",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Second(), nil
		},
	})

	AddFuncLookup("hour", Info{
		Display:     "Hour",
		Category:    "time",
		Description: "Random hour",
		Example:     "8",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Second(), nil
		},
	})

	AddFuncLookup("day", Info{
		Display:     "Day",
		Category:    "time",
		Description: "Random day",
		Example:     "12",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Day(), nil
		},
	})

	AddFuncLookup("weekday", Info{
		Display:     "Weekday",
		Category:    "time",
		Description: "Random week day",
		Example:     "Friday",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return WeekDay(), nil
		},
	})

	AddFuncLookup("year", Info{
		Display:     "Year",
		Category:    "time",
		Description: "Random year",
		Example:     "1900",
		Output:      "int",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return Year(), nil
		},
	})

	AddFuncLookup("timezone", Info{
		Display:     "Timezone",
		Category:    "time",
		Description: "Random timezone",
		Example:     "Kaliningrad Standard Time",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZone(), nil
		},
	})

	AddFuncLookup("timezoneabv", Info{
		Display:     "Timezone Abbreviation",
		Category:    "time",
		Description: "Random abbreviated timezone",
		Example:     "KST",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZoneAbv(), nil
		},
	})

	AddFuncLookup("timezonefull", Info{
		Display:     "Timezone Full",
		Category:    "time",
		Description: "Random full timezone",
		Example:     "(UTC+03:00) Kaliningrad, Minsk",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZoneFull(), nil
		},
	})

	AddFuncLookup("timezoneoffset", Info{
		Display:     "Timezone Offset",
		Category:    "time",
		Description: "Random timezone offset",
		Example:     "3",
		Output:      "float32",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZoneOffset(), nil
		},
	})

	AddFuncLookup("timezoneregion", Info{
		Display:     "Timezone Region",
		Category:    "time",
		Description: "Random region timezone",
		Example:     "America/Alaska",
		Output:      "string",
		Call: func(m *map[string][]string, info *Info) (interface{}, error) {
			return TimeZoneRegion(), nil
		},
	})

}
<|endoftext|>


<commit_before>package hush

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/pkg/errors"

	yaml "gopkg.in/yaml.v2"
)

type T map[Path]Value

func LoadTree() (T, error) {
	hushPath, err := hushPath()
	if err != nil {
		return nil, err
	}

	_, err = os.Stat(hushPath)
	if os.IsNotExist(err) {
		warn("hush file does not exist. assuming an empty one\n")
		return T{}, nil
	}
	if err != nil {
		return nil, errors.Wrap(err, "can't stat hush file")
	}

	file, err := os.Open(hushPath)
	if err != nil {
		return nil, errors.Wrap(err, "opening hush file")
	}
	hushData, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, errors.Wrap(err, "can't read hush file")
	}

	keys := make(yaml.MapSlice, 0)
	err = yaml.Unmarshal(hushData, &keys)
	if err != nil {
		return nil, errors.Wrap(err, "can't parse hush file")
	}
	tree := newT(keys)
	return tree, nil
}

func newT(items yaml.MapSlice) T {
	t := make(T, 3*len(items))
	newT_(items, []string{}, t)
	return t
}

func newT_(items yaml.MapSlice, crumbs []string, t T) {
	n := len(crumbs)
	for _, item := range items {
		key := item.Key.(string)
		crumbs = append(crumbs, key)

		switch val := item.Value.(type) {
		case string:
			p := NewPath(strings.Join(crumbs, "/"))
			t[p] = NewValue(val)
		case yaml.MapSlice:
			newT_(val, crumbs, t)
		default:
			panic(fmt.Sprintf("unexpected type: %#v", val))
		}
		crumbs = crumbs[:n] // remove final crumb
	}
}

func (t T) mapSlice() yaml.MapSlice {
	// sort by key
	kvs := make([][]string, 0, len(t))
	for p, val := range t {
		kvs = append(kvs, []string{string(p), string(val)})
	}
	sort.SliceStable(kvs, func(i, j int) bool {
		return kvs[i][0] < kvs[j][0]
	})

	var slice yaml.MapSlice
	for _, kv := range kvs {
		path := strings.Split(kv[0], "\t")
		slice = mapSlice_(slice, path, kv[1])
	}
	return slice
}

func mapSlice_(slice yaml.MapSlice, path []string, value string) yaml.MapSlice {
	if len(path) == 0 {
		panic("path should never have 0 length")
	}
	if len(path) == 1 {
		return append(slice, yaml.MapItem{
			Key:   path[0],
			Value: value,
		})
	}

	var inner yaml.MapSlice
	if len(slice) == 0 {
		slice = append(slice, yaml.MapItem{Key: path[0]})
	} else {
		final := slice[len(slice)-1]
		if final.Key.(string) == path[0] {
			inner = final.Value.(yaml.MapSlice)
		} else {
			slice = append(slice, yaml.MapItem{Key: path[0]})
		}
	}
	slice[len(slice)-1].Value = mapSlice_(inner, path[1:], value)
	return slice
}

func (t T) filter(pattern string) T {
	keep := make(T)
	for p, val := range t {
		if matches(p, pattern) {
			keep[p] = val
		}
	}
	return keep
}

func matches(p Path, pattern string) bool {
	ps := strings.Split(string(p), "\t")
	patterns := strings.Split(pattern, "/")
	if len(patterns) > len(ps) {
		return false
	}

	for i, pattern := range patterns {
		if !strings.Contains(ps[i], pattern) {
			return false
		}
	}
	return true
}

func (t T) get(p Path) (Value, bool) {
	val, ok := t[p]
	return val, ok
}

func (t T) set(p Path, val Value) {
	t[p] = val.Ciphertext(encryptionKey)
}

func (tree T) encrypt() {
	for p, v := range tree {
		tree[p] = v.Ciphertext(encryptionKey)
	}
}

var encryptionKey = []byte(`0123456789abcdef`)

func (tree T) decrypt() {
	for p, v := range tree {
		tree[p] = v.Plaintext(encryptionKey)
	}
}

// Print displays a tree for human consumption.
func (tree T) Print(w io.Writer) error {
	tree.decrypt()
	slice := tree.mapSlice()
	data, err := yaml.Marshal(slice)
	if err != nil {
		return errors.Wrap(err, "printing tree")
	}

	_, err = w.Write(data)
	return err
}

// Save stores a tree to disk for permanent, private archival.
func (tree T) Save() error {
	slice := tree.mapSlice()

	data, err := yaml.Marshal(slice)
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}

	// save to temporary file
	file, err := ioutil.TempFile("", "hush-")
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	_, err = file.Write(data)
	file.Close()
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}

	// move temporary file over top of permanent file
	hushPath, err := hushPath()
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	err = os.Rename(file.Name(), hushPath)
	return errors.Wrap(err, "saving tree")
}
<commit_msg>Make Decrypt return a new tree<commit_after>package hush

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/pkg/errors"

	yaml "gopkg.in/yaml.v2"
)

type T map[Path]Value

func LoadTree() (T, error) {
	hushPath, err := hushPath()
	if err != nil {
		return nil, err
	}

	_, err = os.Stat(hushPath)
	if os.IsNotExist(err) {
		warn("hush file does not exist. assuming an empty one\n")
		return T{}, nil
	}
	if err != nil {
		return nil, errors.Wrap(err, "can't stat hush file")
	}

	file, err := os.Open(hushPath)
	if err != nil {
		return nil, errors.Wrap(err, "opening hush file")
	}
	hushData, err := ioutil.ReadAll(file)
	if err != nil {
		return nil, errors.Wrap(err, "can't read hush file")
	}

	keys := make(yaml.MapSlice, 0)
	err = yaml.Unmarshal(hushData, &keys)
	if err != nil {
		return nil, errors.Wrap(err, "can't parse hush file")
	}
	tree := newT(keys)
	return tree, nil
}

func newT(items yaml.MapSlice) T {
	t := make(T, 3*len(items))
	newT_(items, []string{}, t)
	return t
}

func newT_(items yaml.MapSlice, crumbs []string, t T) {
	n := len(crumbs)
	for _, item := range items {
		key := item.Key.(string)
		crumbs = append(crumbs, key)

		switch val := item.Value.(type) {
		case string:
			p := NewPath(strings.Join(crumbs, "/"))
			t[p] = NewValue(val)
		case yaml.MapSlice:
			newT_(val, crumbs, t)
		default:
			panic(fmt.Sprintf("unexpected type: %#v", val))
		}
		crumbs = crumbs[:n] // remove final crumb
	}
}

func (t T) mapSlice() yaml.MapSlice {
	// sort by key
	kvs := make([][]string, 0, len(t))
	for p, val := range t {
		kvs = append(kvs, []string{string(p), string(val)})
	}
	sort.SliceStable(kvs, func(i, j int) bool {
		return kvs[i][0] < kvs[j][0]
	})

	var slice yaml.MapSlice
	for _, kv := range kvs {
		path := strings.Split(kv[0], "\t")
		slice = mapSlice_(slice, path, kv[1])
	}
	return slice
}

func mapSlice_(slice yaml.MapSlice, path []string, value string) yaml.MapSlice {
	if len(path) == 0 {
		panic("path should never have 0 length")
	}
	if len(path) == 1 {
		return append(slice, yaml.MapItem{
			Key:   path[0],
			Value: value,
		})
	}

	var inner yaml.MapSlice
	if len(slice) == 0 {
		slice = append(slice, yaml.MapItem{Key: path[0]})
	} else {
		final := slice[len(slice)-1]
		if final.Key.(string) == path[0] {
			inner = final.Value.(yaml.MapSlice)
		} else {
			slice = append(slice, yaml.MapItem{Key: path[0]})
		}
	}
	slice[len(slice)-1].Value = mapSlice_(inner, path[1:], value)
	return slice
}

func (t T) filter(pattern string) T {
	keep := make(T)
	for p, val := range t {
		if matches(p, pattern) {
			keep[p] = val
		}
	}
	return keep
}

func matches(p Path, pattern string) bool {
	ps := strings.Split(string(p), "\t")
	patterns := strings.Split(pattern, "/")
	if len(patterns) > len(ps) {
		return false
	}

	for i, pattern := range patterns {
		if !strings.Contains(ps[i], pattern) {
			return false
		}
	}
	return true
}

func (t T) get(p Path) (Value, bool) {
	val, ok := t[p]
	return val, ok
}

func (t T) set(p Path, val Value) {
	t[p] = val.Ciphertext(encryptionKey)
}

func (tree T) encrypt() {
	for p, v := range tree {
		tree[p] = v.Ciphertext(encryptionKey)
	}
}

var encryptionKey = []byte(`0123456789abcdef`)

// Decrypt returns a copy of this tree with all leaves decrypted.
func (tree T) Decrypt() T {
	t := make(T, len(tree))
	for p, v := range tree {
		t[p] = v.Plaintext(encryptionKey)
	}
	return t
}

// Print displays a tree for human consumption.
func (tree T) Print(w io.Writer) error {
	tree = tree.Decrypt()
	slice := tree.mapSlice()
	data, err := yaml.Marshal(slice)
	if err != nil {
		return errors.Wrap(err, "printing tree")
	}

	_, err = w.Write(data)
	return err
}

// Save stores a tree to disk for permanent, private archival.
func (tree T) Save() error {
	slice := tree.mapSlice()

	data, err := yaml.Marshal(slice)
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}

	// save to temporary file
	file, err := ioutil.TempFile("", "hush-")
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	_, err = file.Write(data)
	file.Close()
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}

	// move temporary file over top of permanent file
	hushPath, err := hushPath()
	if err != nil {
		return errors.Wrap(err, "saving tree")
	}
	err = os.Rename(file.Name(), hushPath)
	return errors.Wrap(err, "saving tree")
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Patrick Gundlach, speedata (Berlin, Germany)
// Copyright 2014 The Gogs Authors.//

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package git

import (
	"bytes"
	"errors"
	"path"
)

// A tree is a flat directory listing.
type Tree struct {
	TreeEntries []*TreeEntry
	Oid         *Oid
	repository  *Repository
}

// A tree entry is similar to a directory entry (file name, type) in a real file system.
type TreeEntry struct {
	Filemode int
	Name     string
	Id       *Oid
	Type     ObjectType
}

// There are only a few file modes in Git. They look like unix file modes, but they can only be
// one of these.
const (
	FileModeBlob     = 0100644
	FileModeBlobExec = 0100755
	FileModeSymlink  = 0120000
	FileModeCommit   = 0160000
	FileModeTree     = 0040000
)

func (entry *TreeEntry) IsDir() bool {
	return entry.Filemode == FileModeTree
}

func (entry *TreeEntry) IsFile() bool {
	return entry.Filemode == FileModeBlob || entry.Filemode == FileModeBlobExec
}

// Parse tree information from the (uncompressed) raw
// data from the tree object.
func parseTreeData(data []byte) (*Tree, error) {
	tree := new(Tree)
	tree.TreeEntries = make([]*TreeEntry, 0, 10)
	l := len(data)
	pos := 0
	for pos < l {
		te := new(TreeEntry)
		spacepos := bytes.IndexByte(data[pos:], ' ')
		switch string(data[pos : pos+spacepos]) {
		case "100644":
			te.Filemode = FileModeBlob
			te.Type = ObjectBlob
		case "100755":
			te.Filemode = FileModeBlobExec
			te.Type = ObjectBlob
		case "120000":
			te.Filemode = FileModeSymlink
			te.Type = ObjectBlob
		case "160000":
			te.Filemode = FileModeCommit
			te.Type = ObjectCommit
		case "40000":
			te.Filemode = FileModeTree
			te.Type = ObjectTree
		default:
			return nil, errors.New("unknown type: " + string(data[pos:pos+spacepos]))
		}
		pos += spacepos + 1
		zero := bytes.IndexByte(data[pos:], 0)
		te.Name = string(data[pos : pos+zero])
		pos += zero + 1
		oid, err := NewOid(data[pos : pos+20])
		if err != nil {
			return nil, err
		}
		te.Id = oid
		pos = pos + 20
		tree.TreeEntries = append(tree.TreeEntries, te)
	}
	return tree, nil
}

// Find the entry in this directory (tree) with the given name.
func (t *Tree) EntryByName(name string) *TreeEntry {
	for _, v := range t.TreeEntries {
		if v.Name == name {
			return v
		}
	}
	return nil
}

// Get the n-th entry of this tree (0 = first entry). You can also access
// t.TreeEntries[index] directly.
func (t *Tree) EntryByIndex(index int) *TreeEntry {
	if index >= len(t.TreeEntries) {
		return nil
	}
	return t.TreeEntries[index]
}

// Get the number of entries in the directory (tree). Same as
// len(t.TreeEntries).
func (t *Tree) EntryCount() int {
	return len(t.TreeEntries)
}

type TreeWalkCallback func(string, *TreeEntry) int

// The entries will be traversed in the specified order,
// children subtrees will be automatically loaded as required, and the
// callback will be called once per entry with the current (relative) root
// for the entry and the entry data itself.
//
// If the callback returns a positive value, the passed entry will be skipped
// on the traversal (in pre mode). A negative value stops the walk.
//
// Walk will panic() if an error occurs
func (t *Tree) Walk(callback TreeWalkCallback) error {
	t._walk(callback, "")
	return nil
}

func (t *Tree) _walk(cb TreeWalkCallback, dirname string) bool {
	for _, te := range t.TreeEntries {
		cont := cb(dirname, te)
		switch {
		case cont < 0:
			return false
		case cont == 0:
			// descend if it is a tree
			if te.Type == ObjectTree {
				t, err := t.repository.LookupTree(te.Id)
				if err != nil {
					panic(err)
				}
				if t._walk(cb, path.Join(dirname, te.Name)) == false {
					return false
				}
			}
		case cont > 0:
			// do nothing, don't descend into the tree
		}
	}
	return true
}

// Find the tree object in the repository.
func (repos *Repository) LookupTree(oid *Oid) (*Tree, error) {
	_, _, data, err := repos.getRawObject(oid)
	if err != nil {
		return nil, err
	}
	tree, err := parseTreeData(data)
	if err != nil {
		return nil, err
	}
	tree.Oid = oid
	tree.repository = repos
	return tree, nil
}
<commit_msg>add subtree for repository<commit_after>// Copyright (c) 2013 Patrick Gundlach, speedata (Berlin, Germany)
// Copyright 2014 The Gogs Authors.//

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package git

import (
	"bytes"
	"errors"
	"path"
	"strings"
)

// A tree is a flat directory listing.
type Tree struct {
	TreeEntries []*TreeEntry
	Oid         *Oid
	repository  *Repository
}

// A tree entry is similar to a directory entry (file name, type) in a real file system.
type TreeEntry struct {
	Filemode int
	Name     string
	Id       *Oid
	Type     ObjectType
}

// There are only a few file modes in Git. They look like unix file modes, but they can only be
// one of these.
const (
	FileModeBlob     = 0100644
	FileModeBlobExec = 0100755
	FileModeSymlink  = 0120000
	FileModeCommit   = 0160000
	FileModeTree     = 0040000
)

func (entry *TreeEntry) IsDir() bool {
	return entry.Filemode == FileModeTree
}

func (entry *TreeEntry) IsFile() bool {
	return entry.Filemode == FileModeBlob || entry.Filemode == FileModeBlobExec
}

// Parse tree information from the (uncompressed) raw
// data from the tree object.
func parseTreeData(data []byte) (*Tree, error) {
	tree := new(Tree)
	tree.TreeEntries = make([]*TreeEntry, 0, 10)
	l := len(data)
	pos := 0
	for pos < l {
		te := new(TreeEntry)
		spacepos := bytes.IndexByte(data[pos:], ' ')
		switch string(data[pos : pos+spacepos]) {
		case "100644":
			te.Filemode = FileModeBlob
			te.Type = ObjectBlob
		case "100755":
			te.Filemode = FileModeBlobExec
			te.Type = ObjectBlob
		case "120000":
			te.Filemode = FileModeSymlink
			te.Type = ObjectBlob
		case "160000":
			te.Filemode = FileModeCommit
			te.Type = ObjectCommit
		case "40000":
			te.Filemode = FileModeTree
			te.Type = ObjectTree
		default:
			return nil, errors.New("unknown type: " + string(data[pos:pos+spacepos]))
		}
		pos += spacepos + 1
		zero := bytes.IndexByte(data[pos:], 0)
		te.Name = string(data[pos : pos+zero])
		pos += zero + 1
		oid, err := NewOid(data[pos : pos+20])
		if err != nil {
			return nil, err
		}
		te.Id = oid
		pos = pos + 20
		tree.TreeEntries = append(tree.TreeEntries, te)
	}
	return tree, nil
}

// Find the entry in this directory (tree) with the given name.
func (t *Tree) EntryByName(name string) *TreeEntry {
	for _, v := range t.TreeEntries {
		if v.Name == name {
			return v
		}
	}
	return nil
}

// Get the n-th entry of this tree (0 = first entry). You can also access
// t.TreeEntries[index] directly.
func (t *Tree) EntryByIndex(index int) *TreeEntry {
	if index >= len(t.TreeEntries) {
		return nil
	}
	return t.TreeEntries[index]
}

// Get the number of entries in the directory (tree). Same as
// len(t.TreeEntries).
func (t *Tree) EntryCount() int {
	return len(t.TreeEntries)
}

type TreeWalkCallback func(string, *TreeEntry) int

// The entries will be traversed in the specified order,
// children subtrees will be automatically loaded as required, and the
// callback will be called once per entry with the current (relative) root
// for the entry and the entry data itself.
//
// If the callback returns a positive value, the passed entry will be skipped
// on the traversal (in pre mode). A negative value stops the walk.
//
// Walk will panic() if an error occurs
func (t *Tree) Walk(callback TreeWalkCallback) error {
	t._walk(callback, "")
	return nil
}

func (t *Tree) _walk(cb TreeWalkCallback, dirname string) bool {
	for _, te := range t.TreeEntries {
		cont := cb(dirname, te)
		switch {
		case cont < 0:
			return false
		case cont == 0:
			// descend if it is a tree
			if te.Type == ObjectTree {
				t, err := t.repository.LookupTree(te.Id)
				if err != nil {
					panic(err)
				}
				if t._walk(cb, path.Join(dirname, te.Name)) == false {
					return false
				}
			}
		case cont > 0:
			// do nothing, don't descend into the tree
		}
	}
	return true
}

// Find the tree object in the repository.
func (repos *Repository) LookupTree(oid *Oid) (*Tree, error) {
	_, _, data, err := repos.getRawObject(oid)
	if err != nil {
		return nil, err
	}
	tree, err := parseTreeData(data)
	if err != nil {
		return nil, err
	}
	tree.Oid = oid
	tree.repository = repos
	return tree, nil
}

func (repos *Repository) SubTree(tree *Tree, rpath string) (*Tree, error) {
	if rpath == "" {
		return tree, nil
	}
	paths := strings.Split(rpath, "/")
	var g = tree
	var err error
	for _, p := range paths {
		s := g.EntryByName(p)
		if s == nil {
			return nil, nil
		}
		g, err = repos.LookupTree(s.Id)
		if err != nil {
			return nil, err
		}
		if g == nil {
			return nil, nil
		}
	}
	return g, nil
}
<|endoftext|>


<commit_before>package trek

import (
	"database/sql"
	"errors"
	"reflect"
	"sort"
)

var (
	migrations                   []migration
	errNoRows                    = errors.New("sql: no rows in result set")
	errUnrecognizedDatabase      = errors.New("trek: unrecognized database")
	errUnrecognizedAction        = errors.New("trek: unrecognized action")
	errPreviousMigrationNotFound = errors.New("trek: previous migration not found")
	errVersionAlreadyRegistered  = errors.New("Version already registered")
)

const (
	// UP migrates the database to the latest version
	UP = "up"
	// DOWN migrates the database to a previous version
	DOWN = "down"
	// POSTGRES is a supported database
	POSTGRES = "postgres"
	// MYSQL is a supported database
	MYSQL = "mysql"
)

// Register adds migrations to be runned
func Register(version int64, up, down migrationHandler) error {
	if versionAlreadyRegistered(version) {
		return errVersionAlreadyRegistered
	}
	migrations = append(migrations, migration{
		Version: version,
		Up:      up,
		Down:    down,
	})
	return nil
}

// Run executes database migrations
func Run(db *sql.DB, options ...interface{}) (didChange bool, newVersion int64, err error) {
	if len(migrations) == 0 {
		return
	}

	sort.Sort(byVersion(migrations))

	config := parseOptions(options)
	dtbs := &database{db, config}

	err = createTable(dtbs)
	if err != nil {
		return
	}

	oldVersion, err := getVersion(dtbs)
	if err != nil {
		return
	}

	newVersion, err = runMigrations(dtbs, oldVersion)
	didChange = oldVersion != newVersion
	return
}

func parseOptions(options []interface{}) *configuration {
	config := configuration{Action: UP, Database: POSTGRES}

	for _, opt := range options {
		value := reflect.ValueOf(opt)
		if value.Kind() == reflect.String {
			str := value.String()
			switch str {
			case UP:
			case DOWN:
				config.Action = str
				break
			case POSTGRES:
			case MYSQL:
				config.Database = str
				break
			}
		}
	}

	return &config
}

func createTable(db *database) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `CREATE TABLE IF NOT EXISTS migrations (id SERIAL PRIMARY KEY, version BIGINT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW())`
		break
	case MYSQL:
		query = `CREATE TABLE IF NOT EXISTS migrations (id BIGINT PRIMARY KEY AUTO_INCREMENT, version BIGINT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`
		break
	default:
		return errUnrecognizedDatabase
	}

	_, err := db.Exec(query)
	return err
}

func getVersion(db *database) (currentVersion int64, err error) {
	err = db.QueryRow(`SELECT version FROM migrations ORDER BY id DESC LIMIT 1`).Scan(&currentVersion)
	if err != nil && err.Error() == errNoRows.Error() {
		currentVersion = 0
		err = nil
	}
	return
}

func runMigrations(db *database, oldVersion int64) (newVersion int64, err error) {
	switch db.Action {
	case UP:
		newVersion, err = runUp(db, oldVersion)
		break
	case DOWN:
		newVersion, err = runDown(db, oldVersion)
		break
	default:
		err = errUnrecognizedAction
	}

	return
}

func runUp(db *database, oldVersion int64) (newVersion int64, err error) {
	for _, m := range migrations {
		if m.Version <= oldVersion {
			continue
		}

		if m.Up != nil {
			err = m.Up(db.DB)
			if err != nil {
				return
			}
		}

		err = setVersion(db, m.Version)
		if err != nil {
			return
		}

		newVersion = m.Version
	}

	return
}

func runDown(db *database, oldVersion int64) (newVersion int64, err error) {
	if oldVersion == 0 {
		return
	}

	var m *migration
	for i := len(migrations) - 1; i >= 0; i-- {
		if migrations[i].Version <= oldVersion {
			m = &migrations[i]
			break
		}
	}

	if m == nil {
		err = errPreviousMigrationNotFound
		return
	}

	if m.Down != nil {
		err = m.Down(db.DB)
		if err != nil {
			return
		}
	}

	newVersion = m.Version - 1
	err = setVersion(db, newVersion)
	return
}

func setVersion(db *database, version int64) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `INSERT INTO migrations (version) VALUES ($1)`
		break
	case MYSQL:
		query = `INSERT INTO migrations (version) VALUES (?)`
		break
	default:
		return errUnrecognizedDatabase
	}

	stmt, err := db.Prepare(query)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(version)
	return err
}

func versionAlreadyRegistered(version int64) bool {
	for _, m := range migrations {
		if m.Version == version {
			return true
		}
	}
	return false
}

type migrationHandler func(*sql.DB) error

type configuration struct {
	Action   string
	Database string
}

type database struct {
	*sql.DB
	*configuration
}

type migration struct {
	Version int64
	Up      migrationHandler
	Down    migrationHandler
}

type byVersion []migration

func (s byVersion) Len() int { return len(s) }

func (s byVersion) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s byVersion) Less(i, j int) bool { return s[i].Version < s[j].Version }
<commit_msg>fix version change return value<commit_after>package trek

import (
	"database/sql"
	"errors"
	"reflect"
	"sort"
)

var (
	migrations                   []migration
	errNoRows                    = errors.New("sql: no rows in result set")
	errUnrecognizedDatabase      = errors.New("trek: unrecognized database")
	errUnrecognizedAction        = errors.New("trek: unrecognized action")
	errPreviousMigrationNotFound = errors.New("trek: previous migration not found")
	errVersionAlreadyRegistered  = errors.New("Version already registered")
)

const (
	// UP migrates the database to the latest version
	UP = "up"
	// DOWN migrates the database to a previous version
	DOWN = "down"
	// POSTGRES is a supported database
	POSTGRES = "postgres"
	// MYSQL is a supported database
	MYSQL = "mysql"
)

// Register adds migrations to be runned
func Register(version int64, up, down migrationHandler) error {
	if versionAlreadyRegistered(version) {
		return errVersionAlreadyRegistered
	}
	migrations = append(migrations, migration{
		Version: version,
		Up:      up,
		Down:    down,
	})
	return nil
}

// Run executes database migrations
func Run(db *sql.DB, options ...interface{}) (didChange bool, newVersion int64, err error) {
	if len(migrations) == 0 {
		return
	}

	sort.Sort(byVersion(migrations))

	config := parseOptions(options)
	dtbs := &database{db, config}

	err = createTable(dtbs)
	if err != nil {
		return
	}

	oldVersion, err := getVersion(dtbs)
	if err != nil {
		return
	}

	newVersion, err = runMigrations(dtbs, oldVersion)
	didChange = oldVersion != newVersion
	return
}

func parseOptions(options []interface{}) *configuration {
	config := configuration{Action: UP, Database: POSTGRES}

	for _, opt := range options {
		value := reflect.ValueOf(opt)
		if value.Kind() == reflect.String {
			str := value.String()
			switch str {
			case UP:
			case DOWN:
				config.Action = str
				break
			case POSTGRES:
			case MYSQL:
				config.Database = str
				break
			}
		}
	}

	return &config
}

func createTable(db *database) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `CREATE TABLE IF NOT EXISTS migrations (id SERIAL PRIMARY KEY, version BIGINT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW())`
		break
	case MYSQL:
		query = `CREATE TABLE IF NOT EXISTS migrations (id BIGINT PRIMARY KEY AUTO_INCREMENT, version BIGINT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`
		break
	default:
		return errUnrecognizedDatabase
	}

	_, err := db.Exec(query)
	return err
}

func getVersion(db *database) (currentVersion int64, err error) {
	err = db.QueryRow(`SELECT version FROM migrations ORDER BY id DESC LIMIT 1`).Scan(&currentVersion)
	if err != nil && err.Error() == errNoRows.Error() {
		currentVersion = 0
		err = nil
	}
	return
}

func runMigrations(db *database, oldVersion int64) (newVersion int64, err error) {
	switch db.Action {
	case UP:
		newVersion, err = runUp(db, oldVersion)
		break
	case DOWN:
		newVersion, err = runDown(db, oldVersion)
		break
	default:
		err = errUnrecognizedAction
	}

	return
}

func runUp(db *database, oldVersion int64) (newVersion int64, err error) {
	newVersion = oldVersion

	for _, m := range migrations {
		if m.Version <= oldVersion {
			continue
		}

		if m.Up != nil {
			err = m.Up(db.DB)
			if err != nil {
				return
			}
		}

		err = setVersion(db, m.Version)
		if err != nil {
			return
		}

		newVersion = m.Version
	}

	return
}

func runDown(db *database, oldVersion int64) (newVersion int64, err error) {
	if oldVersion == 0 {
		return
	}

	newVersion = oldVersion

	var m *migration
	for i := len(migrations) - 1; i >= 0; i-- {
		if migrations[i].Version <= oldVersion {
			m = &migrations[i]
			break
		}
	}

	if m == nil {
		err = errPreviousMigrationNotFound
		return
	}

	if m.Down != nil {
		err = m.Down(db.DB)
		if err != nil {
			return
		}
	}

	err = setVersion(db, m.Version-1)
	if err != nil {
		return
	}

	newVersion = m.Version - 1
	return
}

func setVersion(db *database, version int64) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `INSERT INTO migrations (version) VALUES ($1)`
		break
	case MYSQL:
		query = `INSERT INTO migrations (version) VALUES (?)`
		break
	default:
		return errUnrecognizedDatabase
	}

	stmt, err := db.Prepare(query)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(version)
	return err
}

func versionAlreadyRegistered(version int64) bool {
	for _, m := range migrations {
		if m.Version == version {
			return true
		}
	}
	return false
}

type migrationHandler func(*sql.DB) error

type configuration struct {
	Action   string
	Database string
}

type database struct {
	*sql.DB
	*configuration
}

type migration struct {
	Version int64
	Up      migrationHandler
	Down    migrationHandler
}

type byVersion []migration

func (s byVersion) Len() int { return len(s) }

func (s byVersion) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s byVersion) Less(i, j int) bool { return s[i].Version < s[j].Version }
<|endoftext|>


<commit_before>// Implementation of an R-Way Trie data structure.
//
// A Trie has a root Node which is the base of the tree.
// Each subsequent Node has a letter and children, which are
// nodes that have letter values associated with them.
package trie

import (
	"sort"
	"sync"
)

type Node struct {
	val      rune
	path     string
	term     bool
	depth    int
	meta     interface{}
	mask     uint64
	parent   *Node
	children map[rune]*Node
}

type Trie struct {
	mu   sync.Mutex
	root *Node
	size int
}

type ByKeys []string

func (a ByKeys) Len() int           { return len(a) }
func (a ByKeys) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByKeys) Less(i, j int) bool { return len(a[i]) < len(a[j]) }

const nul = 0x0

// Creates a new Trie with an initialized root Node.
func New() *Trie {
	return &Trie{
		root: &Node{children: make(map[rune]*Node), depth: 0},
		size: 0,
	}
}

// Returns the root node for the Trie.
func (t *Trie) Root() *Node {
	return t.root
}

// Adds the key to the Trie, including meta data. Meta data
// is stored as `interface{}` and must be type cast by
// the caller.
func (t *Trie) Add(key string, meta interface{}) *Node {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.size++
	runes := []rune(key)
	bitmask := maskruneslice(runes)
	node := t.root
	node.mask |= bitmask
	for i := range runes {
		r := runes[i]
		bitmask = maskruneslice(runes[i:])
		if n, ok := node.children[r]; ok {
			node = n
			node.mask |= bitmask
		} else {
			node = node.NewChild(r, "", bitmask, nil, false)
		}
	}
	node = node.NewChild(nul, key, 0, meta, true)
	return node
}

// Finds and returns meta data associated
// with `key`.
func (t *Trie) Find(key string) (*Node, bool) {
	node := findNode(t.Root(), []rune(key))
	if node == nil {
		return nil, false
	}

	node, ok := node.Children()[nul]
	if !ok || !node.term {
		return nil, false
	}

	return node, true
}

func (t *Trie) HasKeysWithPrefix(key string) bool {
	node := findNode(t.Root(), []rune(key))
	return node != nil
}

// Removes a key from the trie, ensuring that
// all bitmasks up to root are appropriately recalculated.
func (t *Trie) Remove(key string) {
	var (
		i    int
		rs   = []rune(key)
		node = findNode(t.Root(), []rune(key))
	)

	t.mu.Lock()
	defer t.mu.Unlock()

	t.size--
	for n := node.Parent(); n != nil; n = n.Parent() {
		i++
		if len(n.Children()) > 1 {
			r := rs[len(rs)-i]
			n.RemoveChild(r)
			break
		}
	}
}

// Returns all the keys currently stored in the trie.
func (t *Trie) Keys() []string {
	return t.PrefixSearch("")
}

// Performs a fuzzy search against the keys in the trie.
func (t Trie) FuzzySearch(pre string) []string {
	keys := fuzzycollect(t.Root(), []rune(pre))
	sort.Sort(ByKeys(keys))
	return keys
}

// Performs a prefix search against the keys in the trie.
func (t Trie) PrefixSearch(pre string) []string {
	node := findNode(t.Root(), []rune(pre))
	if node == nil {
		return nil
	}

	return collect(node)
}

// Creates and returns a pointer to a new child for the node.
func (parent *Node) NewChild(val rune, path string, bitmask uint64, meta interface{}, term bool) *Node {
	node := &Node{
		val:      val,
		path:    path,
		mask:     bitmask,
		term:     term,
		meta:     meta,
		parent:   parent,
		children: make(map[rune]*Node),
		depth:    parent.depth + 1,
	}
	parent.children[node.val] = node
	parent.mask |= bitmask
	return node
}

func (n *Node) RemoveChild(r rune) {
	delete(n.children, r)
	for nd := n.parent; nd != nil; nd = nd.parent {
		nd.mask ^= nd.mask
		nd.mask |= uint64(1) << uint64(nd.val-'a')
		for _, c := range nd.children {
			nd.mask |= c.mask
		}
	}
}

// Returns the parent of this node.
func (n Node) Parent() *Node {
	return n.parent
}

// Returns the meta information of this node.
func (n Node) Meta() interface{} {
	return n.meta
}

// Returns the children of this node.
func (n Node) Children() map[rune]*Node {
	return n.children
}

func (n Node) Terminating() bool {
	return n.term
}

func (n Node) Val() rune {
	return n.val
}

func (n Node) Depth() int {
	return n.depth
}

// Returns a uint64 representing the current
// mask of this node.
func (n Node) Mask() uint64 {
	return n.mask
}

func findNode(node *Node, runes []rune) *Node {
	if node == nil {
		return nil
	}

	if len(runes) == 0 {
		return node
	}

	n, ok := node.Children()[runes[0]]
	if !ok {
		return nil
	}

	var nrunes []rune
	if len(runes) > 1 {
		nrunes = runes[1:]
	} else {
		nrunes = runes[0:0]
	}

	return findNode(n, nrunes)
}

func findPath(node *Node, runes []rune) []*Node {
	if node == nil {
		return []*Node{}
	}

	if len(runes) == 0 {
		return []*Node{node}
	}

	n, ok := node.Children()[runes[0]]
	if !ok {
		return nil
	}

	var nrunes []rune
	if len(runes) > 1 {
		nrunes = runes[1:]
	} else {
		nrunes = runes[0:0]
	}

	return append(findPath(n, nrunes), node)
}

func maskruneslice(rs []rune) uint64 {
	var m uint64
	for _, r := range rs {
		m |= uint64(1) << uint64(r-'a')
	}
	return m
}

func collect(node *Node) []string {
	var (
		keys []string
		n    *Node
		i    int
	)
	nodes := []*Node{node}
	for l := len(nodes); l != 0; l = len(nodes) {
		i = l - 1
		n = nodes[i]
		nodes = nodes[:i]
		for _, c := range n.children {
			nodes = append(nodes, c)
		}
		if n.term {
			word := n.path
			keys = append(keys, word)
		}
	}
	return keys
}

type potentialSubtree struct {
	idx  int
	node *Node
}

func fuzzycollect(node *Node, partial []rune) []string {
	var (
		m    uint64
		i    int
		p    potentialSubtree
		keys []string
	)

	potential := []potentialSubtree{potentialSubtree{node: node, idx: 0}}
	for l := len(potential); l > 0; l = len(potential) {
		i = l - 1
		p = potential[i]
		potential = potential[:i]
		m = maskruneslice(partial[p.idx:])
		if (p.node.mask & m) != m {
			continue
		}

		if p.node.val == partial[p.idx] {
			p.idx++
			if p.idx == len(partial) {
				keys = append(keys, collect(p.node)...)
				continue
			}
		}

		for _, c := range p.node.children {
			potential = append(potential, potentialSubtree{node: c, idx: p.idx})
		}
	}
	return keys
}
<commit_msg>improve allocs by tuning slice capacity<commit_after>// Implementation of an R-Way Trie data structure.
//
// A Trie has a root Node which is the base of the tree.
// Each subsequent Node has a letter and children, which are
// nodes that have letter values associated with them.
package trie

import (
	"sort"
	"sync"
)

type Node struct {
	val       rune
	path      string
	term      bool
	depth     int
	meta      interface{}
	mask      uint64
	parent    *Node
	children  map[rune]*Node
	termCount int
}

type Trie struct {
	mu   sync.Mutex
	root *Node
	size int
}

type ByKeys []string

func (a ByKeys) Len() int           { return len(a) }
func (a ByKeys) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByKeys) Less(i, j int) bool { return len(a[i]) < len(a[j]) }

const nul = 0x0

// Creates a new Trie with an initialized root Node.
func New() *Trie {
	return &Trie{
		root: &Node{children: make(map[rune]*Node), depth: 0},
		size: 0,
	}
}

// Returns the root node for the Trie.
func (t *Trie) Root() *Node {
	return t.root
}

// Adds the key to the Trie, including meta data. Meta data
// is stored as `interface{}` and must be type cast by
// the caller.
func (t *Trie) Add(key string, meta interface{}) *Node {
	t.mu.Lock()
	defer t.mu.Unlock()

	t.size++
	runes := []rune(key)
	bitmask := maskruneslice(runes)
	node := t.root
	node.mask |= bitmask
	node.termCount++
	for i := range runes {
		r := runes[i]
		bitmask = maskruneslice(runes[i:])
		if n, ok := node.children[r]; ok {
			node = n
			node.mask |= bitmask
		} else {
			node = node.NewChild(r, "", bitmask, nil, false)
		}
		node.termCount++
	}
	node = node.NewChild(nul, key, 0, meta, true)
	return node
}

// Finds and returns meta data associated
// with `key`.
func (t *Trie) Find(key string) (*Node, bool) {
	node := findNode(t.Root(), []rune(key))
	if node == nil {
		return nil, false
	}

	node, ok := node.Children()[nul]
	if !ok || !node.term {
		return nil, false
	}

	return node, true
}

func (t *Trie) HasKeysWithPrefix(key string) bool {
	node := findNode(t.Root(), []rune(key))
	return node != nil
}

// Removes a key from the trie, ensuring that
// all bitmasks up to root are appropriately recalculated.
func (t *Trie) Remove(key string) {
	var (
		i    int
		rs   = []rune(key)
		node = findNode(t.Root(), []rune(key))
	)

	t.mu.Lock()
	defer t.mu.Unlock()

	t.size--
	for n := node.Parent(); n != nil; n = n.Parent() {
		i++
		if len(n.Children()) > 1 {
			r := rs[len(rs)-i]
			n.RemoveChild(r)
			break
		}
	}
}

// Returns all the keys currently stored in the trie.
func (t *Trie) Keys() []string {
	return t.PrefixSearch("")
}

// Performs a fuzzy search against the keys in the trie.
func (t Trie) FuzzySearch(pre string) []string {
	keys := fuzzycollect(t.Root(), []rune(pre))
	sort.Sort(ByKeys(keys))
	return keys
}

// Performs a prefix search against the keys in the trie.
func (t Trie) PrefixSearch(pre string) []string {
	node := findNode(t.Root(), []rune(pre))
	if node == nil {
		return nil
	}

	return collect(node)
}

// Creates and returns a pointer to a new child for the node.
func (parent *Node) NewChild(val rune, path string, bitmask uint64, meta interface{}, term bool) *Node {
	node := &Node{
		val:      val,
		path:     path,
		mask:     bitmask,
		term:     term,
		meta:     meta,
		parent:   parent,
		children: make(map[rune]*Node),
		depth:    parent.depth + 1,
	}
	parent.children[node.val] = node
	parent.mask |= bitmask
	return node
}

func (n *Node) RemoveChild(r rune) {
	delete(n.children, r)
	for nd := n.parent; nd != nil; nd = nd.parent {
		nd.mask ^= nd.mask
		nd.mask |= uint64(1) << uint64(nd.val-'a')
		for _, c := range nd.children {
			nd.mask |= c.mask
		}
	}
}

// Returns the parent of this node.
func (n Node) Parent() *Node {
	return n.parent
}

// Returns the meta information of this node.
func (n Node) Meta() interface{} {
	return n.meta
}

// Returns the children of this node.
func (n Node) Children() map[rune]*Node {
	return n.children
}

func (n Node) Terminating() bool {
	return n.term
}

func (n Node) Val() rune {
	return n.val
}

func (n Node) Depth() int {
	return n.depth
}

// Returns a uint64 representing the current
// mask of this node.
func (n Node) Mask() uint64 {
	return n.mask
}

func findNode(node *Node, runes []rune) *Node {
	if node == nil {
		return nil
	}

	if len(runes) == 0 {
		return node
	}

	n, ok := node.Children()[runes[0]]
	if !ok {
		return nil
	}

	var nrunes []rune
	if len(runes) > 1 {
		nrunes = runes[1:]
	} else {
		nrunes = runes[0:0]
	}

	return findNode(n, nrunes)
}

func maskruneslice(rs []rune) uint64 {
	var m uint64
	for _, r := range rs {
		m |= uint64(1) << uint64(r-'a')
	}
	return m
}

func collect(node *Node) []string {
	var (
		n *Node
		i int
	)
	keys := make([]string, 0, node.termCount)
	nodes := make([]*Node, 1, len(node.children))
	nodes[0] = node
	for l := len(nodes); l != 0; l = len(nodes) {
		i = l - 1
		n = nodes[i]
		nodes = nodes[:i]
		for _, c := range n.children {
			nodes = append(nodes, c)
		}
		if n.term {
			word := n.path
			keys = append(keys, word)
		}
	}
	return keys
}

type potentialSubtree struct {
	idx  int
	node *Node
}

func fuzzycollect(node *Node, partial []rune) []string {
	var (
		m    uint64
		i    int
		p    potentialSubtree
		keys []string
	)

	potential := []potentialSubtree{potentialSubtree{node: node, idx: 0}}
	for l := len(potential); l > 0; l = len(potential) {
		i = l - 1
		p = potential[i]
		potential = potential[:i]
		m = maskruneslice(partial[p.idx:])
		if (p.node.mask & m) != m {
			continue
		}

		if p.node.val == partial[p.idx] {
			p.idx++
			if p.idx == len(partial) {
				keys = append(keys, collect(p.node)...)
				continue
			}
		}

		for _, c := range p.node.children {
			potential = append(potential, potentialSubtree{node: c, idx: p.idx})
		}
	}
	return keys
}
<|endoftext|>


<commit_before>package main

// Just enough UPnP to be able to forward ports
//

import (
	"bytes"
	"encoding/xml"
	"errors"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

type upnpNAT struct {
	serviceURL string
	ourIP      string
	urnDomain  string
}

func Discover() (nat NAT, err error) {
	ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900")
	if err != nil {
		return
	}
	conn, err := net.ListenPacket("udp4", ":0")
	if err != nil {
		return
	}
	socket := conn.(*net.UDPConn)
	defer socket.Close()

	err = socket.SetDeadline(time.Now().Add(3 * time.Second))
	if err != nil {
		return
	}

	st := "InternetGatewayDevice:1"

	buf := bytes.NewBufferString(
		"M-SEARCH * HTTP/1.1\r\n" +
			"HOST: 239.255.255.250:1900\r\n" +
			"ST: ssdp:all\r\n" +
			"MAN: \"ssdp:discover\"\r\n" +
			"MX: 2\r\n\r\n")
	message := buf.Bytes()
	answerBytes := make([]byte, 1024)
	for i := 0; i < 3; i++ {
		_, err = socket.WriteToUDP(message, ssdp)
		if err != nil {
			return
		}
		var n int
		n, _, err = socket.ReadFromUDP(answerBytes)
		for {
			n, _, err = socket.ReadFromUDP(answerBytes)
			if err != nil {
				break
			}
			answer := string(answerBytes[0:n])
			if strings.Index(answer, st) < 0 {
				continue
			}
			// HTTP header field names are case-insensitive.
			// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
			locString := "\r\nlocation:"
			answer = strings.ToLower(answer)
			locIndex := strings.Index(answer, locString)
			if locIndex < 0 {
				continue
			}
			loc := answer[locIndex+len(locString):]
			endIndex := strings.Index(loc, "\r\n")
			if endIndex < 0 {
				continue
			}
			locURL := strings.TrimSpace(loc[0:endIndex])
			var serviceURL, urnDomain string
			serviceURL, urnDomain, err = getServiceURL(locURL)
			if err != nil {
				return
			}
			var ourIP string
			ourIP, err = getOurIP()
			if err != nil {
				return
			}
			nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP, urnDomain: urnDomain}
			return
		}
	}
	err = errors.New("UPnP port discovery failed.")
	return
}

type Envelope struct {
	XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
	Soap    *SoapBody
}
type SoapBody struct {
	XMLName    xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
	ExternalIP *ExternalIPAddressResponse
}

type ExternalIPAddressResponse struct {
	XMLName   xml.Name `xml:"GetExternalIPAddressResponse"`
	IPAddress string   `xml:"NewExternalIPAddress"`
}

type ExternalIPAddress struct {
	XMLName xml.Name `xml:"NewExternalIPAddress"`
	IP      string
}

type Service struct {
	ServiceType string `xml:"serviceType"`
	ControlURL  string `xml:"controlURL"`
}

type DeviceList struct {
	Device []Device `xml:"device"`
}

type ServiceList struct {
	Service []Service `xml:"service"`
}

type Device struct {
	XMLName     xml.Name    `xml:"device"`
	DeviceType  string      `xml:"deviceType"`
	DeviceList  DeviceList  `xml:"deviceList"`
	ServiceList ServiceList `xml:"serviceList"`
}

type Root struct {
	Device Device
}

func getChildDevice(d *Device, deviceType string) *Device {
	dl := d.DeviceList.Device
	for i := 0; i < len(dl); i++ {
		if strings.Index(dl[i].DeviceType, deviceType) >= 0 {
			return &dl[i]
		}
	}
	return nil
}

func getChildService(d *Device, serviceType string) *Service {
	sl := d.ServiceList.Service
	for i := 0; i < len(sl); i++ {
		if strings.Index(sl[i].ServiceType, serviceType) >= 0 {
			return &sl[i]
		}
	}
	return nil
}

func getOurIP() (ip string, err error) {
	hostname, err := os.Hostname()
	if err != nil {
		return
	}
	return net.LookupCNAME(hostname)
}

func getServiceURL(rootURL string) (url, urnDomain string, err error) {
	r, err := http.Get(rootURL)
	if err != nil {
		return
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		err = errors.New(string(r.StatusCode))
		return
	}
	var root Root
	err = xml.NewDecoder(r.Body).Decode(&root)
	if err != nil {
		return
	}
	a := &root.Device
	if strings.Index(a.DeviceType, "InternetGatewayDevice:1") < 0 {
		err = errors.New("No InternetGatewayDevice")
		return
	}
	b := getChildDevice(a, "WANDevice:1")
	if b == nil {
		err = errors.New("No WANDevice")
		return
	}
	c := getChildDevice(b, "WANConnectionDevice:1")
	if c == nil {
		err = errors.New("No WANConnectionDevice")
		return
	}
	d := getChildService(c, "WANIPConnection:1")
	if d == nil {
		// Some routers don't follow the UPnP spec, and put WanIPConnection under WanDevice,
		// instead of under WanConnectionDevice
		d = getChildService(b, "WANIPConnection:1")

		if d == nil {
			err = errors.New("No WANIPConnection")
			return
		}
	}
	// Extract the domain name, which isn't always 'schemas-upnp-org'
	urnDomain = strings.Split(d.ServiceType, ":")[1]
	url = combineURL(rootURL, d.ControlURL)
	return
}

func combineURL(rootURL, subURL string) string {
	protocolEnd := "://"
	protoEndIndex := strings.Index(rootURL, protocolEnd)
	a := rootURL[protoEndIndex+len(protocolEnd):]
	rootIndex := strings.Index(a, "/")
	return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL
}

func soapRequest(url, function, message, domain string) (r *http.Response, err error) {
	fullMessage := "<?xml version=\"1.0\" ?>" +
		"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" +
		"<s:Body>" + message + "</s:Body></s:Envelope>"

	req, err := http.NewRequest("POST", url, strings.NewReader(fullMessage))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "text/xml ; charset=\"utf-8\"")
	req.Header.Set("User-Agent", "Darwin/10.0.0, UPnP/1.0, MiniUPnPc/1.3")
	//req.Header.Set("Transfer-Encoding", "chunked")
	req.Header.Set("SOAPAction", "\"urn:"+domain+":service:WANIPConnection:1#"+function+"\"")
	req.Header.Set("Connection", "Close")
	req.Header.Set("Cache-Control", "no-cache")
	req.Header.Set("Pragma", "no-cache")

	// log.Stderr("soapRequest ", req)

	r, err = http.DefaultClient.Do(req)
	/*if r.Body != nil {
		defer r.Body.Close()
	}*/

	if r.StatusCode >= 400 {
		// log.Stderr(function, r.StatusCode)
		err = errors.New("Error " + strconv.Itoa(r.StatusCode) + " for " + function)
		r = nil
		return
	}
	return
}

type statusInfo struct {
	externalIpAddress string
}

func (n *upnpNAT) getExternalIPAddress() (info statusInfo, err error) {

	message := "<u:GetExternalIPAddress xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
		"</u:GetExternalIPAddress>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "GetExternalIPAddress", message, n.urnDomain)
	if response != nil {
		defer response.Body.Close()
	}
	if err != nil {
		return
	}
	var envelope Envelope
	data, err := ioutil.ReadAll(response.Body)
	reader := bytes.NewReader(data)
	xml.NewDecoder(reader).Decode(&envelope)

	info = statusInfo{envelope.Soap.ExternalIP.IPAddress}

	if err != nil {
		return
	}

	return
}

func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) {
	info, err := n.getExternalIPAddress()
	if err != nil {
		return
	}
	addr = net.ParseIP(info.externalIpAddress)
	return
}

func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) {
	// A single concatenation would break ARM compilation.
	message := "<u:AddPortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort)
	message += "</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>"
	message += "<NewInternalPort>" + strconv.Itoa(internalPort) + "</NewInternalPort>" +
		"<NewInternalClient>" + n.ourIP + "</NewInternalClient>" +
		"<NewEnabled>1</NewEnabled><NewPortMappingDescription>"
	message += description +
		"</NewPortMappingDescription><NewLeaseDuration>" + strconv.Itoa(timeout) +
		"</NewLeaseDuration></u:AddPortMapping>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "AddPortMapping", message, n.urnDomain)
	if response != nil {
		defer response.Body.Close()
	}
	if err != nil {
		return
	}

	// TODO: check response to see if the port was forwarded
	// log.Println(message, response)
	mappedExternalPort = externalPort
	_ = response
	return
}

func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {

	message := "<u:DeletePortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
		"</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
		"</u:DeletePortMapping>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "DeletePortMapping", message, n.urnDomain)
	if response != nil {
		defer response.Body.Close()
	}
	if err != nil {
		return
	}

	// TODO: check response to see if the port was deleted
	// log.Println(message, response)
	_ = response
	return
}
<commit_msg>Improve the way we get the local IP address.<commit_after>package main

// Just enough UPnP to be able to forward ports
//

import (
	"bytes"
	"encoding/xml"
	"errors"
	"io/ioutil"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type upnpNAT struct {
	serviceURL string
	ourIP      string
	urnDomain  string
}

func Discover() (nat NAT, err error) {
	ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900")
	if err != nil {
		return
	}
	conn, err := net.ListenPacket("udp4", ":0")
	if err != nil {
		return
	}
	socket := conn.(*net.UDPConn)
	defer socket.Close()

	err = socket.SetDeadline(time.Now().Add(3 * time.Second))
	if err != nil {
		return
	}

	st := "InternetGatewayDevice:1"

	buf := bytes.NewBufferString(
		"M-SEARCH * HTTP/1.1\r\n" +
			"HOST: 239.255.255.250:1900\r\n" +
			"ST: ssdp:all\r\n" +
			"MAN: \"ssdp:discover\"\r\n" +
			"MX: 2\r\n\r\n")
	message := buf.Bytes()
	answerBytes := make([]byte, 1024)
	for i := 0; i < 3; i++ {
		_, err = socket.WriteToUDP(message, ssdp)
		if err != nil {
			return
		}
		var n int
		n, _, err = socket.ReadFromUDP(answerBytes)
		for {
			n, _, err = socket.ReadFromUDP(answerBytes)
			if err != nil {
				break
			}
			answer := string(answerBytes[0:n])
			if strings.Index(answer, st) < 0 {
				continue
			}
			// HTTP header field names are case-insensitive.
			// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
			locString := "\r\nlocation:"
			answer = strings.ToLower(answer)
			locIndex := strings.Index(answer, locString)
			if locIndex < 0 {
				continue
			}
			loc := answer[locIndex+len(locString):]
			endIndex := strings.Index(loc, "\r\n")
			if endIndex < 0 {
				continue
			}
			locURL := strings.TrimSpace(loc[0:endIndex])
			var serviceURL, urnDomain string
			serviceURL, urnDomain, err = getServiceURL(locURL)
			if err != nil {
				return
			}
			var ourIP net.IP
			ourIP, err = localIPv4()
			if err != nil {
				return
			}
			nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP.String(), urnDomain: urnDomain}
			return
		}
	}
	err = errors.New("UPnP port discovery failed.")
	return
}

type Envelope struct {
	XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
	Soap    *SoapBody
}
type SoapBody struct {
	XMLName    xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
	ExternalIP *ExternalIPAddressResponse
}

type ExternalIPAddressResponse struct {
	XMLName   xml.Name `xml:"GetExternalIPAddressResponse"`
	IPAddress string   `xml:"NewExternalIPAddress"`
}

type ExternalIPAddress struct {
	XMLName xml.Name `xml:"NewExternalIPAddress"`
	IP      string
}

type Service struct {
	ServiceType string `xml:"serviceType"`
	ControlURL  string `xml:"controlURL"`
}

type DeviceList struct {
	Device []Device `xml:"device"`
}

type ServiceList struct {
	Service []Service `xml:"service"`
}

type Device struct {
	XMLName     xml.Name    `xml:"device"`
	DeviceType  string      `xml:"deviceType"`
	DeviceList  DeviceList  `xml:"deviceList"`
	ServiceList ServiceList `xml:"serviceList"`
}

type Root struct {
	Device Device
}

func getChildDevice(d *Device, deviceType string) *Device {
	dl := d.DeviceList.Device
	for i := 0; i < len(dl); i++ {
		if strings.Index(dl[i].DeviceType, deviceType) >= 0 {
			return &dl[i]
		}
	}
	return nil
}

func getChildService(d *Device, serviceType string) *Service {
	sl := d.ServiceList.Service
	for i := 0; i < len(sl); i++ {
		if strings.Index(sl[i].ServiceType, serviceType) >= 0 {
			return &sl[i]
		}
	}
	return nil
}

func localIPv4() (net.IP, error) {
	tt, err := net.Interfaces()
	if err != nil {
		return nil, err
	}
	for _, t := range tt {
		aa, err := t.Addrs()
		if err != nil {
			return nil, err
		}
		for _, a := range aa {
			ipnet, ok := a.(*net.IPNet)
			if !ok {
				continue
			}
			v4 := ipnet.IP.To4()
			if v4 == nil || v4[0] == 127 { // loopback address
				continue
			}
			return v4, nil
		}
	}
	return nil, errors.New("cannot find local IP address")
}

func getServiceURL(rootURL string) (url, urnDomain string, err error) {
	r, err := http.Get(rootURL)
	if err != nil {
		return
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		err = errors.New(string(r.StatusCode))
		return
	}
	var root Root
	err = xml.NewDecoder(r.Body).Decode(&root)
	if err != nil {
		return
	}
	a := &root.Device
	if strings.Index(a.DeviceType, "InternetGatewayDevice:1") < 0 {
		err = errors.New("No InternetGatewayDevice")
		return
	}
	b := getChildDevice(a, "WANDevice:1")
	if b == nil {
		err = errors.New("No WANDevice")
		return
	}
	c := getChildDevice(b, "WANConnectionDevice:1")
	if c == nil {
		err = errors.New("No WANConnectionDevice")
		return
	}
	d := getChildService(c, "WANIPConnection:1")
	if d == nil {
		// Some routers don't follow the UPnP spec, and put WanIPConnection under WanDevice,
		// instead of under WanConnectionDevice
		d = getChildService(b, "WANIPConnection:1")

		if d == nil {
			err = errors.New("No WANIPConnection")
			return
		}
	}
	// Extract the domain name, which isn't always 'schemas-upnp-org'
	urnDomain = strings.Split(d.ServiceType, ":")[1]
	url = combineURL(rootURL, d.ControlURL)
	return
}

func combineURL(rootURL, subURL string) string {
	protocolEnd := "://"
	protoEndIndex := strings.Index(rootURL, protocolEnd)
	a := rootURL[protoEndIndex+len(protocolEnd):]
	rootIndex := strings.Index(a, "/")
	return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL
}

func soapRequest(url, function, message, domain string) (r *http.Response, err error) {
	fullMessage := "<?xml version=\"1.0\" ?>" +
		"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" +
		"<s:Body>" + message + "</s:Body></s:Envelope>"

	req, err := http.NewRequest("POST", url, strings.NewReader(fullMessage))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "text/xml ; charset=\"utf-8\"")
	req.Header.Set("User-Agent", "Darwin/10.0.0, UPnP/1.0, MiniUPnPc/1.3")
	//req.Header.Set("Transfer-Encoding", "chunked")
	req.Header.Set("SOAPAction", "\"urn:"+domain+":service:WANIPConnection:1#"+function+"\"")
	req.Header.Set("Connection", "Close")
	req.Header.Set("Cache-Control", "no-cache")
	req.Header.Set("Pragma", "no-cache")

	// log.Stderr("soapRequest ", req)

	r, err = http.DefaultClient.Do(req)
	/*if r.Body != nil {
		defer r.Body.Close()
	}*/

	if r.StatusCode >= 400 {
		// log.Stderr(function, r.StatusCode)
		err = errors.New("Error " + strconv.Itoa(r.StatusCode) + " for " + function)
		r = nil
		return
	}
	return
}

type statusInfo struct {
	externalIpAddress string
}

func (n *upnpNAT) getExternalIPAddress() (info statusInfo, err error) {

	message := "<u:GetExternalIPAddress xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
		"</u:GetExternalIPAddress>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "GetExternalIPAddress", message, n.urnDomain)
	if response != nil {
		defer response.Body.Close()
	}
	if err != nil {
		return
	}
	var envelope Envelope
	data, err := ioutil.ReadAll(response.Body)
	reader := bytes.NewReader(data)
	xml.NewDecoder(reader).Decode(&envelope)

	info = statusInfo{envelope.Soap.ExternalIP.IPAddress}

	if err != nil {
		return
	}

	return
}

func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) {
	info, err := n.getExternalIPAddress()
	if err != nil {
		return
	}
	addr = net.ParseIP(info.externalIpAddress)
	return
}

func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) {
	// A single concatenation would break ARM compilation.
	message := "<u:AddPortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort)
	message += "</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>"
	message += "<NewInternalPort>" + strconv.Itoa(internalPort) + "</NewInternalPort>" +
		"<NewInternalClient>" + n.ourIP + "</NewInternalClient>" +
		"<NewEnabled>1</NewEnabled><NewPortMappingDescription>"
	message += description +
		"</NewPortMappingDescription><NewLeaseDuration>" + strconv.Itoa(timeout) +
		"</NewLeaseDuration></u:AddPortMapping>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "AddPortMapping", message, n.urnDomain)
	if response != nil {
		defer response.Body.Close()
	}
	if err != nil {
		return
	}

	// TODO: check response to see if the port was forwarded
	// log.Println(message, response)
	mappedExternalPort = externalPort
	_ = response
	return
}

func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {

	message := "<u:DeletePortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
		"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
		"</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
		"</u:DeletePortMapping>"

	var response *http.Response
	response, err = soapRequest(n.serviceURL, "DeletePortMapping", message, n.urnDomain)
	if response != nil {
		defer response.Body.Close()
	}
	if err != nil {
		return
	}

	// TODO: check response to see if the port was deleted
	// log.Println(message, response)
	_ = response
	return
}
<|endoftext|>


<commit_before>package world

import "C"

import (
	"bytes"
	"encoding/binary"
	"unsafe"
)

func CArrayToGoSlice(array *C.double, length C.int) []float64 {
	slice := make([]float64, int(length))
	b := C.GoBytes(unsafe.Pointer(array), C.int(8*length))
	err := binary.Read(bytes.NewReader(b), binary.LittleEndian, slice)
	if err != nil {
		panic(err)
	}
	return slice
}

func Make2DCArrayAlternative(matrix [][]float64) []*C.double {
	alternative := make([]*C.double, len(matrix))
	for i := range alternative {
		// DO NOT free because the source slice is managed by Go
		alternative[i] = (*C.double)(&matrix[i][0])
	}
	return alternative
}
<commit_msg>Remove a magic number<commit_after>package world

import "C"

import (
	"bytes"
	"encoding/binary"
	"unsafe"
)

func CArrayToGoSlice(array *C.double, length C.int) []float64 {
	slice := make([]float64, int(length))
	b := C.GoBytes(unsafe.Pointer(array), C.int(byteSizeOfFloat64*length))
	err := binary.Read(bytes.NewReader(b), binary.LittleEndian, slice)
	if err != nil {
		panic(err)
	}
	return slice
}

func Make2DCArrayAlternative(matrix [][]float64) []*C.double {
	alternative := make([]*C.double, len(matrix))
	for i := range alternative {
		// DO NOT free because the source slice is managed by Go
		alternative[i] = (*C.double)(&matrix[i][0])
	}
	return alternative
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"bytes"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	// ZeroHash is the string of all 00s
	ZeroHash = "0000000000000000000000000000000000000000000000000000000000000000"
)

var (
	RpcConfig = &RPCConfig{}
)

func EntryCost(e *Entry) (int8, error) {
	p, err := e.MarshalBinary()
	if err != nil {
		return 0, err
	}

	// caulculate the length exluding the header size 35 for Milestone 1
	l := len(p) - 35

	if l > 10240 {
		return 10, fmt.Errorf("Entry cannot be larger than 10KB")
	}

	// n is the capacity of the entry payment in KB
	n := int8(l / 1024)

	if r := l % 1024; r > 0 {
		n++
	}

	if n < 1 {
		n = 1
	}
	return n, nil
}

// FactoshiToFactoid converts a uint64 factoshi ammount into a fixed point
// number represented as a string
func FactoshiToFactoid(i uint64) string {
	d := i / 1e8
	r := i % 1e8
	ds := fmt.Sprintf("%d", d)
	rs := fmt.Sprintf("%08d", r)
	rs = strings.TrimRight(rs, "0")
	if len(rs) > 0 {
		ds = ds + "."
	}
	return fmt.Sprintf("%s%s", ds, rs)
}

// FactoidToFactoshi takes a Factoid amount as a string and returns the value in
// factoids
func FactoidToFactoshi(amt string) uint64 {
	valid := regexp.MustCompile(`^([0-9]+)?(\.[0-9]+)?`)
	if !valid.MatchString(amt) {
		return 0
	}

	var total uint64 = 0

	dot := regexp.MustCompile(`\.`)
	pieces := dot.Split(amt, 2)
	whole, _ := strconv.Atoi(pieces[0])
	total += uint64(whole) * 1e8

	if len(pieces) > 1 {
		a := regexp.MustCompile(`(0*)([0-9]+)$`)

		as := a.FindStringSubmatch(pieces[1])
		part, _ := strconv.Atoi(as[0])
		power := len(as[1]) + len(as[2])
		total += uint64(part * 1e8 / int(math.Pow10(power)))
	}

	return total
}

// milliTime returns a 6 byte slice representing the unix time in milliseconds
func milliTime() (r []byte) {
	buf := new(bytes.Buffer)
	t := time.Now().UnixNano()
	m := t / 1e6
	binary.Write(buf, binary.BigEndian, m)
	return buf.Bytes()[2:]
}

// shad Double Sha256 Hash; sha256(sha256(data))
func shad(data []byte) []byte {
	h1 := sha256.Sum256(data)
	h2 := sha256.Sum256(h1[:])
	return h2[:]
}

// sha52 Sha512+Sha256 Hash; sha256(sha512(data)+data)
func sha52(data []byte) []byte {
	h1 := sha512.Sum512(data)
	h2 := sha256.Sum256(append(h1[:], data...))
	return h2[:]
}
<commit_msg>updated factoid amount validation<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"bytes"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/binary"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	// ZeroHash is the string of all 00s
	ZeroHash = "0000000000000000000000000000000000000000000000000000000000000000"
)

var (
	RpcConfig = &RPCConfig{}
)

func EntryCost(e *Entry) (int8, error) {
	p, err := e.MarshalBinary()
	if err != nil {
		return 0, err
	}

	// caulculate the length exluding the header size 35 for Milestone 1
	l := len(p) - 35

	if l > 10240 {
		return 10, fmt.Errorf("Entry cannot be larger than 10KB")
	}

	// n is the capacity of the entry payment in KB
	n := int8(l / 1024)

	if r := l % 1024; r > 0 {
		n++
	}

	if n < 1 {
		n = 1
	}
	return n, nil
}

// FactoshiToFactoid converts a uint64 factoshi ammount into a fixed point
// number represented as a string
func FactoshiToFactoid(i uint64) string {
	d := i / 1e8
	r := i % 1e8
	ds := fmt.Sprintf("%d", d)
	rs := fmt.Sprintf("%08d", r)
	rs = strings.TrimRight(rs, "0")
	if len(rs) > 0 {
		ds = ds + "."
	}
	return fmt.Sprintf("%s%s", ds, rs)
}

// FactoidToFactoshi takes a Factoid amount as a string and returns the value in
// factoids
func FactoidToFactoshi(amt string) uint64 {
	valid := regexp.MustCompile(`^([0-9]+)?(\.[0-9]+)?$`)
	if !valid.MatchString(amt) {
		return 0
	}

	var total uint64 = 0

	dot := regexp.MustCompile(`\.`)
	pieces := dot.Split(amt, 2)
	whole, _ := strconv.Atoi(pieces[0])
	total += uint64(whole) * 1e8

	if len(pieces) > 1 {
		a := regexp.MustCompile(`(0*)([0-9]+)$`)

		as := a.FindStringSubmatch(pieces[1])
		part, _ := strconv.Atoi(as[0])
		power := len(as[1]) + len(as[2])
		total += uint64(part * 1e8 / int(math.Pow10(power)))
	}

	return total
}

// milliTime returns a 6 byte slice representing the unix time in milliseconds
func milliTime() (r []byte) {
	buf := new(bytes.Buffer)
	t := time.Now().UnixNano()
	m := t / 1e6
	binary.Write(buf, binary.BigEndian, m)
	return buf.Bytes()[2:]
}

// shad Double Sha256 Hash; sha256(sha256(data))
func shad(data []byte) []byte {
	h1 := sha256.Sum256(data)
	h2 := sha256.Sum256(h1[:])
	return h2[:]
}

// sha52 Sha512+Sha256 Hash; sha256(sha512(data)+data)
func sha52(data []byte) []byte {
	h1 := sha512.Sum512(data)
	h2 := sha256.Sum256(append(h1[:], data...))
	return h2[:]
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path"
	fpath "path/filepath"
	"strings"
	"time"

	"gopkg.in/urfave/cli.v1"
)

func wikiescape(s string) string {
	return url.QueryEscape(strings.Replace(s, " ", "_", -1))
}

// not needed anymore
func createFile(filename string) *os.File {
	f, err := os.Create(filename)
	if err != nil {
		if os.IsPermission(err) {
			fmt.Println("permission error!")
			return nil
		}

		panic(err.Error())
	}
	return f
}

// a bit of a mess
func removeFile(filename string, log bool) bool {
	if log {
		fmt.Printf("Removing %s...", filename)
	}

	err := os.Remove(filename)
	if err != nil {
		if os.IsNotExist(err) {
			if log {
				fmt.Println(" does not exist!")
			}
			return false
		} else if os.IsPermission(err) {
			if log {
				fmt.Println(" permission error!")
			}
			return false
		}
		fmt.Println("Something happened when deleting your file! :(")
		fmt.Println(err.Error())
		return false
	}
	if log {
		fmt.Println(" success!")
	}
	return true
}

func isDirectory(filepath string) (bool, os.FileInfo, error) {
	fileInfo, err := os.Stat(filepath)
	if err != nil {
		return false, nil, err
	}
	return fileInfo.IsDir(), fileInfo, err
}

func getDirectorySize(filepath string) (float64, error) {
	var size float64
	contents, err := ioutil.ReadDir(filepath)
	if err != nil {
		return -1, err
	}

	for _, file := range contents {
		if file.IsDir() {
			subsize, err := getDirectorySize(fpath.Join(filepath, file.Name()))
			if err != nil {
				return -1, err
			}
			size += subsize
		} else {
			size += float64(file.Size())
		}
	}

	return size, nil
}

func getLastPathComponents(filepath string, depth int) (absPath string) {
	for i := 1; i < depth; i++ {
		absPath = path.Base(filepath) + "\\" + absPath
		filepath = path.Dir(filepath)
	}
	return
}

func getFileErrorReason(err error) string {
	if os.IsNotExist(err) {
		return "doesn't exist"
	} else if os.IsPermission(err) {
		return "permission error"
	} else {
		return err.Error()
	}
}

func checkFilepathArgument(c *cli.Context) (os.FileInfo, string) {
	if len(c.Args()) != 1 {
		cli.ShowSubcommandHelp(c)
		return nil, ""
	}

	filepath := c.Args()[0]
	return getFileOfType(filepath, true, "target")
}

func getFileOfType(filepath string, wantDirectory bool, target string) (os.FileInfo, string) {
	isDirectory, fileInfo, _ := isDirectory(filepath)
	if (fileInfo == nil) || (isDirectory != wantDirectory) {
		if wantDirectory {
			fmt.Println("Error:", target, "is not a directory")
		} else {
			fmt.Println("Error:", target, "is not a file")
		}
		return nil, ""
	}

	return fileInfo, fpath.Clean(filepath)
}

func shouldContinue(c *cli.Context) bool {
	// Ask to continue or just process?
	if c.GlobalBool("force") {
		fmt.Print("\n")
		return true
	}

	fmt.Print("Continue? (y/n): ")
	text := ""
	fmt.Scanln(&text)
	fmt.Print("\n")

	if text != "y" {
		return false
	}
	return true
}

func notifyDeleteMode(c *cli.Context) {
	if c.GlobalBool("delete") {
		fmt.Println("You are running in **DELETE MODE** - data will be permanently lost")
	}
}

// there is a better way to do this
func formatDuration(d time.Duration) (str string) {
	hours := int(d.Hours())
	d -= (time.Duration(hours) * time.Hour)

	minutes := int(d.Minutes())
	d -= (time.Duration(minutes) * time.Minute)

	seconds := int(d.Seconds())

	if hours == 0 {
		str += fmt.Sprintf("%d:%02d", minutes, seconds)
	} else {
		str += fmt.Sprintf("%d:%02d:%02d", hours, minutes, seconds)
	}
	return
}
<commit_msg>Fix location of ffp/md5 files when doing single on the cwd<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path"
	fpath "path/filepath"
	"strings"
	"time"

	"gopkg.in/urfave/cli.v1"
)

func wikiescape(s string) string {
	return url.QueryEscape(strings.Replace(s, " ", "_", -1))
}

// not needed anymore
func createFile(filename string) *os.File {
	f, err := os.Create(filename)
	if err != nil {
		if os.IsPermission(err) {
			fmt.Println("permission error!")
			return nil
		}

		panic(err.Error())
	}
	return f
}

// a bit of a mess
func removeFile(filename string, log bool) bool {
	if log {
		fmt.Printf("Removing %s...", filename)
	}

	err := os.Remove(filename)
	if err != nil {
		if os.IsNotExist(err) {
			if log {
				fmt.Println(" does not exist!")
			}
			return false
		} else if os.IsPermission(err) {
			if log {
				fmt.Println(" permission error!")
			}
			return false
		}
		fmt.Println("Something happened when deleting your file! :(")
		fmt.Println(err.Error())
		return false
	}
	if log {
		fmt.Println(" success!")
	}
	return true
}

func isDirectory(filepath string) (bool, os.FileInfo, error) {
	fileInfo, err := os.Stat(filepath)
	if err != nil {
		return false, nil, err
	}
	return fileInfo.IsDir(), fileInfo, err
}

func getDirectorySize(filepath string) (float64, error) {
	var size float64
	contents, err := ioutil.ReadDir(filepath)
	if err != nil {
		return -1, err
	}

	for _, file := range contents {
		if file.IsDir() {
			subsize, err := getDirectorySize(fpath.Join(filepath, file.Name()))
			if err != nil {
				return -1, err
			}
			size += subsize
		} else {
			size += float64(file.Size())
		}
	}

	return size, nil
}

func getLastPathComponents(filepath string, depth int) (absPath string) {
	for i := 1; i < depth; i++ {
		absPath = path.Base(filepath) + "\\" + absPath
		filepath = path.Dir(filepath)
	}
	return
}

func getFileErrorReason(err error) string {
	if os.IsNotExist(err) {
		return "doesn't exist"
	} else if os.IsPermission(err) {
		return "permission error"
	} else {
		return err.Error()
	}
}

func checkFilepathArgument(c *cli.Context) (os.FileInfo, string) {
	if len(c.Args()) != 1 {
		cli.ShowSubcommandHelp(c)
		return nil, ""
	}

	filepath := c.Args()[0]
	return getFileOfType(filepath, true, "target")
}

func getFileOfType(filepath string, wantDirectory bool, target string) (os.FileInfo, string) {
	filepath, err := fpath.Abs(filepath)
	if err != nil {
		fmt.Println("Could not find absolute directory for path. Error:")
		fmt.Println(err.Error())
		return nil, ""
	}

	isDirectory, fileInfo, _ := isDirectory(filepath)
	if (fileInfo == nil) || (isDirectory != wantDirectory) {
		if wantDirectory {
			fmt.Println("Error:", target, "is not a directory")
		} else {
			fmt.Println("Error:", target, "is not a file")
		}
		return nil, ""
	}

	return fileInfo, filepath
}

func shouldContinue(c *cli.Context) bool {
	// Ask to continue or just process?
	if c.GlobalBool("force") {
		fmt.Print("\n")
		return true
	}

	fmt.Print("Continue? (y/n): ")
	text := ""
	fmt.Scanln(&text)
	fmt.Print("\n")

	if text != "y" {
		return false
	}
	return true
}

func notifyDeleteMode(c *cli.Context) {
	if c.GlobalBool("delete") {
		fmt.Println("You are running in **DELETE MODE** - data will be permanently lost")
	}
}

// there is a better way to do this
func formatDuration(d time.Duration) (str string) {
	hours := int(d.Hours())
	d -= (time.Duration(hours) * time.Hour)

	minutes := int(d.Minutes())
	d -= (time.Duration(minutes) * time.Minute)

	seconds := int(d.Seconds())

	if hours == 0 {
		str += fmt.Sprintf("%d:%02d", minutes, seconds)
	} else {
		str += fmt.Sprintf("%d:%02d:%02d", hours, minutes, seconds)
	}
	return
}
<|endoftext|>