<commit_before>package rrule

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

const (
	// DateTimeFormat is date-time format used in iCalendar (RFC 5545)
	DateTimeFormat = "20060102T150405Z"
	// LocalDateTimeFormat is a date-time format without Z prefix
	LocalDateTimeFormat = "20060102T150405"
	// DateFormat is date format used in iCalendar (RFC 5545)
	DateFormat = "20060102"
)

func timeToStr(time time.Time) string {
	return time.UTC().Format(DateTimeFormat)
}

func timeToDtStartStr(time time.Time) string {
	return fmt.Sprintf("TZID=%s:%s", time.Location().String(), time.Format(LocalDateTimeFormat))
}

func strToTime(str string) (time.Time, error) {
	return strToTimeInLoc(str, time.UTC)
}

func strToTimeInLoc(str string, loc *time.Location) (time.Time, error) {
	if len(str) == len(DateFormat) {
		return time.ParseInLocation(DateFormat, str, loc)
	}
	if len(str) == len(LocalDateTimeFormat) {
		return time.ParseInLocation(LocalDateTimeFormat, str, loc)
	}
	// date-time format carries zone info
	return time.Parse(DateTimeFormat, str)
}

func (f Frequency) String() string {
	return [...]string{
		"YEARLY", "MONTHLY", "WEEKLY", "DAILY",
		"HOURLY", "MINUTELY", "SECONDLY"}[f]
}

func strToFreq(str string) (Frequency, error) {
	freqMap := map[string]Frequency{
		"YEARLY": YEARLY, "MONTHLY": MONTHLY, "WEEKLY": WEEKLY, "DAILY": DAILY,
		"HOURLY": HOURLY, "MINUTELY": MINUTELY, "SECONDLY": SECONDLY,
	}
	result, ok := freqMap[str]
	if !ok {
		return 0, errors.New("undefined frequency: " + str)
	}
	return result, nil
}

func (wday Weekday) String() string {
	s := [...]string{"MO", "TU", "WE", "TH", "FR", "SA", "SU"}[wday.weekday]
	if wday.n == 0 {
		return s
	}
	return fmt.Sprintf("%+d%s", wday.n, s)
}

func strToWeekday(str string) (Weekday, error) {
	if len(str) < 2 {
		return Weekday{}, errors.New("undefined weekday: " + str)
	}
	weekMap := map[string]Weekday{
		"MO": MO, "TU": TU, "WE": WE, "TH": TH,
		"FR": FR, "SA": SA, "SU": SU}
	result, ok := weekMap[str[len(str)-2:]]
	if !ok {
		return Weekday{}, errors.New("undefined weekday: " + str)
	}
	if len(str) > 2 {
		n, e := strconv.Atoi(str[:len(str)-2])
		if e != nil {
			return Weekday{}, e
		}
		result.n = n
	}
	return result, nil
}

func strToWeekdays(value string) ([]Weekday, error) {
	contents := strings.Split(value, ",")
	result := make([]Weekday, len(contents))
	var e error
	for i, s := range contents {
		result[i], e = strToWeekday(s)
		if e != nil {
			return nil, e
		}
	}
	return result, nil
}

func appendIntsOption(options []string, key string, value []int) []string {
	if len(value) == 0 {
		return options
	}
	valueStr := make([]string, len(value))
	for i, v := range value {
		valueStr[i] = strconv.Itoa(v)
	}
	return append(options, fmt.Sprintf("%s=%s", key, strings.Join(valueStr, ",")))
}

func strToInts(value string) ([]int, error) {
	contents := strings.Split(value, ",")
	result := make([]int, len(contents))
	var e error
	for i, s := range contents {
		result[i], e = strconv.Atoi(s)
		if e != nil {
			return nil, e
		}
	}
	return result, nil
}

func (option *ROption) String() string {
	result := []string{fmt.Sprintf("FREQ=%v", option.Freq)}
	if !option.Dtstart.IsZero() && !option.RFC {
		result = append(result, fmt.Sprintf("DTSTART=%s", timeToStr(option.Dtstart)))
	}
	if option.Interval != 0 {
		result = append(result, fmt.Sprintf("INTERVAL=%v", option.Interval))
	}
	if option.Wkst != MO {
		result = append(result, fmt.Sprintf("WKST=%v", option.Wkst))
	}
	if option.Count != 0 {
		result = append(result, fmt.Sprintf("COUNT=%v", option.Count))
	}
	if !option.Until.IsZero() {
		result = append(result, fmt.Sprintf("UNTIL=%v", timeToStr(option.Until)))
	}
	result = appendIntsOption(result, "BYSETPOS", option.Bysetpos)
	result = appendIntsOption(result, "BYMONTH", option.Bymonth)
	result = appendIntsOption(result, "BYMONTHDAY", option.Bymonthday)
	result = appendIntsOption(result, "BYYEARDAY", option.Byyearday)
	result = appendIntsOption(result, "BYWEEKNO", option.Byweekno)
	if len(option.Byweekday) != 0 {
		valueStr := make([]string, len(option.Byweekday))
		for i, wday := range option.Byweekday {
			valueStr[i] = wday.String()
		}
		result = append(result, fmt.Sprintf("BYDAY=%s", strings.Join(valueStr, ",")))
	}
	result = appendIntsOption(result, "BYHOUR", option.Byhour)
	result = appendIntsOption(result, "BYMINUTE", option.Byminute)
	result = appendIntsOption(result, "BYSECOND", option.Bysecond)
	result = appendIntsOption(result, "BYEASTER", option.Byeaster)
	return strings.Join(result, ";")
}

// StrToROption converts string to ROption
func StrToROption(rfcString string) (*ROption, error) {
	return StrToROptionInLocation(rfcString, time.UTC)
}

// StrToROptionInLocation is same as StrToROption but in case local
// time is supplied as date-time/date field (ex. UNTIL), it is parsed
// as a time in a given location (time zone)
func StrToROptionInLocation(rfcString string, loc *time.Location) (*ROption, error) {
	rfcString = strings.TrimSpace(rfcString)
	if len(rfcString) == 0 {
		return nil, errors.New("empty string")
	}
	result := ROption{}
	result.RFC = true
	for _, attr := range strings.Split(rfcString, ";") {
		keyValue := strings.Split(attr, "=")
		if len(keyValue) != 2 {
			return nil, errors.New("wrong format")
		}
		key, value := keyValue[0], keyValue[1]
		if len(value) == 0 {
			return nil, errors.New(key + " option has no value")
		}
		var e error
		switch key {
		case "FREQ":
			result.Freq, e = strToFreq(value)
		case "DTSTART":
			result.RFC = false
			result.Dtstart, e = strToTimeInLoc(value, loc)
		case "INTERVAL":
			result.Interval, e = strconv.Atoi(value)
		case "WKST":
			result.Wkst, e = strToWeekday(value)
		case "COUNT":
			result.Count, e = strconv.Atoi(value)
		case "UNTIL":
			result.Until, e = strToTimeInLoc(value, loc)
		case "BYSETPOS":
			result.Bysetpos, e = strToInts(value)
		case "BYMONTH":
			result.Bymonth, e = strToInts(value)
		case "BYMONTHDAY":
			result.Bymonthday, e = strToInts(value)
		case "BYYEARDAY":
			result.Byyearday, e = strToInts(value)
		case "BYWEEKNO":
			result.Byweekno, e = strToInts(value)
		case "BYDAY":
			result.Byweekday, e = strToWeekdays(value)
		case "BYHOUR":
			result.Byhour, e = strToInts(value)
		case "BYMINUTE":
			result.Byminute, e = strToInts(value)
		case "BYSECOND":
			result.Bysecond, e = strToInts(value)
		case "BYEASTER":
			result.Byeaster, e = strToInts(value)
		default:
			return nil, errors.New("unknown RRULE property: " + key)
		}
		if e != nil {
			return nil, e
		}
	}
	return &result, nil
}

func (r *RRule) String() string {
	return r.OrigOptions.String()
}

func (set *Set) String() string {
	res := set.Recurrence()
	return strings.Join(res, "\n")
}

// StrToRRule converts string to RRule
func StrToRRule(rfcString string) (*RRule, error) {
	option, e := StrToROption(rfcString)
	if e != nil {
		return nil, e
	}
	return NewRRule(*option)
}

// StrToRRuleSet converts string to RRuleSet
func StrToRRuleSet(s string) (*Set, error) {
	s = strings.TrimSpace(s)
	if s == "" {
		return nil, errors.New("empty string")
	}
	ss := strings.Split(s, "\n")
	return StrSliceToRRuleSet(ss)
}

// StrSliceToRRuleSet converts given str slice to RRuleSet
func StrSliceToRRuleSet(ss []string) (*Set, error) {
	set := Set{}

	// According to RFC DTSTART is always the first line.
	firstName, err := processRRuleName(ss[0])
	if err != nil {
		return nil, err
	}

	if firstName == "DTSTART" {
		nameLen := strings.IndexAny(ss[0], ";:")
		dt, err := strToDtStart(ss[0][nameLen+1:])
		if err != nil {
			return nil, fmt.Errorf("strToDtStart failed: %v", err)
		}
		set.DTStart(dt)
		// We've processed the first one
		ss = ss[1:]
	}

	for _, line := range ss {

		name, err := processRRuleName(line)
		if err != nil {
			return nil, err
		}

		nameLen := len(name)

		switch name {
		case "RRULE", "EXRULE":
			r, err := StrToRRule(line[nameLen+1:])

			if err != nil {
				return nil, fmt.Errorf("strToRRule failed: %v", err)
			}

			if !set.GetDTStart().IsZero() {
				opt := r.OrigOptions
				opt.Dtstart = set.GetDTStart()
				r, err = NewRRule(opt)
				if err != nil {
					return nil, fmt.Errorf("could not add dtstart to rule: %v", r)
				}
			}

			if name == "RRULE" {
				set.RRule(r)
			} else {
				set.ExRule(r)
			}
		case "RDATE", "EXDATE":
			ts, err := StrToDates(line[nameLen+1:])
			if err != nil {
				return nil, fmt.Errorf("strToDates failed: %v", err)
			}
			for _, t := range ts {
				if name == "RDATE" {
					set.RDate(t)
				} else {
					set.ExDate(t)
				}
			}
		default:
			return nil, fmt.Errorf("unsupported property: %v", name)
		}
	}

	return &set, nil
}

// StrToDates is intended to parse RDATE and EXDATE properties supporting only
// VALUE=DATE-TIME (DATE and PERIOD are not supported).
// Accepts string with format: "VALUE=DATE-TIME;[TZID=...]:{time},{time},...,{time}"
// or simply "{time},{time},...{time}" and parses it to array of dates
func StrToDates(str string) (ts []time.Time, err error) {
	tmp := strings.Split(str, ":")
	if len(tmp) > 2 {
		return nil, fmt.Errorf("bad format")
	}
	var loc *time.Location
	if len(tmp) == 2 {
		params := strings.Split(tmp[0], ";")
		for _, param := range params {
			if strings.HasPrefix(param, "TZID=") {
				loc, err = parseTZID(param)
			} else if param != "VALUE=DATE-TIME" {
				err = fmt.Errorf("unsupported: %v", param)
			}
			if err != nil {
				return nil, fmt.Errorf("bad dates param: %s", err.Error())
			}
		}
		tmp = tmp[1:]
	}
	for _, datestr := range strings.Split(tmp[0], ",") {
		var t time.Time
		if loc == nil {
			t, err = strToTime(datestr)
		} else {
			t, err = strToTimeInLoc(datestr, loc)
		}
		if err != nil {
			return nil, fmt.Errorf("strToTime failed: %v", err)
		}
		ts = append(ts, t)
	}
	return
}

// processRRuleName processes the name of an RRule off a multi-line RRule set
func processRRuleName(line string) (string, error) {
	line = strings.ToUpper(strings.TrimSpace(line))
	if line == "" {
		return "", fmt.Errorf("bad format %v", line)
	}

	nameLen := strings.IndexAny(line, ";:")
	if nameLen <= 0 {
		return "", fmt.Errorf("bad format %v", line)
	}

	name := line[:nameLen]
	if strings.IndexAny(name, "=") > 0 {
		return "", fmt.Errorf("bad format %v", line)
	}

	return name, nil
}

// strToDtStart accepts string with format: "(TZID={timezone}:)?{time}" and parses it to a date
// may be used to parse DTSTART rules, without the DTSTART; part.
func strToDtStart(str string) (time.Time, error) {
	tmp := strings.Split(str, ":")
	if len(tmp) > 2 || len(tmp) == 0 {
		return time.Time{}, fmt.Errorf("bad format")
	}

	if len(tmp) == 2 {
		// tzid
		loc, err := parseTZID(tmp[0])
		if err != nil {
			return time.Time{}, err
		}
		return strToTimeInLoc(tmp[1], loc)
	}
	// no tzid, len == 1
	return strToTime(tmp[0])
}

func parseTZID(s string) (*time.Location, error) {
	if !strings.HasPrefix(s, "TZID=") || len(s) == len("TZID=") {
		return nil, fmt.Errorf("bad TZID parameter format")
	}
	return time.LoadLocation(s[len("TZID="):])
}
<commit_msg>Small improvement (no need to get name of the rule again)<commit_after>package rrule

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

const (
	// DateTimeFormat is date-time format used in iCalendar (RFC 5545)
	DateTimeFormat = "20060102T150405Z"
	// LocalDateTimeFormat is a date-time format without Z prefix
	LocalDateTimeFormat = "20060102T150405"
	// DateFormat is date format used in iCalendar (RFC 5545)
	DateFormat = "20060102"
)

func timeToStr(time time.Time) string {
	return time.UTC().Format(DateTimeFormat)
}

func timeToDtStartStr(time time.Time) string {
	return fmt.Sprintf("TZID=%s:%s", time.Location().String(), time.Format(LocalDateTimeFormat))
}

func strToTime(str string) (time.Time, error) {
	return strToTimeInLoc(str, time.UTC)
}

func strToTimeInLoc(str string, loc *time.Location) (time.Time, error) {
	if len(str) == len(DateFormat) {
		return time.ParseInLocation(DateFormat, str, loc)
	}
	if len(str) == len(LocalDateTimeFormat) {
		return time.ParseInLocation(LocalDateTimeFormat, str, loc)
	}
	// date-time format carries zone info
	return time.Parse(DateTimeFormat, str)
}

func (f Frequency) String() string {
	return [...]string{
		"YEARLY", "MONTHLY", "WEEKLY", "DAILY",
		"HOURLY", "MINUTELY", "SECONDLY"}[f]
}

func strToFreq(str string) (Frequency, error) {
	freqMap := map[string]Frequency{
		"YEARLY": YEARLY, "MONTHLY": MONTHLY, "WEEKLY": WEEKLY, "DAILY": DAILY,
		"HOURLY": HOURLY, "MINUTELY": MINUTELY, "SECONDLY": SECONDLY,
	}
	result, ok := freqMap[str]
	if !ok {
		return 0, errors.New("undefined frequency: " + str)
	}
	return result, nil
}

func (wday Weekday) String() string {
	s := [...]string{"MO", "TU", "WE", "TH", "FR", "SA", "SU"}[wday.weekday]
	if wday.n == 0 {
		return s
	}
	return fmt.Sprintf("%+d%s", wday.n, s)
}

func strToWeekday(str string) (Weekday, error) {
	if len(str) < 2 {
		return Weekday{}, errors.New("undefined weekday: " + str)
	}
	weekMap := map[string]Weekday{
		"MO": MO, "TU": TU, "WE": WE, "TH": TH,
		"FR": FR, "SA": SA, "SU": SU}
	result, ok := weekMap[str[len(str)-2:]]
	if !ok {
		return Weekday{}, errors.New("undefined weekday: " + str)
	}
	if len(str) > 2 {
		n, e := strconv.Atoi(str[:len(str)-2])
		if e != nil {
			return Weekday{}, e
		}
		result.n = n
	}
	return result, nil
}

func strToWeekdays(value string) ([]Weekday, error) {
	contents := strings.Split(value, ",")
	result := make([]Weekday, len(contents))
	var e error
	for i, s := range contents {
		result[i], e = strToWeekday(s)
		if e != nil {
			return nil, e
		}
	}
	return result, nil
}

func appendIntsOption(options []string, key string, value []int) []string {
	if len(value) == 0 {
		return options
	}
	valueStr := make([]string, len(value))
	for i, v := range value {
		valueStr[i] = strconv.Itoa(v)
	}
	return append(options, fmt.Sprintf("%s=%s", key, strings.Join(valueStr, ",")))
}

func strToInts(value string) ([]int, error) {
	contents := strings.Split(value, ",")
	result := make([]int, len(contents))
	var e error
	for i, s := range contents {
		result[i], e = strconv.Atoi(s)
		if e != nil {
			return nil, e
		}
	}
	return result, nil
}

func (option *ROption) String() string {
	result := []string{fmt.Sprintf("FREQ=%v", option.Freq)}
	if !option.Dtstart.IsZero() && !option.RFC {
		result = append(result, fmt.Sprintf("DTSTART=%s", timeToStr(option.Dtstart)))
	}
	if option.Interval != 0 {
		result = append(result, fmt.Sprintf("INTERVAL=%v", option.Interval))
	}
	if option.Wkst != MO {
		result = append(result, fmt.Sprintf("WKST=%v", option.Wkst))
	}
	if option.Count != 0 {
		result = append(result, fmt.Sprintf("COUNT=%v", option.Count))
	}
	if !option.Until.IsZero() {
		result = append(result, fmt.Sprintf("UNTIL=%v", timeToStr(option.Until)))
	}
	result = appendIntsOption(result, "BYSETPOS", option.Bysetpos)
	result = appendIntsOption(result, "BYMONTH", option.Bymonth)
	result = appendIntsOption(result, "BYMONTHDAY", option.Bymonthday)
	result = appendIntsOption(result, "BYYEARDAY", option.Byyearday)
	result = appendIntsOption(result, "BYWEEKNO", option.Byweekno)
	if len(option.Byweekday) != 0 {
		valueStr := make([]string, len(option.Byweekday))
		for i, wday := range option.Byweekday {
			valueStr[i] = wday.String()
		}
		result = append(result, fmt.Sprintf("BYDAY=%s", strings.Join(valueStr, ",")))
	}
	result = appendIntsOption(result, "BYHOUR", option.Byhour)
	result = appendIntsOption(result, "BYMINUTE", option.Byminute)
	result = appendIntsOption(result, "BYSECOND", option.Bysecond)
	result = appendIntsOption(result, "BYEASTER", option.Byeaster)
	return strings.Join(result, ";")
}

// StrToROption converts string to ROption
func StrToROption(rfcString string) (*ROption, error) {
	return StrToROptionInLocation(rfcString, time.UTC)
}

// StrToROptionInLocation is same as StrToROption but in case local
// time is supplied as date-time/date field (ex. UNTIL), it is parsed
// as a time in a given location (time zone)
func StrToROptionInLocation(rfcString string, loc *time.Location) (*ROption, error) {
	rfcString = strings.TrimSpace(rfcString)
	if len(rfcString) == 0 {
		return nil, errors.New("empty string")
	}
	result := ROption{}
	result.RFC = true
	for _, attr := range strings.Split(rfcString, ";") {
		keyValue := strings.Split(attr, "=")
		if len(keyValue) != 2 {
			return nil, errors.New("wrong format")
		}
		key, value := keyValue[0], keyValue[1]
		if len(value) == 0 {
			return nil, errors.New(key + " option has no value")
		}
		var e error
		switch key {
		case "FREQ":
			result.Freq, e = strToFreq(value)
		case "DTSTART":
			result.RFC = false
			result.Dtstart, e = strToTimeInLoc(value, loc)
		case "INTERVAL":
			result.Interval, e = strconv.Atoi(value)
		case "WKST":
			result.Wkst, e = strToWeekday(value)
		case "COUNT":
			result.Count, e = strconv.Atoi(value)
		case "UNTIL":
			result.Until, e = strToTimeInLoc(value, loc)
		case "BYSETPOS":
			result.Bysetpos, e = strToInts(value)
		case "BYMONTH":
			result.Bymonth, e = strToInts(value)
		case "BYMONTHDAY":
			result.Bymonthday, e = strToInts(value)
		case "BYYEARDAY":
			result.Byyearday, e = strToInts(value)
		case "BYWEEKNO":
			result.Byweekno, e = strToInts(value)
		case "BYDAY":
			result.Byweekday, e = strToWeekdays(value)
		case "BYHOUR":
			result.Byhour, e = strToInts(value)
		case "BYMINUTE":
			result.Byminute, e = strToInts(value)
		case "BYSECOND":
			result.Bysecond, e = strToInts(value)
		case "BYEASTER":
			result.Byeaster, e = strToInts(value)
		default:
			return nil, errors.New("unknown RRULE property: " + key)
		}
		if e != nil {
			return nil, e
		}
	}
	return &result, nil
}

func (r *RRule) String() string {
	return r.OrigOptions.String()
}

func (set *Set) String() string {
	res := set.Recurrence()
	return strings.Join(res, "\n")
}

// StrToRRule converts string to RRule
func StrToRRule(rfcString string) (*RRule, error) {
	option, e := StrToROption(rfcString)
	if e != nil {
		return nil, e
	}
	return NewRRule(*option)
}

// StrToRRuleSet converts string to RRuleSet
func StrToRRuleSet(s string) (*Set, error) {
	s = strings.TrimSpace(s)
	if s == "" {
		return nil, errors.New("empty string")
	}
	ss := strings.Split(s, "\n")
	return StrSliceToRRuleSet(ss)
}

// StrSliceToRRuleSet converts given str slice to RRuleSet
func StrSliceToRRuleSet(ss []string) (*Set, error) {
	set := Set{}

	// According to RFC DTSTART is always the first line.
	firstName, err := processRRuleName(ss[0])
	if err != nil {
		return nil, err
	}

	if firstName == "DTSTART" {
		dt, err := strToDtStart(ss[0][len(firstName)+1:])
		if err != nil {
			return nil, fmt.Errorf("strToDtStart failed: %v", err)
		}
		set.DTStart(dt)
		// We've processed the first one
		ss = ss[1:]
	}

	for _, line := range ss {

		name, err := processRRuleName(line)
		if err != nil {
			return nil, err
		}

		nameLen := len(name)

		switch name {
		case "RRULE", "EXRULE":
			r, err := StrToRRule(line[nameLen+1:])

			if err != nil {
				return nil, fmt.Errorf("strToRRule failed: %v", err)
			}

			if !set.GetDTStart().IsZero() {
				opt := r.OrigOptions
				opt.Dtstart = set.GetDTStart()
				r, err = NewRRule(opt)
				if err != nil {
					return nil, fmt.Errorf("could not add dtstart to rule: %v", r)
				}
			}

			if name == "RRULE" {
				set.RRule(r)
			} else {
				set.ExRule(r)
			}
		case "RDATE", "EXDATE":
			ts, err := StrToDates(line[nameLen+1:])
			if err != nil {
				return nil, fmt.Errorf("strToDates failed: %v", err)
			}
			for _, t := range ts {
				if name == "RDATE" {
					set.RDate(t)
				} else {
					set.ExDate(t)
				}
			}
		default:
			return nil, fmt.Errorf("unsupported property: %v", name)
		}
	}

	return &set, nil
}

// StrToDates is intended to parse RDATE and EXDATE properties supporting only
// VALUE=DATE-TIME (DATE and PERIOD are not supported).
// Accepts string with format: "VALUE=DATE-TIME;[TZID=...]:{time},{time},...,{time}"
// or simply "{time},{time},...{time}" and parses it to array of dates
func StrToDates(str string) (ts []time.Time, err error) {
	tmp := strings.Split(str, ":")
	if len(tmp) > 2 {
		return nil, fmt.Errorf("bad format")
	}
	var loc *time.Location
	if len(tmp) == 2 {
		params := strings.Split(tmp[0], ";")
		for _, param := range params {
			if strings.HasPrefix(param, "TZID=") {
				loc, err = parseTZID(param)
			} else if param != "VALUE=DATE-TIME" {
				err = fmt.Errorf("unsupported: %v", param)
			}
			if err != nil {
				return nil, fmt.Errorf("bad dates param: %s", err.Error())
			}
		}
		tmp = tmp[1:]
	}
	for _, datestr := range strings.Split(tmp[0], ",") {
		var t time.Time
		if loc == nil {
			t, err = strToTime(datestr)
		} else {
			t, err = strToTimeInLoc(datestr, loc)
		}
		if err != nil {
			return nil, fmt.Errorf("strToTime failed: %v", err)
		}
		ts = append(ts, t)
	}
	return
}

// processRRuleName processes the name of an RRule off a multi-line RRule set
func processRRuleName(line string) (string, error) {
	line = strings.ToUpper(strings.TrimSpace(line))
	if line == "" {
		return "", fmt.Errorf("bad format %v", line)
	}

	nameLen := strings.IndexAny(line, ";:")
	if nameLen <= 0 {
		return "", fmt.Errorf("bad format %v", line)
	}

	name := line[:nameLen]
	if strings.IndexAny(name, "=") > 0 {
		return "", fmt.Errorf("bad format %v", line)
	}

	return name, nil
}

// strToDtStart accepts string with format: "(TZID={timezone}:)?{time}" and parses it to a date
// may be used to parse DTSTART rules, without the DTSTART; part.
func strToDtStart(str string) (time.Time, error) {
	tmp := strings.Split(str, ":")
	if len(tmp) > 2 || len(tmp) == 0 {
		return time.Time{}, fmt.Errorf("bad format")
	}

	if len(tmp) == 2 {
		// tzid
		loc, err := parseTZID(tmp[0])
		if err != nil {
			return time.Time{}, err
		}
		return strToTimeInLoc(tmp[1], loc)
	}
	// no tzid, len == 1
	return strToTime(tmp[0])
}

func parseTZID(s string) (*time.Location, error) {
	if !strings.HasPrefix(s, "TZID=") || len(s) == len("TZID=") {
		return nil, fmt.Errorf("bad TZID parameter format")
	}
	return time.LoadLocation(s[len("TZID="):])
}
<|endoftext|>


<commit_before>// what about changing package to svg??
package main

import "fmt"

type SVG struct {
    svg_string string
    width, height int
}

func (s *SVG) set_width(w int) {
    s.width = w
}

func (s *SVG) set_height(h int) {
    s.height = h
}

func (s *SVG) header() string {
    return fmt.Sprintf("<svg xmlns='http://www.w3.org/2000/svg' width='%v' height='%v'>", s.width, s.height)
}

func (s *SVG) footer() string {
    return "</svg>"
}

func (s *SVG) to_s() string {
    return s.header() + s.svg_string + s.footer()
}

func (s *SVG) rect(x, y, w, h int) {
    rect_str := fmt.Sprintf("<rect x='%v' y='%v' width='%v' height='%v' />", x, y, w, h)
    s.svg_string += rect_str
}

func (s *SVG) circle(cx, cy, r int) {
    circle_str := fmt.Sprintf("<circle cx='%v' cy='%v' r='%v' />", cx, cy, r)
    s.svg_string += circle_str
}

func (s *SVG) path(str string) {
    path_str := fmt.Sprintf("<path d='%s' />", str)
    s.svg_string += path_str
}

func (s *SVG) polyline(str string) {
    polyline_str := fmt.Sprintf("<polyline points='%s' />", str)
    s.svg_string += polyline_str
}

func main() {
    svg := new(SVG)

    svg.set_height(100)
    svg.set_width(100)

    svg.rect(1,2,4,5)
    svg.circle(1,2,3)
    svg.path("path_string")
    svg.polyline("polyline_string")

    fmt.Println(svg.to_s())
}
<commit_msg>SVG : implement write_args method<commit_after>// what about changing package to svg??
// initially we are not using double quotes inside strings, think on it.
package main

import "fmt"
import "reflect"

type SVG struct {
    svg_string string
    width, height int
}

func (s *SVG) set_width(w int) {
    s.width = w
}

func (s *SVG) set_height(h int) {
    s.height = h
}

func (s *SVG) header() string {
    return fmt.Sprintf("<svg xmlns='http://www.w3.org/2000/svg' width='%v' height='%v'>", s.width, s.height)
}

func (s *SVG) footer() string {
    return "</svg>"
}

func (s *SVG) to_s() string {
    return s.header() + s.svg_string + s.footer()
}

func (s *SVG) rect(x, y, w, h int) {
    rect_str := fmt.Sprintf("<rect x='%v' y='%v' width='%v' height='%v' />", x, y, w, h)
    s.svg_string += rect_str
}

func (s *SVG) circle(cx, cy, r int) {
    circle_str := fmt.Sprintf("<circle cx='%v' cy='%v' r='%v' />", cx, cy, r)
    s.svg_string += circle_str
}

func (s *SVG) path(str string) {
    path_str := fmt.Sprintf("<path d='%s' />", str)
    s.svg_string += path_str
}

func (s *SVG) polyline(str string) {
    polyline_str := fmt.Sprintf("<polyline points='%s' />", str)
    s.svg_string += polyline_str
}

func (s *SVG) write_args(args map[string]interface{}) string {
    str := ""

    for k, v := range args {
        obj_type := fmt.Sprintf("%s", reflect.TypeOf(v))

        switch obj_type {
            case "string": str += fmt.Sprintf("%s='%s' ", k, v)
            case "int": str += fmt.Sprintf("%s='%v' ", k, v)
            default: {
                str += fmt.Sprintf("%s='", k)
                for K, V := range v.(map[string]string) {
                    str += fmt.Sprintf("%s:%s;", K, V)
                }
                str += "' "
            }
        }
    }

    return str
}

func main() {
    svg := new(SVG)

    svg.set_height(100)
    svg.set_width(100)

/*
    svg.rect(1,2,4,5)
    svg.circle(1,2,3)
    svg.path("path_string")
    svg.polyline("polyline_string")

    fmt.Println(svg.to_s())
*/

    args  := make(map[string]interface{})

    args["first"] = "pravendra"
    args["last"] = "singh"
    args["age"] = 13

    args["things"] = map[string]string{"alpha": "beta"}

    fmt.Println(svg.write_args(args))
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"github.com/cayleygraph/cayley"
	"github.com/cayleygraph/cayley/graph"
	_ "github.com/aselus-hub/cayley/graph/sql"
	"github.com/cayleygraph/cayley/quad"
	"github.com/satori/go.uuid"
	"log"
	"math/rand"
	"sync"
	"time"
)

const insecureCdbPath = "postgresql://root@127.0.0.1:26257/"

const runTime = 1*time.Second
const batchSize = 15

type node struct {
	parent string
	child  string
	id     string
}

func generateAndSendAGraph(wg *sync.WaitGroup, sumChan chan uint64, quit chan struct{}) {
	defer wg.Done()
	var numProccessed uint64
	if store, err := InitCayley(insecureCdbPath + "cayley?sslmode=disable"); err != nil {
		fmt.Printf("Could not initialize cayley, %s\n", err.Error())
		return
	} else {
		defer store.Close()
		tx := cayley.NewTransaction()
		for {
			select {
			case <-quit:
				tx = commitTx(store, tx, true)
				sumChan <- numProccessed
				return
			default:
				nodes := generateGraph(store)
				for _, n := range nodes {
					n = n
					addNquadsForNode(n, tx)
					tx = commitTx(store, tx, false)
					numProccessed++
				}
			}
		}
	}
}

func generateGraph(store *cayley.Handle) []node {
	// create a lineage for connecting A through link to B, etc.
	numItems := 2 + rand.Intn(10)
	// permutations := rand.Perm(numItems)
	// create a list of nodes, with number of true items and number of links.
	nodes := make([]node, numItems, numItems)
	currentUUID := ""
	for index := range nodes {
		newUuid := uuid.NewV4().String()
		nodes[index] = node{parent: currentUUID, id: uuid.NewV4().String(), child: currentUUID}
		currentUUID = newUuid
	}
	return nodes
}

func addNquadsForNode(n node, tx *graph.Transaction)  {
	if n.parent != "" {
		tx.AddQuad(quad.Make(n.parent, "related_through", n.id, nil))
	}

	if n.child != "" {
		tx.AddQuad(quad.Make(n.id, "related_through", n.child, nil))
	}
}

func commitTx(store *cayley.Handle, tx *graph.Transaction, force bool) *graph.Transaction {
	if len(tx.Deltas) > batchSize || force {
		err := store.ApplyTransaction(tx)
		if err != nil {
			panic(err.Error())
		}
		return cayley.NewTransaction()
	} else {
		return tx
	}
}

const NumRoutines = 4

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	SetupCayleyInCdb()
	termination := sync.WaitGroup{}
	termination.Add(NumRoutines)
	var trueEnd time.Duration
	var totalSum uint64
	processedNodes := make(chan uint64, NumRoutines)
	quit := make(chan struct{})

	start := time.Now()
	for i := 0; i < NumRoutines; i++ {
		go generateAndSendAGraph(&termination, processedNodes, quit)
	}
	for time.Since(start) < runTime {
		time.Sleep(time.Millisecond * 10)
	}
	close(quit)
	termination.Wait()
	trueEnd = time.Since(start)

outerFor:
	for {
		select {
		case subSum := <-processedNodes:
			totalSum += subSum
		default:
			break outerFor
		}
	}

	fmt.Printf("time elapsed: %v\n", trueEnd)
	fmt.Printf("total processed: %v\n", totalSum)
	fmt.Printf("sets/second: %v\n", float64(totalSum) / trueEnd.Seconds())
}

func SetupCayleyInCdb() {
	db, err := sql.Open("postgres", insecureCdbPath+"system?sslmode=disable")
	if err != nil {
		log.Fatalf("Unable to initialize cockroach: %s", err.Error())
	}
	defer db.Close()
	_, err = db.Exec("CREATE DATABASE IF NOT EXISTS cayley")
	if err != nil {
		log.Fatalf("Unable to initialize cockroach: %s", err.Error())
	}

	if err = graph.InitQuadStore("sql", insecureCdbPath+"cayley?sslmode=disable", graph.Options{"flavor": "cockroach"}); err != nil {
		if err != graph.ErrDatabaseExists {
			panic(err.Error())
		}
	}

}

func InitCayley(pathToCockroachDB string) (store *cayley.Handle, err error) {
	store, err = cayley.NewGraph("sql", pathToCockroachDB, graph.Options{"flavor": "cockroach"})
	if err != nil {
		return
	}
	return
}
<commit_msg>updated to have regular reporting for longer runs updated execution based opn adivce from @petermattis<commit_after>package main

import (
	"database/sql"
	"fmt"
	"github.com/cayleygraph/cayley"
	"github.com/cayleygraph/cayley/graph"
	_ "github.com/aselus-hub/cayley/graph/sql"
	"github.com/cayleygraph/cayley/quad"
	"github.com/satori/go.uuid"
	"log"
	"math/rand"
	"sync"
	"time"
)

const insecureCdbPath = "postgresql://root@127.0.0.1:26257/"

const (
runTime = 1*time.Second
reportEvery = 5*time.Second
batchSize = 15
NumRoutines = 4
)

type node struct {
	parent string
	child  string
	id     string
}

func generateAndSendAGraph(wg *sync.WaitGroup, sumChan chan uint64, quit chan struct{}) {
	defer wg.Done()
	var numProccessed uint64
	lastReport := time.Now()
	if store, err := InitCayley(insecureCdbPath + "cayley?sslmode=disable&binary_parameters"); err != nil {
		fmt.Printf("Could not initialize cayley, %s\n", err.Error())
		return
	} else {
		defer store.Close()
		tx := cayley.NewTransaction()
		for {
			select {
			case <-quit:
				tx = commitTx(store, tx, true)
				sumChan <- numProccessed
				return
			default:
				if time.Since(lastReport) > reportEvery {
					sumChan <- numProccessed
					numProccessed = 0
					lastReport = time.Now()
				}
				nodes := generateGraph(store)
				for _, n := range nodes {
					n = n
					addNquadsForNode(n, tx)
					tx = commitTx(store, tx, false)
					numProccessed++
				}
			}
		}
	}
}

func generateGraph(store *cayley.Handle) []node {
	// create a lineage for connecting A through link to B, etc.
	numItems := 2 + rand.Intn(10)
	// permutations := rand.Perm(numItems)
	// create a list of nodes, with number of true items and number of links.
	nodes := make([]node, numItems, numItems)
	currentUUID := ""
	for index := range nodes {
		newUuid := uuid.NewV4().String()
		nodes[index] = node{parent: currentUUID, id: uuid.NewV4().String(), child: currentUUID}
		currentUUID = newUuid
	}
	return nodes
}

func addNquadsForNode(n node, tx *graph.Transaction)  {
	if n.parent != "" {
		tx.AddQuad(quad.Make(n.parent, "related_through", n.id, nil))
	}

	if n.child != "" {
		tx.AddQuad(quad.Make(n.id, "related_through", n.child, nil))
	}
}

func commitTx(store *cayley.Handle, tx *graph.Transaction, force bool) *graph.Transaction {
	if len(tx.Deltas) > batchSize || force {
		err := store.ApplyTransaction(tx)
		if err != nil {
			panic(err.Error())
		}
		return cayley.NewTransaction()
	} else {
		return tx
	}
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	SetupCayleyInCdb()
	termination := sync.WaitGroup{}
	termination.Add(NumRoutines)
	var trueEnd time.Duration
	var totalSum uint64
	processedNodes := make(chan uint64, NumRoutines)
	quit := make(chan struct{})

	start := time.Now()
	for i := 0; i < NumRoutines; i++ {
		go generateAndSendAGraph(&termination, processedNodes, quit)
	}

	var curSum uint64
	var numSum int

	lastUpdate := time.Now()
	for {
		select {
		case <-time.After(time.Second):
		case subSum := <-processedNodes:
			curSum += subSum
			fmt.Printf("node sum: %d\n", subSum)
			numSum++
			if numSum == NumRoutines {
				fmt.Printf("\trunning sum: %d [%v/sec]\n", curSum, float64(curSum) / time.Since(lastUpdate).Seconds())
				lastUpdate = time.Now()
				totalSum += curSum
				curSum = 0
				numSum = 0
			}
		}
		if time.Since(start) > runTime {
			close(quit)
			break
		}

	}

	termination.Wait()
	trueEnd = time.Since(start)

outerFor:
	for {
		select {
		case subSum := <-processedNodes:
			totalSum += subSum
		default:
			break outerFor
		}
	}

	fmt.Printf("time elapsed: %v\n", trueEnd)
	fmt.Printf("total processed: %v\n", totalSum+curSum)
	fmt.Printf("sets/second: %v\n", float64(totalSum) / trueEnd.Seconds())
}

func SetupCayleyInCdb() {
	db, err := sql.Open("postgres", insecureCdbPath+"system?sslmode=disable")
	if err != nil {
		log.Fatalf("Unable to initialize cockroach: %s", err.Error())
	}
	defer db.Close()
	_, err = db.Exec("CREATE DATABASE IF NOT EXISTS cayley")
	if err != nil {
		log.Fatalf("Unable to initialize cockroach: %s", err.Error())
	}

	if err = graph.InitQuadStore("sql", insecureCdbPath+"cayley?sslmode=disable", graph.Options{"flavor": "cockroach"}); err != nil {
		if err != graph.ErrDatabaseExists {
			panic(err.Error())
		}
	}

}

func InitCayley(pathToCockroachDB string) (store *cayley.Handle, err error) {
	store, err = cayley.NewGraph("sql", pathToCockroachDB, graph.Options{"flavor": "cockroach"})
	if err != nil {
		return
	}
	return
}
<|endoftext|>


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

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

// Unix environment variables.

package unix

import "sync"

var (
	// envOnce guards initialization by copyenv, which populates env.
	envOnce sync.Once

	// envLock guards env and envs.
	envLock sync.RWMutex

	// env maps from an environment variable to its first occurrence in envs.
	env map[string]int

	// envs is provided by the runtime. elements are expected to be
	// of the form "key=value".
	envs []string
)

// setenv_c is provided by the runtime, but is a no-op if cgo isn't
// loaded.
func setenv_c(k, v string)

func copyenv() {
	env = make(map[string]int)
	for i, s := range envs {
		for j := 0; j < len(s); j++ {
			if s[j] == '=' {
				key := s[:j]
				if _, ok := env[key]; !ok {
					env[key] = i
				}
				break
			}
		}
	}
}

func Getenv(key string) (value string, found bool) {
	envOnce.Do(copyenv)
	if len(key) == 0 {
		return "", false
	}

	envLock.RLock()
	defer envLock.RUnlock()

	i, ok := env[key]
	if !ok {
		return "", false
	}
	s := envs[i]
	for i := 0; i < len(s); i++ {
		if s[i] == '=' {
			return s[i+1:], true
		}
	}
	return "", false
}

func Setenv(key, value string) error {
	envOnce.Do(copyenv)
	if len(key) == 0 {
		return EINVAL
	}
	for i := 0; i < len(key); i++ {
		if key[i] == '=' || key[i] == 0 {
			return EINVAL
		}
	}
	for i := 0; i < len(value); i++ {
		if value[i] == 0 {
			return EINVAL
		}
	}

	envLock.Lock()
	defer envLock.Unlock()

	i, ok := env[key]
	kv := key + "=" + value
	if ok {
		envs[i] = kv
	} else {
		i = len(envs)
		envs = append(envs, kv)
	}
	env[key] = i
	setenv_c(key, value)
	return nil
}

func Clearenv() {
	envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv

	envLock.Lock()
	defer envLock.Unlock()

	env = make(map[string]int)
	envs = []string{}
	// TODO(bradfitz): pass through to C
}

func Environ() []string {
	envOnce.Do(copyenv)
	envLock.RLock()
	defer envLock.RUnlock()
	a := make([]string, len(envs))
	copy(a, envs)
	return a
}
<commit_msg>go.sys/unix: implement the environment functions by wrapping syscall The environment is global state that is owned by the standard syscall package. With this change, go test passes on darwin in the unix directory.<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

// Unix environment variables.

package unix

import "syscall"

func Getenv(key string) (value string, found bool) {
	return syscall.Getenv(key)
}

func Setenv(key, value string) error {
	return syscall.Setenv(key, value)
}

func Clearenv() {
	syscall.Clearenv()
}

func Environ() []string {
	return syscall.Environ()
}
<|endoftext|>


<commit_before>package model

import (
	"database/sql/driver"
	"encoding/json"
	"strings"
	"time"
)

type Tags []string

type HatenaBookmarkTime struct {
	*time.Time
}

// ref: https://dev.classmethod.jp/go/struct-json/
func (hbt *HatenaBookmarkTime) UnmarshalJSON(data []byte) error {
	t, err := time.Parse("\"2006/01/02 15:04\"", string(data))
	*hbt = HatenaBookmarkTime{&t}
	return err
}

func (hbt HatenaBookmarkTime) MarshalJSON() ([]byte, error) {
	return json.Marshal(hbt.Format("2006/01/02 15:04"))
}

// ref: https://qiita.com/roothybrid7/items/52623bedb45ff0c26a8a
func (hbt *HatenaBookmarkTime) Scan(value interface{}) error {
	v := value.(time.Time)
	hbt.Time = &v
	return nil
}

func (hbt HatenaBookmarkTime) Value() (driver.Value, error) {
	return *hbt.Time, nil
}

func (tags *Tags) Scan(value interface{}) error {
	v := strings.Split(value.(string), "\t")
	*tags = append(*tags, v...)
	return nil
}

func (tags Tags) Value() (driver.Value, error) {
	return strings.Join(tags, "\t"), nil
}

type Bookmark struct {
	HatenaBookmarkId int                `db:"hatena_bookmark_id"`
	Timestamp        HatenaBookmarkTime `json:"timestamp" db:"timestamp"`
	User             string             `json:"user" db:"user"`
	Tags             Tags               `json:"tags" db:"tags"`
	Comment          string             `json:"comment" db:"comment"`
}

type HatenaBookmark struct {
	Id         int         `db:"id"`
	ExampleId  int         `db:"example_id"`
	Title      string      `json:"title" db:"title"`
	Bookmarks  []*Bookmark `json:"bookmarks"`
	Screenshot string      `json:"screenshot" db:"screenshot"`
	EntryUrl   string      `json:"entry_url" db:"entry_url"`
	Count      int         `json:"count" db:"count"`
	Url        string      `json:"url" db:"url"`
	EId        string      `json:"eid" db:"eid"`
}

func (bookmarks *HatenaBookmark) MarshalBinary() ([]byte, error) {
	json, err := json.Marshal(bookmarks)
	if err != nil {
		return nil, err
	}
	return []byte(json), nil
}

func (bookmarks *HatenaBookmark) UnmarshalBinary(data []byte) error {
	err := json.Unmarshal(data, bookmarks)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>空文字対策<commit_after>package model

import (
	"database/sql/driver"
	"encoding/json"
	"strings"
	"time"
)

type Tags []string

type HatenaBookmarkTime struct {
	*time.Time
}

// ref: https://dev.classmethod.jp/go/struct-json/
func (hbt *HatenaBookmarkTime) UnmarshalJSON(data []byte) error {
	t, err := time.Parse("\"2006/01/02 15:04\"", string(data))
	*hbt = HatenaBookmarkTime{&t}
	return err
}

func (hbt HatenaBookmarkTime) MarshalJSON() ([]byte, error) {
	return json.Marshal(hbt.Format("2006/01/02 15:04"))
}

// ref: https://qiita.com/roothybrid7/items/52623bedb45ff0c26a8a
func (hbt *HatenaBookmarkTime) Scan(value interface{}) error {
	v := value.(time.Time)
	hbt.Time = &v
	return nil
}

func (hbt HatenaBookmarkTime) Value() (driver.Value, error) {
	return *hbt.Time, nil
}

func (tags *Tags) Scan(value interface{}) error {
	s := value.(string)
	if s == "" {
		return nil
	}
	v := strings.Split(s, "\t")
	*tags = append(*tags, v...)
	return nil
}

func (tags Tags) Value() (driver.Value, error) {
	return strings.Join(tags, "\t"), nil
}

type Bookmark struct {
	HatenaBookmarkId int                `db:"hatena_bookmark_id"`
	Timestamp        HatenaBookmarkTime `json:"timestamp" db:"timestamp"`
	User             string             `json:"user" db:"user"`
	Tags             Tags               `json:"tags" db:"tags"`
	Comment          string             `json:"comment" db:"comment"`
}

type HatenaBookmark struct {
	Id         int         `db:"id"`
	ExampleId  int         `db:"example_id"`
	Title      string      `json:"title" db:"title"`
	Bookmarks  []*Bookmark `json:"bookmarks"`
	Screenshot string      `json:"screenshot" db:"screenshot"`
	EntryUrl   string      `json:"entry_url" db:"entry_url"`
	Count      int         `json:"count" db:"count"`
	Url        string      `json:"url" db:"url"`
	EId        string      `json:"eid" db:"eid"`
}

func (bookmarks *HatenaBookmark) MarshalBinary() ([]byte, error) {
	json, err := json.Marshal(bookmarks)
	if err != nil {
		return nil, err
	}
	return []byte(json), nil
}

func (bookmarks *HatenaBookmark) UnmarshalBinary(data []byte) error {
	err := json.Unmarshal(data, bookmarks)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package onekey

import (
	"testing"
	"github.com/stretchr/testify/assert"
)

func TestGenerate(t *testing.T) {
	chain := Keychain()
	_ = chain.generate()
	assert.Equal(t, chain.size(), 1, "KeyChain should properly generate keys")
}

func TestConsume(t *testing.T) {
	chain := Keychain()
	key := chain.generate()
	ok := chain.consume(key)
	assert.Equal(t, ok, true, "KeyChain should be able to consume generated keys")
	assert.Equal(t, chain.size(), 0, "KeyChain should properly remove consumed keys")
}<commit_msg>tests done<commit_after>package onekey

import (
	"testing"
	"github.com/stretchr/testify/assert"
)

func TestSize(t *testing.T) {
	chain := Keychain()
	for i := 0; i<33; i++ {
		chain.generate()
	}
	assert.Equal(t, chain.size(), 33, "KeyChain should have the right size")
}

func TestGenerate(t *testing.T) {
	chain := Keychain()
	_ = chain.generate()
	assert.Equal(t, chain.size(), 1, "KeyChain should properly generate keys")
}

func TestConsume(t *testing.T) {
	chain := Keychain()
	key := chain.generate()
	ok := chain.consume(key)
	assert.Equal(t, ok, true, "KeyChain should be able to consume generated keys")
	assert.Equal(t, chain.size(), 0, "KeyChain should properly remove consumed keys")
}<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"

	"github.com/voxelbrain/goptions"
)

var (
	options = struct {
		Server string        `goptions:"-s, --server, description='Pixelpixel server to push to'"`
		Help   goptions.Help `goptions:"-h, --help, description='Show this help'"`
	}{
		Server: "localhost:8080",
	}
)

const (
	keyFile = ".key"
)

func main() {
	goptions.ParseAndFail(&options)

	key := loadKey()

	fs, err := createFs(".")
	if err != nil {
		log.Fatalf("Could not create filesystem: %s", err)
	}

	var req *http.Request
	if key == "" {
		url := "http://" + path.Join(options.Server, "pixels") + "/"
		req, _ = http.NewRequest("POST", url, bytes.NewReader(fs))
	} else {
		url := "http://" + path.Join(options.Server, "pixels", key)
		req, _ = http.NewRequest("PUT", url, bytes.NewReader(fs))
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalf("Could not upload filesystem: %s", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 300 {
		log.Fatalf("An error occured! Status code: %d", resp.StatusCode)
	}

	buf := &bytes.Buffer{}
	io.Copy(buf, resp.Body)
	if key == "" {
		f, err := os.Create(keyFile)
		if err != nil {
			log.Fatalf("Could not save key file (key=%s): %s", buf.String(), err)
		}
		defer f.Close()
		f.Write(buf.Bytes())
	}
}

func createFs(path string) ([]byte, error) {
	buf := &bytes.Buffer{}
	fs := tar.NewWriter(buf)
	err := filepath.Walk(path, func(path string, info os.FileInfo, _ error) error {
		if path == "." {
			return nil
		}
		log.Printf("Adding %s", path)
		if info.IsDir() {
			err := fs.WriteHeader(&tar.Header{
				Name:     info.Name(),
				Typeflag: tar.TypeDir,
			})
			return err
		}

		err := fs.WriteHeader(&tar.Header{
			Name:     info.Name(),
			Mode:     int64(info.Mode()),
			Size:     info.Size(),
			Typeflag: tar.TypeReg,
		})
		if err != nil {
			log.Printf("Could not start next file: %s", err)
			return err
		}
		f, err := os.Open(path)
		if err != nil {
			log.Printf("Could not read %s: %s", path, err)
			return err
		}
		defer f.Close()
		io.Copy(fs, f)
		return nil
	})
	fs.Flush()
	fs.Close()
	return buf.Bytes(), err
}

func loadKey() string {
	f, err := os.Open(keyFile)
	if err != nil {
		return ""
	}
	defer f.Close()
	key, err := ioutil.ReadAll(f)
	if err != nil {
		return ""
	}
	return string(key)
}
<commit_msg>Skip dot files<commit_after>package main

import (
	"archive/tar"
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/voxelbrain/goptions"
)

var (
	options = struct {
		Server string        `goptions:"-s, --server, description='Pixelpixel server to push to'"`
		Help   goptions.Help `goptions:"-h, --help, description='Show this help'"`
	}{
		Server: "localhost:8080",
	}
)

const (
	keyFile = ".key"
)

func main() {
	goptions.ParseAndFail(&options)

	key := loadKey()

	fs, err := createFs(".")
	if err != nil {
		log.Fatalf("Could not create filesystem: %s", err)
	}

	var req *http.Request
	if key == "" {
		url := "http://" + path.Join(options.Server, "pixels") + "/"
		req, _ = http.NewRequest("POST", url, bytes.NewReader(fs))
	} else {
		url := "http://" + path.Join(options.Server, "pixels", key)
		req, _ = http.NewRequest("PUT", url, bytes.NewReader(fs))
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalf("Could not upload filesystem: %s", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 300 {
		log.Fatalf("An error occured! Status code: %d", resp.StatusCode)
	}

	buf := &bytes.Buffer{}
	io.Copy(buf, resp.Body)
	if key == "" {
		f, err := os.Create(keyFile)
		if err != nil {
			log.Fatalf("Could not save key file (key=%s): %s", buf.String(), err)
		}
		defer f.Close()
		f.Write(buf.Bytes())
	}
}

func createFs(path string) ([]byte, error) {
	buf := &bytes.Buffer{}
	fs := tar.NewWriter(buf)
	err := filepath.Walk(path, func(path string, info os.FileInfo, _ error) error {
		if strings.HasPrefix(path, ".") {
			return nil
		}
		log.Printf("Adding %s", path)
		if info.IsDir() {
			err := fs.WriteHeader(&tar.Header{
				Name:     info.Name(),
				Typeflag: tar.TypeDir,
			})
			return err
		}

		err := fs.WriteHeader(&tar.Header{
			Name:     info.Name(),
			Mode:     int64(info.Mode()),
			Size:     info.Size(),
			Typeflag: tar.TypeReg,
		})
		if err != nil {
			log.Printf("Could not start next file: %s", err)
			return err
		}
		f, err := os.Open(path)
		if err != nil {
			log.Printf("Could not read %s: %s", path, err)
			return err
		}
		defer f.Close()
		io.Copy(fs, f)
		return nil
	})
	fs.Flush()
	fs.Close()
	return buf.Bytes(), err
}

func loadKey() string {
	f, err := os.Open(keyFile)
	if err != nil {
		return ""
	}
	defer f.Close()
	key, err := ioutil.ReadAll(f)
	if err != nil {
		return ""
	}
	return string(key)
}
<|endoftext|>


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

package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"time"

	"github.com/Jigsaw-Code/outline-ss-server/metrics"
	onet "github.com/Jigsaw-Code/outline-ss-server/net"

	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
	"github.com/shadowsocks/go-shadowsocks2/socks"
)

func findAccessKey(clientConn onet.DuplexConn, cipherList map[string]shadowaead.Cipher) (string, onet.DuplexConn, error) {
	if len(cipherList) == 0 {
		return "", nil, errors.New("Empty cipher list")
	} else if len(cipherList) == 1 {
		for id, cipher := range cipherList {
			reader := shadowaead.NewShadowsocksReader(clientConn, cipher)
			writer := shadowaead.NewShadowsocksWriter(clientConn, cipher)
			return id, onet.WrapConn(clientConn, reader, writer), nil
		}
	}
	// buffer saves the bytes read from shadowConn, in order to allow for replays.
	var buffer bytes.Buffer
	// Try each cipher until we find one that authenticates successfully.
	// This assumes that all ciphers are AEAD.
	// TODO: Reorder list to try previously successful ciphers first for the client IP.
	// TODO: Ban and log client IPs with too many failures too quick to protect against DoS.
	for id, cipher := range cipherList {
		log.Printf("Trying key %v", id)
		// tmpReader reuses the bytes read so far, falling back to shadowConn if it needs more
		// bytes. All bytes read from shadowConn are saved in buffer.
		tmpReader := io.MultiReader(bytes.NewReader(buffer.Bytes()), io.TeeReader(clientConn, &buffer))
		// Override the Reader of shadowConn so we can reset it for each cipher test.
		cipherReader := shadowaead.NewShadowsocksReader(tmpReader, cipher)
		// Read should read just enough data to authenticate the payload size.
		_, err := cipherReader.Read(make([]byte, 0))
		if err != nil {
			log.Printf("Failed key %v: %v", id, err)
			continue
		}
		log.Printf("Selected key %v", id)
		// We don't need to replay the bytes anymore, but we don't want to drop those
		// read so far.
		ssr := shadowaead.NewShadowsocksReader(io.MultiReader(&buffer, clientConn), cipher)
		ssw := shadowaead.NewShadowsocksWriter(clientConn, cipher)
		return id, onet.WrapConn(clientConn, ssr, ssw).(onet.DuplexConn), nil
	}
	return "", nil, fmt.Errorf("could not find valid key")
}

func runTCPService(listener *net.TCPListener, ciphers *map[string]shadowaead.Cipher, m metrics.ShadowsocksMetrics) {
	for {
		var clientConn onet.DuplexConn
		clientConn, err := listener.AcceptTCP()
		if err != nil {
			log.Printf("failed to accept: %v", err)
			continue
		}
		m.AddOpenTCPConnection()

		go func() (connError *connectionError) {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("ERROR Panic in TCP handler: %v", r)
				}
			}()
			connStart := time.Now()
			clientConn.(*net.TCPConn).SetKeepAlive(true)
			keyID := ""
			var proxyMetrics metrics.ProxyMetrics
			clientConn = metrics.MeasureConn(clientConn, &proxyMetrics.ProxyClient, &proxyMetrics.ClientProxy)
			defer func() {
				connEnd := time.Now()
				connDuration := connEnd.Sub(connStart)
				clientConn.Close()
				status := "OK"
				if connError != nil {
					log.Printf("ERROR [TCP] %v: %v", connError.message, connError.cause)
					status = connError.status
				}
				log.Printf("Done with status %v, duration %v", status, connDuration)
				m.AddClosedTCPConnection(keyID, status, proxyMetrics, connDuration)
			}()

			keyID, clientConn, err := findAccessKey(clientConn, *ciphers)
			if err != nil {
				return &connectionError{"ERR_CIPHER", "Failed to find a valid cipher", err}
			}

			tgtAddr, err := socks.ReadAddr(clientConn)
			if err != nil {
				return &connectionError{"ERR_READ_ADDRESS", "Failed to get target address", err}
			}
			tgtTCPAddr, err := net.ResolveTCPAddr("tcp", tgtAddr.String())
			if err != nil {
				return &connectionError{"ERR_RESOLVE_ADDRESS", fmt.Sprintf("Failed to resolve target address %v", tgtAddr.String()), err}
			}
			if !tgtTCPAddr.IP.IsGlobalUnicast() {
				return &connectionError{"ERR_ADDRESS_INVALID", fmt.Sprintf("Target address is not global unicast: %v", tgtAddr.String()), err}
			}

			tgtTCPConn, err := net.DialTCP("tcp", nil, tgtTCPAddr)
			if err != nil {
				return &connectionError{"ERR_CONNECT", "Failed to connect to target", err}
			}
			defer tgtTCPConn.Close()
			tgtTCPConn.SetKeepAlive(true)
			tgtConn := metrics.MeasureConn(tgtTCPConn, &proxyMetrics.ProxyTarget, &proxyMetrics.TargetProxy)

			// TODO: Disable logging in production. This is sensitive.
			log.Printf("proxy %s <-> %s", clientConn.RemoteAddr(), tgtConn)
			_, _, err = onet.Relay(clientConn, tgtConn)
			if err != nil {
				return &connectionError{"ERR_RELAY", "Failed to relay traffic", err}
			}
			return nil
		}()
	}
}
<commit_msg>Print address<commit_after>// Copyright 2018 Jigsaw Operations LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"time"

	"github.com/Jigsaw-Code/outline-ss-server/metrics"
	onet "github.com/Jigsaw-Code/outline-ss-server/net"

	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
	"github.com/shadowsocks/go-shadowsocks2/socks"
)

func findAccessKey(clientConn onet.DuplexConn, cipherList map[string]shadowaead.Cipher) (string, onet.DuplexConn, error) {
	if len(cipherList) == 0 {
		return "", nil, errors.New("Empty cipher list")
	} else if len(cipherList) == 1 {
		for id, cipher := range cipherList {
			reader := shadowaead.NewShadowsocksReader(clientConn, cipher)
			writer := shadowaead.NewShadowsocksWriter(clientConn, cipher)
			return id, onet.WrapConn(clientConn, reader, writer), nil
		}
	}
	// buffer saves the bytes read from shadowConn, in order to allow for replays.
	var buffer bytes.Buffer
	// Try each cipher until we find one that authenticates successfully.
	// This assumes that all ciphers are AEAD.
	// TODO: Reorder list to try previously successful ciphers first for the client IP.
	// TODO: Ban and log client IPs with too many failures too quick to protect against DoS.
	for id, cipher := range cipherList {
		log.Printf("Trying key %v", id)
		// tmpReader reuses the bytes read so far, falling back to shadowConn if it needs more
		// bytes. All bytes read from shadowConn are saved in buffer.
		tmpReader := io.MultiReader(bytes.NewReader(buffer.Bytes()), io.TeeReader(clientConn, &buffer))
		// Override the Reader of shadowConn so we can reset it for each cipher test.
		cipherReader := shadowaead.NewShadowsocksReader(tmpReader, cipher)
		// Read should read just enough data to authenticate the payload size.
		_, err := cipherReader.Read(make([]byte, 0))
		if err != nil {
			log.Printf("Failed key %v: %v", id, err)
			continue
		}
		log.Printf("Selected key %v", id)
		// We don't need to replay the bytes anymore, but we don't want to drop those
		// read so far.
		ssr := shadowaead.NewShadowsocksReader(io.MultiReader(&buffer, clientConn), cipher)
		ssw := shadowaead.NewShadowsocksWriter(clientConn, cipher)
		return id, onet.WrapConn(clientConn, ssr, ssw).(onet.DuplexConn), nil
	}
	return "", nil, fmt.Errorf("could not find valid key")
}

func runTCPService(listener *net.TCPListener, ciphers *map[string]shadowaead.Cipher, m metrics.ShadowsocksMetrics) {
	for {
		var clientConn onet.DuplexConn
		clientConn, err := listener.AcceptTCP()
		if err != nil {
			log.Printf("failed to accept: %v", err)
			continue
		}
		m.AddOpenTCPConnection()

		go func() (connError *connectionError) {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("ERROR Panic in TCP handler: %v", r)
				}
			}()
			connStart := time.Now()
			clientConn.(*net.TCPConn).SetKeepAlive(true)
			keyID := ""
			var proxyMetrics metrics.ProxyMetrics
			clientConn = metrics.MeasureConn(clientConn, &proxyMetrics.ProxyClient, &proxyMetrics.ClientProxy)
			defer func() {
				connEnd := time.Now()
				connDuration := connEnd.Sub(connStart)
				clientConn.Close()
				status := "OK"
				if connError != nil {
					log.Printf("ERROR [TCP] %v: %v", connError.message, connError.cause)
					status = connError.status
				}
				log.Printf("Done with status %v, duration %v", status, connDuration)
				m.AddClosedTCPConnection(keyID, status, proxyMetrics, connDuration)
			}()

			keyID, clientConn, err := findAccessKey(clientConn, *ciphers)
			if err != nil {
				return &connectionError{"ERR_CIPHER", "Failed to find a valid cipher", err}
			}

			tgtAddr, err := socks.ReadAddr(clientConn)
			if err != nil {
				return &connectionError{"ERR_READ_ADDRESS", "Failed to get target address", err}
			}
			tgtTCPAddr, err := net.ResolveTCPAddr("tcp", tgtAddr.String())
			if err != nil {
				return &connectionError{"ERR_RESOLVE_ADDRESS", fmt.Sprintf("Failed to resolve target address %v", tgtAddr.String()), err}
			}
			if !tgtTCPAddr.IP.IsGlobalUnicast() {
				return &connectionError{"ERR_ADDRESS_INVALID", fmt.Sprintf("Target address is not global unicast: %v", tgtAddr.String()), err}
			}

			tgtTCPConn, err := net.DialTCP("tcp", nil, tgtTCPAddr)
			if err != nil {
				return &connectionError{"ERR_CONNECT", "Failed to connect to target", err}
			}
			defer tgtTCPConn.Close()
			tgtTCPConn.SetKeepAlive(true)
			tgtConn := metrics.MeasureConn(tgtTCPConn, &proxyMetrics.ProxyTarget, &proxyMetrics.TargetProxy)

			// TODO: Disable logging in production. This is sensitive.
			log.Printf("proxy %s <-> %s", clientConn.RemoteAddr().String(), tgtConn)
			_, _, err = onet.Relay(clientConn, tgtConn)
			if err != nil {
				return &connectionError{"ERR_RELAY", "Failed to relay traffic", err}
			}
			return nil
		}()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"
	"path/filepath"

	"github.com/OpenBazaar/openbazaar-go/cmd"
	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
	"github.com/jessevdk/go-flags"
	"github.com/op/go-logging"
)

var log = logging.MustGetLogger("main")

type Opts struct {
	Version bool `short:"v" long:"version" description:"Print the version number and exit"`
}

var opts Opts

var parser = flags.NewParser(&opts, flags.Default)

func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for sig := range c {
			log.Noticef("Received %s\n", sig)
			log.Info("OpenBazaar Server shutting down...")
			if core.Node != nil {
				if core.Node.MessageRetriever != nil {
					core.Node.RecordAgingNotifier.Stop()
					core.Node.InboundMsgScanner.Stop()
					close(core.Node.MessageRetriever.DoneChan)
					core.Node.MessageRetriever.Wait()
				}
				core.OfflineMessageWaitGroup.Wait()
				core.Node.PublishLock.Lock()
				core.Node.Datastore.Close()
				repoLockFile := filepath.Join(core.Node.RepoPath, fsrepo.LockFile)
				os.Remove(repoLockFile)
				core.Node.Multiwallet.Close()
				core.Node.IpfsNode.Close()
			}
			os.Exit(1)
		}
	}()

	_, err := parser.AddCommand("gencerts",
		"Generate certificates",
		"Generate self-singned certificates",
		&cmd.GenerateCertificates{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("init",
		"initialize a new repo and exit",
		"Initializes a new repo without starting the server",
		&cmd.Init{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("status",
		"get the repo status",
		"Returns the status of the repo ― Uninitialized, Encrypted, Decrypted. Also returns whether Tor is available.",
		&cmd.Status{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("setapicreds",
		"set API credentials",
		"The API password field in the config file takes a SHA256 hash of the password. This command will generate the hash for you and save it to the config file.",
		&cmd.SetAPICreds{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("start",
		"start the OpenBazaar-Server",
		"The start command starts the OpenBazaar-Server",
		&cmd.Start{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("encryptdatabase",
		"encrypt your database",
		"This command encrypts the database containing your bitcoin private keys, identity key, and contracts",
		&cmd.EncryptDatabase{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("decryptdatabase",
		"decrypt your database",
		"This command decrypts the database containing your bitcoin private keys, identity key, and contracts.\n [Warning] doing so may put your bitcoins at risk.",
		&cmd.DecryptDatabase{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("restore",
		"restore user data",
		"This command will attempt to restore user data (profile, listings, ratings, etc) by downloading them from the network. This will only work if the IPNS mapping is still available in the DHT. Optionally it will take a mnemonic seed to restore from.",
		&cmd.Restore{})
	if err != nil {
		log.Error(err)
	}
	if len(os.Args) > 1 && (os.Args[1] == "--version" || os.Args[1] == "-v") {
		fmt.Println(core.VERSION)
		return
	}
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>Fix "singned" typo<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"
	"path/filepath"

	"github.com/OpenBazaar/openbazaar-go/cmd"
	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/ipfs/go-ipfs/repo/fsrepo"
	"github.com/jessevdk/go-flags"
	"github.com/op/go-logging"
)

var log = logging.MustGetLogger("main")

type Opts struct {
	Version bool `short:"v" long:"version" description:"Print the version number and exit"`
}

var opts Opts

var parser = flags.NewParser(&opts, flags.Default)

func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for sig := range c {
			log.Noticef("Received %s\n", sig)
			log.Info("OpenBazaar Server shutting down...")
			if core.Node != nil {
				if core.Node.MessageRetriever != nil {
					core.Node.RecordAgingNotifier.Stop()
					core.Node.InboundMsgScanner.Stop()
					close(core.Node.MessageRetriever.DoneChan)
					core.Node.MessageRetriever.Wait()
				}
				core.OfflineMessageWaitGroup.Wait()
				core.Node.PublishLock.Lock()
				core.Node.Datastore.Close()
				repoLockFile := filepath.Join(core.Node.RepoPath, fsrepo.LockFile)
				os.Remove(repoLockFile)
				core.Node.Multiwallet.Close()
				core.Node.IpfsNode.Close()
			}
			os.Exit(1)
		}
	}()

	_, err := parser.AddCommand("gencerts",
		"Generate certificates",
		"Generate self-signed certificates",
		&cmd.GenerateCertificates{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("init",
		"initialize a new repo and exit",
		"Initializes a new repo without starting the server",
		&cmd.Init{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("status",
		"get the repo status",
		"Returns the status of the repo ― Uninitialized, Encrypted, Decrypted. Also returns whether Tor is available.",
		&cmd.Status{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("setapicreds",
		"set API credentials",
		"The API password field in the config file takes a SHA256 hash of the password. This command will generate the hash for you and save it to the config file.",
		&cmd.SetAPICreds{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("start",
		"start the OpenBazaar-Server",
		"The start command starts the OpenBazaar-Server",
		&cmd.Start{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("encryptdatabase",
		"encrypt your database",
		"This command encrypts the database containing your bitcoin private keys, identity key, and contracts",
		&cmd.EncryptDatabase{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("decryptdatabase",
		"decrypt your database",
		"This command decrypts the database containing your bitcoin private keys, identity key, and contracts.\n [Warning] doing so may put your bitcoins at risk.",
		&cmd.DecryptDatabase{})
	if err != nil {
		log.Error(err)
	}
	_, err = parser.AddCommand("restore",
		"restore user data",
		"This command will attempt to restore user data (profile, listings, ratings, etc) by downloading them from the network. This will only work if the IPNS mapping is still available in the DHT. Optionally it will take a mnemonic seed to restore from.",
		&cmd.Restore{})
	if err != nil {
		log.Error(err)
	}
	if len(os.Args) > 1 && (os.Args[1] == "--version" || os.Args[1] == "-v") {
		fmt.Println(core.VERSION)
		return
	}
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package userdb

type Store interface {
	Check(username, password string) error
	Add(username, password string) error
}

type UserInfo interface {
	GetFirstName() string
	GetLastName() string
	GetUsername() string
	GetEmail() string
	GetIsVerified() bool
	GetRegistrationTime() time.Time
}

type UserStore interface {
	Get(username string) (UserInfo, error)
	Check(username, password string) error
	Insert(userinfo UserInfo) error
	Update(userinfo UserInfo) error
	Delete(username string) error
}
<commit_msg>Fixed build break<commit_after>package userdb

import "time"

type Store interface {
	Check(username, password string) error
	Add(username, password string) error
}

type UserInfo interface {
	GetFirstName() string
	GetLastName() string
	GetUsername() string
	GetEmail() string
	GetIsVerified() bool
	GetRegistrationTime() time.Time
}

type UserStore interface {
	Get(username string) (UserInfo, error)
	Check(username, password string) error
	Insert(userinfo UserInfo) error
	Update(userinfo UserInfo) error
	Delete(username string) error
}
<|endoftext|>


<commit_before>package util

import (
	"golang.org/x/text/language"
	"net/http"
)

var SupportedLanguageMatcher = language.NewMatcher([]language.Tag{
	language.Chinese,
	language.English,
})

func Language(req *http.Request) language.Tag {
	tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language"))
	tag, _, _ := SupportedLanguageMatcher.Match(tags...)
	return tag
}
<commit_msg>Use zh-CN instead of zh.<commit_after>package util

import (
	"golang.org/x/text/language"
	"net/http"
)

var SupportedLanguageMatcher = language.NewMatcher([]language.Tag{
	language.SimplifiedChinese,
	language.English,
})

func Language(req *http.Request) language.Tag {
	tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language"))
	tag, _, _ := SupportedLanguageMatcher.Match(tags...)
	return tag
}
<|endoftext|>


<commit_before>package input

import (
	"encoding/binary"
	"errors"
	"io"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/txscript"
	"github.com/btcsuite/btcd/wire"
	"github.com/lightningnetwork/lnd/keychain"
)

var (
	// ErrTweakOverdose signals a SignDescriptor is invalid because both of its
	// SingleTweak and DoubleTweak are non-nil.
	ErrTweakOverdose = errors.New("sign descriptor should only have one tweak")
)

// SignDescriptor houses the necessary information required to successfully sign
// a given output. This struct is used by the Signer interface in order to gain
// access to critical data needed to generate a valid signature.
type SignDescriptor struct {
	// KeyDesc is a descriptor that precisely describes *which* key to use
	// for signing. This may provide the raw public key directly, or
	// require the Signer to re-derive the key according to the populated
	// derivation path.
	KeyDesc keychain.KeyDescriptor

	// SingleTweak is a scalar value that will be added to the private key
	// corresponding to the above public key to obtain the private key to
	// be used to sign this input. This value is typically derived via the
	// following computation:
	//
	//  * derivedKey = privkey + sha256(perCommitmentPoint || pubKey) mod N
	//
	// NOTE: If this value is nil, then the input can be signed using only
	// the above public key. Either a SingleTweak should be set or a
	// DoubleTweak, not both.
	SingleTweak []byte

	// DoubleTweak is a private key that will be used in combination with
	// its corresponding private key to derive the private key that is to
	// be used to sign the target input. Within the Lightning protocol,
	// this value is typically the commitment secret from a previously
	// revoked commitment transaction. This value is in combination with
	// two hash values, and the original private key to derive the private
	// key to be used when signing.
	//
	//  * k = (privKey*sha256(pubKey || tweakPub) +
	//        tweakPriv*sha256(tweakPub || pubKey)) mod N
	//
	// NOTE: If this value is nil, then the input can be signed using only
	// the above public key. Either a SingleTweak should be set or a
	// DoubleTweak, not both.
	DoubleTweak *btcec.PrivateKey

	// WitnessScript is the full script required to properly redeem the
	// output. This field will only be populated if a p2wsh or a p2sh
	// output is being signed.
	WitnessScript []byte

	// Output is the target output which should be signed. The PkScript and
	// Value fields within the output should be properly populated,
	// otherwise an invalid signature may be generated.
	Output *wire.TxOut

	// HashType is the target sighash type that should be used when
	// generating the final sighash, and signature.
	HashType txscript.SigHashType

	// SigHashes is the pre-computed sighash midstate to be used when
	// generating the final sighash for signing.
	SigHashes *txscript.TxSigHashes

	// InputIndex is the target input within the transaction that should be
	// signed.
	InputIndex int
}

// WriteSignDescriptor serializes a SignDescriptor struct into the passed
// io.Writer stream.
//
// NOTE: We assume the SigHashes and InputIndex fields haven't been assigned
// yet, since that is usually done just before broadcast by the witness
// generator.
func WriteSignDescriptor(w io.Writer, sd *SignDescriptor) error {
	err := binary.Write(w, binary.BigEndian, sd.KeyDesc.Family)
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.BigEndian, sd.KeyDesc.Index)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, sd.KeyDesc.PubKey != nil)
	if err != nil {
		return err
	}

	if sd.KeyDesc.PubKey != nil {
		serializedPubKey := sd.KeyDesc.PubKey.SerializeCompressed()
		if err := wire.WriteVarBytes(w, 0, serializedPubKey); err != nil {
			return err
		}
	}

	if err := wire.WriteVarBytes(w, 0, sd.SingleTweak); err != nil {
		return err
	}

	var doubleTweakBytes []byte
	if sd.DoubleTweak != nil {
		doubleTweakBytes = sd.DoubleTweak.Serialize()
	}
	if err := wire.WriteVarBytes(w, 0, doubleTweakBytes); err != nil {
		return err
	}

	if err := wire.WriteVarBytes(w, 0, sd.WitnessScript); err != nil {
		return err
	}

	if err := writeTxOut(w, sd.Output); err != nil {
		return err
	}

	var scratch [4]byte
	binary.BigEndian.PutUint32(scratch[:], uint32(sd.HashType))
	if _, err := w.Write(scratch[:]); err != nil {
		return err
	}

	return nil
}

// ReadSignDescriptor deserializes a SignDescriptor struct from the passed
// io.Reader stream.
func ReadSignDescriptor(r io.Reader, sd *SignDescriptor) error {
	err := binary.Read(r, binary.BigEndian, &sd.KeyDesc.Family)
	if err != nil {
		return err
	}
	err = binary.Read(r, binary.BigEndian, &sd.KeyDesc.Index)
	if err != nil {
		return err
	}

	var hasKey bool
	err = binary.Read(r, binary.BigEndian, &hasKey)
	if err != nil {
		return err
	}

	if hasKey {
		pubKeyBytes, err := wire.ReadVarBytes(r, 0, 34, "pubkey")
		if err != nil {
			return err
		}
		sd.KeyDesc.PubKey, err = btcec.ParsePubKey(
			pubKeyBytes, btcec.S256(),
		)
		if err != nil {
			return err
		}
	}

	singleTweak, err := wire.ReadVarBytes(r, 0, 32, "singleTweak")
	if err != nil {
		return err
	}

	// Serializing a SignDescriptor with a nil-valued SingleTweak results
	// in deserializing a zero-length slice. Since a nil-valued SingleTweak
	// has special meaning and a zero-length slice for a SingleTweak is
	// invalid, we can use the zero-length slice as the flag for a
	// nil-valued SingleTweak.
	if len(singleTweak) == 0 {
		sd.SingleTweak = nil
	} else {
		sd.SingleTweak = singleTweak
	}

	doubleTweakBytes, err := wire.ReadVarBytes(r, 0, 32, "doubleTweak")
	if err != nil {
		return err
	}

	// Serializing a SignDescriptor with a nil-valued DoubleTweak results
	// in deserializing a zero-length slice. Since a nil-valued DoubleTweak
	// has special meaning and a zero-length slice for a DoubleTweak is
	// invalid, we can use the zero-length slice as the flag for a
	// nil-valued DoubleTweak.
	if len(doubleTweakBytes) == 0 {
		sd.DoubleTweak = nil
	} else {
		sd.DoubleTweak, _ = btcec.PrivKeyFromBytes(btcec.S256(), doubleTweakBytes)
	}

	// Only one tweak should ever be set, fail if both are present.
	if sd.SingleTweak != nil && sd.DoubleTweak != nil {
		return ErrTweakOverdose
	}

	witnessScript, err := wire.ReadVarBytes(r, 0, 500, "witnessScript")
	if err != nil {
		return err
	}
	sd.WitnessScript = witnessScript

	txOut := &wire.TxOut{}
	if err := readTxOut(r, txOut); err != nil {
		return err
	}
	sd.Output = txOut

	var hashType [4]byte
	if _, err := io.ReadFull(r, hashType[:]); err != nil {
		return err
	}
	sd.HashType = txscript.SigHashType(binary.BigEndian.Uint32(hashType[:]))

	return nil
}
<commit_msg>input: update SignDescriptor doc to note only segwit is supported<commit_after>package input

import (
	"encoding/binary"
	"errors"
	"io"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/txscript"
	"github.com/btcsuite/btcd/wire"
	"github.com/lightningnetwork/lnd/keychain"
)

var (
	// ErrTweakOverdose signals a SignDescriptor is invalid because both of its
	// SingleTweak and DoubleTweak are non-nil.
	ErrTweakOverdose = errors.New("sign descriptor should only have one tweak")
)

// SignDescriptor houses the necessary information required to successfully
// sign a given segwit output. This struct is used by the Signer interface in
// order to gain access to critical data needed to generate a valid signature.
type SignDescriptor struct {
	// KeyDesc is a descriptor that precisely describes *which* key to use
	// for signing. This may provide the raw public key directly, or
	// require the Signer to re-derive the key according to the populated
	// derivation path.
	KeyDesc keychain.KeyDescriptor

	// SingleTweak is a scalar value that will be added to the private key
	// corresponding to the above public key to obtain the private key to
	// be used to sign this input. This value is typically derived via the
	// following computation:
	//
	//  * derivedKey = privkey + sha256(perCommitmentPoint || pubKey) mod N
	//
	// NOTE: If this value is nil, then the input can be signed using only
	// the above public key. Either a SingleTweak should be set or a
	// DoubleTweak, not both.
	SingleTweak []byte

	// DoubleTweak is a private key that will be used in combination with
	// its corresponding private key to derive the private key that is to
	// be used to sign the target input. Within the Lightning protocol,
	// this value is typically the commitment secret from a previously
	// revoked commitment transaction. This value is in combination with
	// two hash values, and the original private key to derive the private
	// key to be used when signing.
	//
	//  * k = (privKey*sha256(pubKey || tweakPub) +
	//        tweakPriv*sha256(tweakPub || pubKey)) mod N
	//
	// NOTE: If this value is nil, then the input can be signed using only
	// the above public key. Either a SingleTweak should be set or a
	// DoubleTweak, not both.
	DoubleTweak *btcec.PrivateKey

	// WitnessScript is the full script required to properly redeem the
	// output. This field should be set to the full script if a p2wsh
	// output is being signed. For p2wkh it should be set to the hashed
	// script (PkScript).
	WitnessScript []byte

	// Output is the target output which should be signed. The PkScript and
	// Value fields within the output should be properly populated,
	// otherwise an invalid signature may be generated.
	Output *wire.TxOut

	// HashType is the target sighash type that should be used when
	// generating the final sighash, and signature.
	HashType txscript.SigHashType

	// SigHashes is the pre-computed sighash midstate to be used when
	// generating the final sighash for signing.
	SigHashes *txscript.TxSigHashes

	// InputIndex is the target input within the transaction that should be
	// signed.
	InputIndex int
}

// WriteSignDescriptor serializes a SignDescriptor struct into the passed
// io.Writer stream.
//
// NOTE: We assume the SigHashes and InputIndex fields haven't been assigned
// yet, since that is usually done just before broadcast by the witness
// generator.
func WriteSignDescriptor(w io.Writer, sd *SignDescriptor) error {
	err := binary.Write(w, binary.BigEndian, sd.KeyDesc.Family)
	if err != nil {
		return err
	}
	err = binary.Write(w, binary.BigEndian, sd.KeyDesc.Index)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, sd.KeyDesc.PubKey != nil)
	if err != nil {
		return err
	}

	if sd.KeyDesc.PubKey != nil {
		serializedPubKey := sd.KeyDesc.PubKey.SerializeCompressed()
		if err := wire.WriteVarBytes(w, 0, serializedPubKey); err != nil {
			return err
		}
	}

	if err := wire.WriteVarBytes(w, 0, sd.SingleTweak); err != nil {
		return err
	}

	var doubleTweakBytes []byte
	if sd.DoubleTweak != nil {
		doubleTweakBytes = sd.DoubleTweak.Serialize()
	}
	if err := wire.WriteVarBytes(w, 0, doubleTweakBytes); err != nil {
		return err
	}

	if err := wire.WriteVarBytes(w, 0, sd.WitnessScript); err != nil {
		return err
	}

	if err := writeTxOut(w, sd.Output); err != nil {
		return err
	}

	var scratch [4]byte
	binary.BigEndian.PutUint32(scratch[:], uint32(sd.HashType))
	if _, err := w.Write(scratch[:]); err != nil {
		return err
	}

	return nil
}

// ReadSignDescriptor deserializes a SignDescriptor struct from the passed
// io.Reader stream.
func ReadSignDescriptor(r io.Reader, sd *SignDescriptor) error {
	err := binary.Read(r, binary.BigEndian, &sd.KeyDesc.Family)
	if err != nil {
		return err
	}
	err = binary.Read(r, binary.BigEndian, &sd.KeyDesc.Index)
	if err != nil {
		return err
	}

	var hasKey bool
	err = binary.Read(r, binary.BigEndian, &hasKey)
	if err != nil {
		return err
	}

	if hasKey {
		pubKeyBytes, err := wire.ReadVarBytes(r, 0, 34, "pubkey")
		if err != nil {
			return err
		}
		sd.KeyDesc.PubKey, err = btcec.ParsePubKey(
			pubKeyBytes, btcec.S256(),
		)
		if err != nil {
			return err
		}
	}

	singleTweak, err := wire.ReadVarBytes(r, 0, 32, "singleTweak")
	if err != nil {
		return err
	}

	// Serializing a SignDescriptor with a nil-valued SingleTweak results
	// in deserializing a zero-length slice. Since a nil-valued SingleTweak
	// has special meaning and a zero-length slice for a SingleTweak is
	// invalid, we can use the zero-length slice as the flag for a
	// nil-valued SingleTweak.
	if len(singleTweak) == 0 {
		sd.SingleTweak = nil
	} else {
		sd.SingleTweak = singleTweak
	}

	doubleTweakBytes, err := wire.ReadVarBytes(r, 0, 32, "doubleTweak")
	if err != nil {
		return err
	}

	// Serializing a SignDescriptor with a nil-valued DoubleTweak results
	// in deserializing a zero-length slice. Since a nil-valued DoubleTweak
	// has special meaning and a zero-length slice for a DoubleTweak is
	// invalid, we can use the zero-length slice as the flag for a
	// nil-valued DoubleTweak.
	if len(doubleTweakBytes) == 0 {
		sd.DoubleTweak = nil
	} else {
		sd.DoubleTweak, _ = btcec.PrivKeyFromBytes(btcec.S256(), doubleTweakBytes)
	}

	// Only one tweak should ever be set, fail if both are present.
	if sd.SingleTweak != nil && sd.DoubleTweak != nil {
		return ErrTweakOverdose
	}

	witnessScript, err := wire.ReadVarBytes(r, 0, 500, "witnessScript")
	if err != nil {
		return err
	}
	sd.WitnessScript = witnessScript

	txOut := &wire.TxOut{}
	if err := readTxOut(r, txOut); err != nil {
		return err
	}
	sd.Output = txOut

	var hashType [4]byte
	if _, err := io.ReadFull(r, hashType[:]); err != nil {
		return err
	}
	sd.HashType = txscript.SigHashType(binary.BigEndian.Uint32(hashType[:]))

	return nil
}
<|endoftext|>