<commit_before>package mit

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

var parensRegex = regexp.MustCompile("\\((.*?)\\)")

// A ScheduledMeeting struct contains details about a scheduled meeting in a TimeInfo. Each TimeInfo can have multiple ScheduledMeetings.
type ScheduledMeeting struct {
	Weekdays     []time.Weekday
	StartSeconds int
	EndSeconds   int
}

// A TimeInfo struct contains details about when a class's section meets.
type TimeInfo struct {
	Meetings []ScheduledMeeting
	BeginsOn time.Time
	EndsOn   time.Time
}

func parseTime(timeString string, forceAM bool) (int, error) {
	// sometimes, for whatever reason, use a colon instead of the normal dot as a separator
	// this seems to just be some advising seminars
	// replace these colons with a dot so that we can handle them
	timeString = strings.Replace(timeString, ":", ".", -1)

	// some classes also like to just randomly add a "pm"
	// looking at you WGS.228 and 15.389
	isPM := false
	if strings.Contains(timeString, "pm") || strings.Contains(timeString, "PM") {
		timeString = strings.Replace(strings.Replace(timeString, "pm", "", -1), "PM", "", -1)
		isPM = true
	}

	// it's a time like "4" or "5.30"
	parts := strings.Split(timeString, ".")
	if len(parts) > 2 {
		return 0, fmt.Errorf("mit: parseTime: time string '%s' had too many dots", timeString)
	}

	hour, err := strconv.Atoi(strings.TrimSpace(parts[0]))
	if err != nil {
		return 0, err
	}

	minute := 0

	if len(parts) == 2 {
		minute, err = strconv.Atoi(strings.TrimSpace(parts[1]))
		if err != nil {
			return 0, err
		}
	}

	if forceAM || (!isPM && hour >= 8 && hour <= 12) {
		// assume AM
	} else {
		// assume PM
		hour += 12
	}

	timeSeconds := ((hour * 60) + minute) * 60

	return timeSeconds, nil
}

func assignYearForDate(date time.Time, termInfo TermInfo) time.Time {
	return date.AddDate(termInfo.FirstDayOfClasses.Year(), 0, 0)
}

// ParseScheduledMeeting parses the given time info string, in a format like "MW4-5.30"
func ParseScheduledMeeting(scheduledMeetingString string, termInfo TermInfo) (*ScheduledMeeting, *time.Time, *time.Time, error) {
	scheduledMeeting := ScheduledMeeting{
		Weekdays: []time.Weekday{},
	}

	var beginsOn *time.Time
	var endsOn *time.Time

	if strings.TrimSpace(strings.ToUpper(scheduledMeetingString)) == "*SECTION CANCELLED" || strings.TrimSpace(strings.ToUpper(scheduledMeetingString)) == "*TO BE ARRANGED" || strings.TrimSpace(strings.ToUpper(scheduledMeetingString)) == "TBA" || strings.TrimSpace(strings.ToUpper(scheduledMeetingString)) == "TBD" || strings.TrimSpace(strings.ToUpper(scheduledMeetingString)) == "ARRANGED" {
		// oof
		return nil, nil, nil, nil
	}

	parsedATime := false

	if strings.Contains(scheduledMeetingString, "EVE") {
		// it's an evening class
		// for example "TR EVE (4-6 PM)" or "W EVE (4-6.30 PM)"

		matches := parensRegex.FindAllStringSubmatch(scheduledMeetingString, -1)
		if len(matches) != 1 {
			return nil, nil, nil, fmt.Errorf("mit: ParseScheduledMeeting: time info string '%s' had unexpected number of parens", scheduledMeetingString)
		}

		time := matches[0][1]
		time = strings.Replace(time, " PM", "", -1)

		subScheduledMeeting, _, _, err := ParseScheduledMeeting(time, termInfo)
		if err != nil {
			return nil, nil, nil, err
		}

		if subScheduledMeeting.StartSeconds < 12*60*60 {
			subScheduledMeeting.StartSeconds += 12 * 60 * 60
		} else if subScheduledMeeting.EndSeconds < 12*60*60 {
			subScheduledMeeting.EndSeconds += 12 * 60 * 60
		}

		scheduledMeeting.StartSeconds = subScheduledMeeting.StartSeconds
		scheduledMeeting.EndSeconds = subScheduledMeeting.EndSeconds

		scheduledMeetingString = strings.Replace(scheduledMeetingString, "EVE", "", -1)
		scheduledMeetingString = parensRegex.ReplaceAllString(scheduledMeetingString, "")

		parsedATime = true
	} else if strings.Contains(scheduledMeetingString, "(") {
		// there's a thing in parentheses
		// for example "TR10.30-12 (BEGINS OCT 21)"
		matches := parensRegex.FindAllStringSubmatch(scheduledMeetingString, -1)
		for _, match := range matches {
			info := match[1]

			if strings.HasPrefix(info, "BEGINS") {
				dateString := strings.Replace(info, "BEGINS ", "", -1)
				parsedDate, err := time.Parse("Jan 2", dateString)
				if err != nil {
					return nil, nil, nil, err
				}
				parsedDate = assignYearForDate(parsedDate, termInfo)
				beginsOn = &parsedDate
			} else if strings.HasPrefix(info, "END") {
				dateString := strings.Replace(info, "ENDS ", "", -1)
				parsedDate, err := time.Parse("Jan 2", dateString)
				if err != nil {
					return nil, nil, nil, err
				}
				parsedDate = assignYearForDate(parsedDate, termInfo)
				endsOn = &parsedDate
			} else if strings.HasPrefix(info, "MEETS") {
				// it's a message in the format "MEETS 4/7 TO 5/14"
				dateString := strings.Replace(info, "MEETS ", "", -1)
				parts := strings.Split(dateString, "TO")

				parsedBegin, err := time.Parse("1/2", strings.TrimSpace(parts[0]))
				if err != nil {
					return nil, nil, nil, err
				}
				parsedBegin = assignYearForDate(parsedBegin, termInfo)
				beginsOn = &parsedBegin

				parsedEnd, err := time.Parse("1/2", strings.TrimSpace(parts[1]))
				if err != nil {
					return nil, nil, nil, err
				}
				parsedEnd = assignYearForDate(parsedEnd, termInfo)
				endsOn = &parsedEnd
			} else if strings.HasPrefix(info, "LIMITED") {
				// it's about limited enrollment, which we don't care about
				// just ignore it
			} else {
				// some classes are not entered into the catalog correctly
				// they have a format like T(11-12:30)
				// if we can parse the time in parenthesis, assume that's the problem
				parsedInfo, _, _, err := ParseScheduledMeeting(info, termInfo)
				if err != nil {
					// didn't work, give up
					return nil, nil, nil, fmt.Errorf("mit: ParseScheduledMeeting: couldn't handle info '%s'", info)
				}

				// it worked, so keep going
				if parsedInfo.StartSeconds != 0 {
					scheduledMeeting.StartSeconds = parsedInfo.StartSeconds
				}
				if parsedInfo.EndSeconds != 0 {
					scheduledMeeting.EndSeconds = parsedInfo.EndSeconds
				}
			}
		}

		scheduledMeetingString = parensRegex.ReplaceAllString(scheduledMeetingString, "")
	}

	scheduledMeetingString = strings.TrimSpace(scheduledMeetingString)

	charMap := map[rune]time.Weekday{
		'M': time.Monday,
		'T': time.Tuesday,
		'W': time.Wednesday,
		'R': time.Thursday,
		'F': time.Friday,
	}

	remainingScheduledMeetingString := ""

	// first parse out all the weekdays
	for i, scheduledMeetingRune := range scheduledMeetingString {
		weekday, isWeekday := charMap[scheduledMeetingRune]
		if isWeekday {
			scheduledMeeting.Weekdays = append(scheduledMeeting.Weekdays, weekday)
		} else {
			// we're done
			remainingScheduledMeetingString = scheduledMeetingString[i:]
			break
		}
	}

	var err error
	if remainingScheduledMeetingString != "" && !parsedATime {
		if strings.Contains(remainingScheduledMeetingString, "-") {
			// it's a time like "4-5.30"
			forceAM := false
			if strings.Contains(remainingScheduledMeetingString, "AM") {
				forceAM = true
				remainingScheduledMeetingString = strings.Replace(remainingScheduledMeetingString, "AM", "", -1)
			}

			// HACK: 18.204 has a string in the format "MW2.30-4 (LIMITED 15 EACH S .."
			// we detect this and ignore the parenthesis
			if strings.Contains(remainingScheduledMeetingString, "(") && !strings.Contains(remainingScheduledMeetingString, ")") {
				remainingScheduledMeetingString = strings.Split(remainingScheduledMeetingString, "(")[0]
			}

			timeParts := strings.Split(remainingScheduledMeetingString, "-")
			if len(timeParts) != 2 {
				return nil, nil, nil, fmt.Errorf("mit: ParseScheduledMeeting: time info string '%s' had too many dashes", scheduledMeetingString)
			}

			scheduledMeeting.StartSeconds, err = parseTime(timeParts[0], forceAM)
			if err != nil {
				return nil, nil, nil, err
			}

			scheduledMeeting.EndSeconds, err = parseTime(timeParts[1], forceAM)
			if err != nil {
				return nil, nil, nil, err
			}
		} else {
			// it's a time like "4"
			scheduledMeeting.StartSeconds, err = parseTime(remainingScheduledMeetingString, false)
			if err != nil {
				return nil, nil, nil, err
			}

			// we can assume it's an hour long
			scheduledMeeting.EndSeconds = scheduledMeeting.StartSeconds + 60*60
		}
	} else {
		if strings.TrimSpace(remainingScheduledMeetingString) != "" && parsedATime {
			// there's something left, and it can't be a time...
			// complain
			return nil, nil, nil, fmt.Errorf("mit: unexpected extra data '%s' when parsing time string '%s'", remainingScheduledMeetingString, scheduledMeetingString)
		}
	}

	return &scheduledMeeting, beginsOn, endsOn, nil
}

// ParseTimeInfo parses out the time information from an input string in the format "MW9-11,F9".
func ParseTimeInfo(timeInfoString string, termInfo TermInfo) (TimeInfo, error) {
	timeInfo := TimeInfo{
		Meetings: []ScheduledMeeting{},
		BeginsOn: termInfo.FirstDayOfClasses,
		EndsOn:   termInfo.LastDayOfClasses,
	}

	// hack to cope with the fact that some people really, really don't understand how the course catalog works
	// this is specifically for AS.301
	timeInfoString = strings.Replace(timeInfoString, "Thurs", "R", -1)

	timeInfoParts := strings.Split(timeInfoString, ",")
	for _, part := range timeInfoParts {
		meeting, beginsOn, endsOn, err := ParseScheduledMeeting(part, termInfo)
		if err != nil {
			return TimeInfo{}, err
		}

		if beginsOn != nil {
			timeInfo.BeginsOn = *beginsOn
		}
		if endsOn != nil {
			timeInfo.EndsOn = *endsOn
		}

		if meeting != nil {
			timeInfo.Meetings = append(timeInfo.Meetings, *meeting)
		}
	}

	return timeInfo, nil
}
<commit_msg>mit: fix importer crash on some variations of 'to be arranged'<commit_after>package mit

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

var parensRegex = regexp.MustCompile("\\((.*?)\\)")

// A ScheduledMeeting struct contains details about a scheduled meeting in a TimeInfo. Each TimeInfo can have multiple ScheduledMeetings.
type ScheduledMeeting struct {
	Weekdays     []time.Weekday
	StartSeconds int
	EndSeconds   int
}

// A TimeInfo struct contains details about when a class's section meets.
type TimeInfo struct {
	Meetings []ScheduledMeeting
	BeginsOn time.Time
	EndsOn   time.Time
}

func parseTime(timeString string, forceAM bool) (int, error) {
	// sometimes, for whatever reason, use a colon instead of the normal dot as a separator
	// this seems to just be some advising seminars
	// replace these colons with a dot so that we can handle them
	timeString = strings.Replace(timeString, ":", ".", -1)

	// some classes also like to just randomly add a "pm"
	// looking at you WGS.228 and 15.389
	isPM := false
	if strings.Contains(timeString, "pm") || strings.Contains(timeString, "PM") {
		timeString = strings.Replace(strings.Replace(timeString, "pm", "", -1), "PM", "", -1)
		isPM = true
	}

	// it's a time like "4" or "5.30"
	parts := strings.Split(timeString, ".")
	if len(parts) > 2 {
		return 0, fmt.Errorf("mit: parseTime: time string '%s' had too many dots", timeString)
	}

	hour, err := strconv.Atoi(strings.TrimSpace(parts[0]))
	if err != nil {
		return 0, err
	}

	minute := 0

	if len(parts) == 2 {
		minute, err = strconv.Atoi(strings.TrimSpace(parts[1]))
		if err != nil {
			return 0, err
		}
	}

	if forceAM || (!isPM && hour >= 8 && hour <= 12) {
		// assume AM
	} else {
		// assume PM
		hour += 12
	}

	timeSeconds := ((hour * 60) + minute) * 60

	return timeSeconds, nil
}

func assignYearForDate(date time.Time, termInfo TermInfo) time.Time {
	return date.AddDate(termInfo.FirstDayOfClasses.Year(), 0, 0)
}

// ParseScheduledMeeting parses the given time info string, in a format like "MW4-5.30"
func ParseScheduledMeeting(scheduledMeetingString string, termInfo TermInfo) (*ScheduledMeeting, *time.Time, *time.Time, error) {
	scheduledMeeting := ScheduledMeeting{
		Weekdays: []time.Weekday{},
	}

	var beginsOn *time.Time
	var endsOn *time.Time

	normalizedMeetingString := strings.ToUpper(strings.TrimSpace(strings.Replace(scheduledMeetingString, "*", "", -1)))

	if normalizedMeetingString == "SECTION CANCELLED" || normalizedMeetingString == "TO BE ARRANGED" || normalizedMeetingString == "TBA" || normalizedMeetingString == "TBD" || normalizedMeetingString == "ARRANGED" {
		// oof
		return nil, nil, nil, nil
	}

	parsedATime := false

	if strings.Contains(scheduledMeetingString, "EVE") {
		// it's an evening class
		// for example "TR EVE (4-6 PM)" or "W EVE (4-6.30 PM)"

		matches := parensRegex.FindAllStringSubmatch(scheduledMeetingString, -1)
		if len(matches) != 1 {
			return nil, nil, nil, fmt.Errorf("mit: ParseScheduledMeeting: time info string '%s' had unexpected number of parens", scheduledMeetingString)
		}

		time := matches[0][1]
		time = strings.Replace(time, " PM", "", -1)

		subScheduledMeeting, _, _, err := ParseScheduledMeeting(time, termInfo)
		if err != nil {
			return nil, nil, nil, err
		}

		if subScheduledMeeting.StartSeconds < 12*60*60 {
			subScheduledMeeting.StartSeconds += 12 * 60 * 60
		} else if subScheduledMeeting.EndSeconds < 12*60*60 {
			subScheduledMeeting.EndSeconds += 12 * 60 * 60
		}

		scheduledMeeting.StartSeconds = subScheduledMeeting.StartSeconds
		scheduledMeeting.EndSeconds = subScheduledMeeting.EndSeconds

		scheduledMeetingString = strings.Replace(scheduledMeetingString, "EVE", "", -1)
		scheduledMeetingString = parensRegex.ReplaceAllString(scheduledMeetingString, "")

		parsedATime = true
	} else if strings.Contains(scheduledMeetingString, "(") {
		// there's a thing in parentheses
		// for example "TR10.30-12 (BEGINS OCT 21)"
		matches := parensRegex.FindAllStringSubmatch(scheduledMeetingString, -1)
		for _, match := range matches {
			info := match[1]

			if strings.HasPrefix(info, "BEGINS") {
				dateString := strings.Replace(info, "BEGINS ", "", -1)
				parsedDate, err := time.Parse("Jan 2", dateString)
				if err != nil {
					return nil, nil, nil, err
				}
				parsedDate = assignYearForDate(parsedDate, termInfo)
				beginsOn = &parsedDate
			} else if strings.HasPrefix(info, "END") {
				dateString := strings.Replace(info, "ENDS ", "", -1)
				parsedDate, err := time.Parse("Jan 2", dateString)
				if err != nil {
					return nil, nil, nil, err
				}
				parsedDate = assignYearForDate(parsedDate, termInfo)
				endsOn = &parsedDate
			} else if strings.HasPrefix(info, "MEETS") {
				// it's a message in the format "MEETS 4/7 TO 5/14"
				dateString := strings.Replace(info, "MEETS ", "", -1)
				parts := strings.Split(dateString, "TO")

				parsedBegin, err := time.Parse("1/2", strings.TrimSpace(parts[0]))
				if err != nil {
					return nil, nil, nil, err
				}
				parsedBegin = assignYearForDate(parsedBegin, termInfo)
				beginsOn = &parsedBegin

				parsedEnd, err := time.Parse("1/2", strings.TrimSpace(parts[1]))
				if err != nil {
					return nil, nil, nil, err
				}
				parsedEnd = assignYearForDate(parsedEnd, termInfo)
				endsOn = &parsedEnd
			} else if strings.HasPrefix(info, "LIMITED") {
				// it's about limited enrollment, which we don't care about
				// just ignore it
			} else {
				// some classes are not entered into the catalog correctly
				// they have a format like T(11-12:30)
				// if we can parse the time in parenthesis, assume that's the problem
				parsedInfo, _, _, err := ParseScheduledMeeting(info, termInfo)
				if err != nil {
					// didn't work, give up
					return nil, nil, nil, fmt.Errorf("mit: ParseScheduledMeeting: couldn't handle info '%s'", info)
				}

				// it worked, so keep going
				if parsedInfo.StartSeconds != 0 {
					scheduledMeeting.StartSeconds = parsedInfo.StartSeconds
				}
				if parsedInfo.EndSeconds != 0 {
					scheduledMeeting.EndSeconds = parsedInfo.EndSeconds
				}
			}
		}

		scheduledMeetingString = parensRegex.ReplaceAllString(scheduledMeetingString, "")
	}

	scheduledMeetingString = strings.TrimSpace(scheduledMeetingString)

	charMap := map[rune]time.Weekday{
		'M': time.Monday,
		'T': time.Tuesday,
		'W': time.Wednesday,
		'R': time.Thursday,
		'F': time.Friday,
	}

	remainingScheduledMeetingString := ""

	// first parse out all the weekdays
	for i, scheduledMeetingRune := range scheduledMeetingString {
		weekday, isWeekday := charMap[scheduledMeetingRune]
		if isWeekday {
			scheduledMeeting.Weekdays = append(scheduledMeeting.Weekdays, weekday)
		} else {
			// we're done
			remainingScheduledMeetingString = scheduledMeetingString[i:]
			break
		}
	}

	var err error
	if remainingScheduledMeetingString != "" && !parsedATime {
		if strings.Contains(remainingScheduledMeetingString, "-") {
			// it's a time like "4-5.30"
			forceAM := false
			if strings.Contains(remainingScheduledMeetingString, "AM") {
				forceAM = true
				remainingScheduledMeetingString = strings.Replace(remainingScheduledMeetingString, "AM", "", -1)
			}

			// HACK: 18.204 has a string in the format "MW2.30-4 (LIMITED 15 EACH S .."
			// we detect this and ignore the parenthesis
			if strings.Contains(remainingScheduledMeetingString, "(") && !strings.Contains(remainingScheduledMeetingString, ")") {
				remainingScheduledMeetingString = strings.Split(remainingScheduledMeetingString, "(")[0]
			}

			timeParts := strings.Split(remainingScheduledMeetingString, "-")
			if len(timeParts) != 2 {
				return nil, nil, nil, fmt.Errorf("mit: ParseScheduledMeeting: time info string '%s' had too many dashes", scheduledMeetingString)
			}

			scheduledMeeting.StartSeconds, err = parseTime(timeParts[0], forceAM)
			if err != nil {
				return nil, nil, nil, err
			}

			scheduledMeeting.EndSeconds, err = parseTime(timeParts[1], forceAM)
			if err != nil {
				return nil, nil, nil, err
			}
		} else {
			// it's a time like "4"
			scheduledMeeting.StartSeconds, err = parseTime(remainingScheduledMeetingString, false)
			if err != nil {
				return nil, nil, nil, err
			}

			// we can assume it's an hour long
			scheduledMeeting.EndSeconds = scheduledMeeting.StartSeconds + 60*60
		}
	} else {
		if strings.TrimSpace(remainingScheduledMeetingString) != "" && parsedATime {
			// there's something left, and it can't be a time...
			// complain
			return nil, nil, nil, fmt.Errorf("mit: unexpected extra data '%s' when parsing time string '%s'", remainingScheduledMeetingString, scheduledMeetingString)
		}
	}

	return &scheduledMeeting, beginsOn, endsOn, nil
}

// ParseTimeInfo parses out the time information from an input string in the format "MW9-11,F9".
func ParseTimeInfo(timeInfoString string, termInfo TermInfo) (TimeInfo, error) {
	timeInfo := TimeInfo{
		Meetings: []ScheduledMeeting{},
		BeginsOn: termInfo.FirstDayOfClasses,
		EndsOn:   termInfo.LastDayOfClasses,
	}

	// hack to cope with the fact that some people really, really don't understand how the course catalog works
	// this is specifically for AS.301
	timeInfoString = strings.Replace(timeInfoString, "Thurs", "R", -1)

	timeInfoParts := strings.Split(timeInfoString, ",")
	for _, part := range timeInfoParts {
		meeting, beginsOn, endsOn, err := ParseScheduledMeeting(part, termInfo)
		if err != nil {
			return TimeInfo{}, err
		}

		if beginsOn != nil {
			timeInfo.BeginsOn = *beginsOn
		}
		if endsOn != nil {
			timeInfo.EndsOn = *endsOn
		}

		if meeting != nil {
			timeInfo.Meetings = append(timeInfo.Meetings, *meeting)
		}
	}

	return timeInfo, nil
}
<|endoftext|>


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

package cmd

import (
	"fmt"

	"github.com/cilium/cilium/common"
	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/command"
	"github.com/cilium/cilium/pkg/loadbalancer"
	"github.com/cilium/cilium/pkg/maps/lbmap"

	"github.com/spf13/cobra"
)

const (
	idTitle             = "ID"
	serviceAddressTitle = "SERVICE ADDRESS"
	backendAddressTitle = "BACKEND ADDRESS"
)

var (
	listRevNAT bool
	listLegacy bool
)

func dumpRevNat(serviceList map[string][]string) {
	if err := lbmap.RevNat4Map.DumpIfExists(serviceList); err != nil {
		Fatalf("Unable to dump IPv4 reverse NAT table: %s", err)
	}
	if err := lbmap.RevNat6Map.DumpIfExists(serviceList); err != nil {
		Fatalf("Unable to dump IPv6 reverse NAT table: %s", err)
	}
}

func dumpSVC(serviceList map[string][]string) {
	// It's safe to use the same map for both IPv4 and IPv6, as backend
	// IDs are allocated from the same pool regardless the protocol
	backendMap := make(map[loadbalancer.BackendID]lbmap.BackendValue)

	parseBackendEntry := func(key bpf.MapKey, value bpf.MapValue) {
		id := key.(lbmap.BackendKey).GetID()
		backendMap[id] = value.DeepCopyMapValue().(lbmap.BackendValue)
	}
	if err := lbmap.Backend4Map.DumpWithCallbackIfExists(parseBackendEntry); err != nil {
		Fatalf("Unable to dump IPv4 backends table: %s", err)
	}
	if err := lbmap.Backend6Map.DumpWithCallbackIfExists(parseBackendEntry); err != nil {
		Fatalf("Unable to dump IPv6 backends table: %s", err)
	}

	parseSVCEntry := func(key bpf.MapKey, value bpf.MapValue) {
		var entry string

		svcKey := key.(lbmap.ServiceKeyV2)
		svcVal := value.(lbmap.ServiceValueV2)
		svc := svcKey.String()
		revNATID := svcVal.GetRevNat()
		backendID := svcVal.GetBackendID()

		if backendID == 0 {
			ip := "0.0.0.0"
			if svcKey.IsIPv6() {
				ip = "[::]"
			}
			entry = fmt.Sprintf("%s:%d (%d)", ip, 0, revNATID)
		} else if backend, found := backendMap[backendID]; !found {
			entry = fmt.Sprintf("backend %d not found", backendID)
		} else {
			fmtStr := "%s:%d (%d)"
			if svcKey.IsIPv6() {
				fmtStr = "[%s]:%d (%d)"
			}
			entry = fmt.Sprintf(fmtStr, backend.GetAddress(),
				backend.GetPort(), revNATID)
		}

		serviceList[svc] = append(serviceList[svc], entry)
	}

	if err := lbmap.Service4MapV2.DumpWithCallback(parseSVCEntry); err != nil {
		Fatalf("Unable to dump IPv4 services table: %s", err)
	}
	if err := lbmap.Service6MapV2.DumpWithCallback(parseSVCEntry); err != nil {
		Fatalf("Unable to dump IPv6 services table: %s", err)
	}
}

func dumpLegacySVC(serviceList map[string][]string) {
	if err := lbmap.Service4Map.DumpIfExists(serviceList); err != nil {
		Fatalf("Unable to dump IPv4 services table: %s", err)
	}
	if err := lbmap.Service6Map.DumpIfExists(serviceList); err != nil {
		Fatalf("Unable to dump IPv6 services table: %s", err)
	}
}

// bpfCtListCmd represents the bpf_ct_list command
var bpfLBListCmd = &cobra.Command{
	Use:     "list",
	Aliases: []string{"ls"},
	Short:   "List load-balancing configuration",
	Run: func(cmd *cobra.Command, args []string) {
		common.RequireRootPrivilege("cilium bpf lb list")

		var firstTitle string
		serviceList := make(map[string][]string)
		switch {
		case listRevNAT:
			firstTitle = idTitle
			dumpRevNat(serviceList)
		case listLegacy:
			firstTitle = serviceAddressTitle
			dumpLegacySVC(serviceList)
		default:
			firstTitle = serviceAddressTitle
			dumpSVC(serviceList)
		}

		if command.OutputJSON() {
			if err := command.PrintOutput(serviceList); err != nil {
				Fatalf("Unable to generate JSON output: %s", err)
			}
			return
		}

		TablePrinter(firstTitle, backendAddressTitle, serviceList)
	},
}

func init() {
	bpfLBCmd.AddCommand(bpfLBListCmd)
	bpfLBListCmd.Flags().BoolVarP(&listRevNAT, "revnat", "", false, "List reverse NAT entries")
	bpfLBListCmd.Flags().BoolVarP(&listLegacy, "legacy", "", false, "List legacy service entries")
	command.AddJSONOutput(bpfLBListCmd)
}
<commit_msg>cilium/cmd: dump bpf lb list if map exists<commit_after>// Copyright 2017-2019 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"

	"github.com/cilium/cilium/common"
	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/command"
	"github.com/cilium/cilium/pkg/loadbalancer"
	"github.com/cilium/cilium/pkg/maps/lbmap"

	"github.com/spf13/cobra"
)

const (
	idTitle             = "ID"
	serviceAddressTitle = "SERVICE ADDRESS"
	backendAddressTitle = "BACKEND ADDRESS"
)

var (
	listRevNAT bool
	listLegacy bool
)

func dumpRevNat(serviceList map[string][]string) {
	if err := lbmap.RevNat4Map.DumpIfExists(serviceList); err != nil {
		Fatalf("Unable to dump IPv4 reverse NAT table: %s", err)
	}
	if err := lbmap.RevNat6Map.DumpIfExists(serviceList); err != nil {
		Fatalf("Unable to dump IPv6 reverse NAT table: %s", err)
	}
}

func dumpSVC(serviceList map[string][]string) {
	// It's safe to use the same map for both IPv4 and IPv6, as backend
	// IDs are allocated from the same pool regardless the protocol
	backendMap := make(map[loadbalancer.BackendID]lbmap.BackendValue)

	parseBackendEntry := func(key bpf.MapKey, value bpf.MapValue) {
		id := key.(lbmap.BackendKey).GetID()
		backendMap[id] = value.DeepCopyMapValue().(lbmap.BackendValue)
	}
	if err := lbmap.Backend4Map.DumpWithCallbackIfExists(parseBackendEntry); err != nil {
		Fatalf("Unable to dump IPv4 backends table: %s", err)
	}
	if err := lbmap.Backend6Map.DumpWithCallbackIfExists(parseBackendEntry); err != nil {
		Fatalf("Unable to dump IPv6 backends table: %s", err)
	}

	parseSVCEntry := func(key bpf.MapKey, value bpf.MapValue) {
		var entry string

		svcKey := key.(lbmap.ServiceKeyV2)
		svcVal := value.(lbmap.ServiceValueV2)
		svc := svcKey.String()
		revNATID := svcVal.GetRevNat()
		backendID := svcVal.GetBackendID()

		if backendID == 0 {
			ip := "0.0.0.0"
			if svcKey.IsIPv6() {
				ip = "[::]"
			}
			entry = fmt.Sprintf("%s:%d (%d)", ip, 0, revNATID)
		} else if backend, found := backendMap[backendID]; !found {
			entry = fmt.Sprintf("backend %d not found", backendID)
		} else {
			fmtStr := "%s:%d (%d)"
			if svcKey.IsIPv6() {
				fmtStr = "[%s]:%d (%d)"
			}
			entry = fmt.Sprintf(fmtStr, backend.GetAddress(),
				backend.GetPort(), revNATID)
		}

		serviceList[svc] = append(serviceList[svc], entry)
	}

	if err := lbmap.Service4MapV2.DumpWithCallbackIfExists(parseSVCEntry); err != nil {
		Fatalf("Unable to dump IPv4 services table: %s", err)
	}
	if err := lbmap.Service6MapV2.DumpWithCallbackIfExists(parseSVCEntry); err != nil {
		Fatalf("Unable to dump IPv6 services table: %s", err)
	}
}

func dumpLegacySVC(serviceList map[string][]string) {
	if err := lbmap.Service4Map.DumpIfExists(serviceList); err != nil {
		Fatalf("Unable to dump IPv4 services table: %s", err)
	}
	if err := lbmap.Service6Map.DumpIfExists(serviceList); err != nil {
		Fatalf("Unable to dump IPv6 services table: %s", err)
	}
}

// bpfCtListCmd represents the bpf_ct_list command
var bpfLBListCmd = &cobra.Command{
	Use:     "list",
	Aliases: []string{"ls"},
	Short:   "List load-balancing configuration",
	Run: func(cmd *cobra.Command, args []string) {
		common.RequireRootPrivilege("cilium bpf lb list")

		var firstTitle string
		serviceList := make(map[string][]string)
		switch {
		case listRevNAT:
			firstTitle = idTitle
			dumpRevNat(serviceList)
		case listLegacy:
			firstTitle = serviceAddressTitle
			dumpLegacySVC(serviceList)
		default:
			firstTitle = serviceAddressTitle
			dumpSVC(serviceList)
		}

		if command.OutputJSON() {
			if err := command.PrintOutput(serviceList); err != nil {
				Fatalf("Unable to generate JSON output: %s", err)
			}
			return
		}

		TablePrinter(firstTitle, backendAddressTitle, serviceList)
	},
}

func init() {
	bpfLBCmd.AddCommand(bpfLBListCmd)
	bpfLBListCmd.Flags().BoolVarP(&listRevNAT, "revnat", "", false, "List reverse NAT entries")
	bpfLBListCmd.Flags().BoolVarP(&listLegacy, "legacy", "", false, "List legacy service entries")
	command.AddJSONOutput(bpfLBListCmd)
}
<|endoftext|>


<commit_before>package helpers

import (
	"errors"
	"koding/db/mongodb"
	"koding/db/mongodb/modelhelper"
	"koding/tools/logger"

	"labix.org/v2/mgo"
)

type iterOptions struct {
	// Starting offset
	Skip int

	// Ending point, iter count
	Limit int

	// Filter for limiting the result set
	Filter modelhelper.Selector

	// Iteration collection
	CollectionName string

	// Iteration function, all results will be passed to this function
	F func(result interface{})

	// Sometimes iteration can timeout, this is retry count
	RetryCount int

	// Data object itself for marshalling the result
	DataType interface{}

	// logger for iteration
	Log logger.Log
}

// NewIterOptions Sets the default values for iterOptions
func NewIterOptions() *iterOptions {
	return &iterOptions{
		Skip:       0,
		Limit:      1000,
		Filter:     modelhelper.Selector{},
		RetryCount: 50,
		Log:        logger.New("Iter"),
	}
}

// Iter accepts mongo and iterOptions and runs the query
func Iter(mongo *mongodb.MongoDB, iterOptions *iterOptions) error {
	if iterOptions.CollectionName == "" {
		return errors.New("Collection name is not set")
	}

	if iterOptions.F == nil {
		return errors.New("Iteration function is not given")
	}
	if iterOptions.DataType == nil {
		return errors.New("Datatype is not given")
	}

	return mongo.Run("jAccounts", createQuery(iterOptions))
}

// createQuery creates mongo query for iteration
func createQuery(iterOptions *iterOptions) func(coll *mgo.Collection) error {
	return func(coll *mgo.Collection) error {
		// find the total count
		query := coll.Find(iterOptions.Filter)
		totalCount, err := query.Count()
		if err != nil {
			iterOptions.Log.Error("While getting count, exiting: %v", err)
			return err
		}
		iterOptions.Log.Info("Totaly we have %v items for operation", totalCount)

		skip := iterOptions.Skip
		// this is a starting point
		index := skip
		// this is the item count to be processed
		limit := iterOptions.Limit
		// this will be the ending point
		count := index + limit

		iteration := 0
		for {
			// if we reach to the end of the all collection, exit
			if index >= totalCount {
				iterOptions.Log.Info("All items are processed, exiting")
				break
			}

			// this is the max re-iterating count
			if iteration == iterOptions.RetryCount {
				break
			}

			// if we processed all items then exit
			if index == count {
				break
			}

			iter := query.Skip(index).Limit(count - index).Iter()

			for iter.Next(iterOptions.DataType) {
				iterOptions.F(iterOptions.DataType)
				index++
				iterOptions.Log.Debug("Index: %v", index)
			}

			if err := iter.Close(); err != nil {
				iterOptions.Log.Error("Iteration failed: %v", err)
			}

			if iter.Timeout() {
				continue
			}

			iterOptions.Log.Info("iter existed, starting over from %v  -- %v  item(s) are processsed on this iter", index+1, index-skip)
			iteration++
		}

		if iteration == iterOptions.RetryCount {
			iterOptions.Log.Info("Max iteration count %v reached, exiting", iteration)
		}
		iterOptions.Log.Info("Deleted %v guest accounts on this process", index-skip)

		return nil
	}
}
<commit_msg>MongoHelper: add doc<commit_after>package helpers

import (
	"errors"
	"koding/db/mongodb"
	"koding/db/mongodb/modelhelper"
	"koding/tools/logger"

	"labix.org/v2/mgo"
)

// iterOptions holds the related config paramters for Iter operation
type iterOptions struct {
	// Starting offset
	Skip int

	// Ending point, iter count
	Limit int

	// Filter for limiting the result set
	Filter modelhelper.Selector

	// Iteration collection
	CollectionName string

	// Iteration function, all results will be passed to this function
	F func(result interface{})

	// Sometimes iteration can timeout, this is retry count
	RetryCount int

	// Data object itself for marshalling the result
	DataType interface{}

	// logger for iteration
	Log logger.Log
}

// NewIterOptions Sets the default values for iterOptions
func NewIterOptions() *iterOptions {
	return &iterOptions{
		Skip:       0,
		Limit:      1000,
		Filter:     modelhelper.Selector{},
		RetryCount: 50,
		Log:        logger.New("Iter"),
	}
}

// Iter accepts mongo and iterOptions and runs the query
func Iter(mongo *mongodb.MongoDB, iterOptions *iterOptions) error {
	if iterOptions.CollectionName == "" {
		return errors.New("Collection name is not set")
	}

	if iterOptions.F == nil {
		return errors.New("Iteration function is not given")
	}
	if iterOptions.DataType == nil {
		return errors.New("Datatype is not given")
	}

	return mongo.Run("jAccounts", createQuery(iterOptions))
}

// createQuery creates mongo query for iteration
func createQuery(iterOptions *iterOptions) func(coll *mgo.Collection) error {
	return func(coll *mgo.Collection) error {
		// find the total count
		query := coll.Find(iterOptions.Filter)
		totalCount, err := query.Count()
		if err != nil {
			iterOptions.Log.Error("While getting count, exiting: %v", err)
			return err
		}
		iterOptions.Log.Info("Totaly we have %v items for operation", totalCount)

		skip := iterOptions.Skip
		// this is a starting point
		index := skip
		// this is the item count to be processed
		limit := iterOptions.Limit
		// this will be the ending point
		count := index + limit

		iteration := 0
		for {
			// if we reach to the end of the all collection, exit
			if index >= totalCount {
				iterOptions.Log.Info("All items are processed, exiting")
				break
			}

			// this is the max re-iterating count
			if iteration == iterOptions.RetryCount {
				break
			}

			// if we processed all items then exit
			if index == count {
				break
			}

			iter := query.Skip(index).Limit(count - index).Iter()

			for iter.Next(iterOptions.DataType) {
				iterOptions.F(iterOptions.DataType)
				index++
				iterOptions.Log.Debug("Index: %v", index)
			}

			if err := iter.Close(); err != nil {
				iterOptions.Log.Error("Iteration failed: %v", err)
			}

			if iter.Timeout() {
				continue
			}

			iterOptions.Log.Info("iter existed, starting over from %v  -- %v  item(s) are processsed on this iter", index+1, index-skip)
			iteration++
		}

		if iteration == iterOptions.RetryCount {
			iterOptions.Log.Info("Max iteration count %v reached, exiting", iteration)
		}
		iterOptions.Log.Info("Deleted %v guest accounts on this process", index-skip)

		return nil
	}
}
<|endoftext|>


<commit_before>package worker

import (
	"github.com/youtube/vitess/go/sqltypes"

	querypb "github.com/youtube/vitess/go/vt/proto/query"
)

// ResultReader is an advanced version of sqltypes.ResultStream.
// In addition to the streamed Result messages (which contain a set of rows),
// it will expose the Fields (columns information) of the result separately.
type ResultReader interface {
	// Fields returns the field information for the columns in the result.
	Fields() []*querypb.Field

	// Next is identical to sqltypes.ResultStream.Recv().
	// It returns the next result on the stream.
	// It will return io.EOF if the stream ended.
	Next() (*sqltypes.Result, error)
}
<commit_msg>worker: Clarify that ResultReader implementations must be referred by their pointer type.<commit_after>package worker

import (
	"github.com/youtube/vitess/go/sqltypes"

	querypb "github.com/youtube/vitess/go/vt/proto/query"
)

// ResultReader is an advanced version of sqltypes.ResultStream.
// In addition to the streamed Result messages (which contain a set of rows),
// it will expose the Fields (columns information) of the result separately.
//
// Note that some code in the worker package checks if instances of ResultReader
// are equal. In consequence, any ResultReader implementation must always use
// pointer receivers. This way, implementations are always referred by their
// pointer type and the equal comparison of ResultReader instances behaves as
// expected.
type ResultReader interface {
	// Fields returns the field information for the columns in the result.
	Fields() []*querypb.Field

	// Next is identical to sqltypes.ResultStream.Recv().
	// It returns the next result on the stream.
	// It will return io.EOF if the stream ended.
	Next() (*sqltypes.Result, error)
}
<|endoftext|>


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

package ml

import (
	"github.com/cpmech/gosl/la"
)

// LinReg implements functions to perform linear regression
type LinReg struct {
	e la.Vector // error = l - y
}

// NewLinReg returns new LinReg object
func NewLinReg() (o *LinReg) {
	o = new(LinReg)
	return
}

// Model implements the model equation: xᵀθ
//   x -- [nFeatures] x-values
//   θ -- [1+nFeatures] parameters
func (o *LinReg) Model(x, θ la.Vector) float64 {
	return θ[0] + la.VecDot(x, θ[1:])
}

// Cost computes the total cost
func (o *LinReg) Cost(data *RegData) float64 {
	if len(o.e) != data.m {
		o.e = la.NewVector(data.m)
	}
	la.MatVecMul(data.l, 1, data.x, data.θ)
	la.VecAdd(o.e, 1, data.l, -1, data.y)
	return la.VecDot(o.e, o.e) / float64(2*data.m)
}

// Deriv computes the derivative of the cost function: dC/dθ
//   Input:
//     data -- regression data
//   Output:
//     dCdθ -- derivative of cost function
func (o *LinReg) Deriv(dCdθ la.Vector, data *RegData) {
	if len(o.e) != data.m {
		o.e = la.NewVector(data.m)
	}
	la.MatVecMul(data.l, 1, data.x, data.θ)
	la.VecAdd(o.e, 1, data.l, -1, data.y)
	la.MatTrVecMul(dCdθ, 1.0/float64(data.m), data.x, o.e)
}

// CalcTheta calculates θ using anlalytical solution
//   Solve:  XᵀX θ = Xᵀy
func (o *LinReg) CalcTheta(data *RegData) {
	XtX := la.NewMatrix(data.n, data.n)
	la.MatTrMatMul(XtX, 1, data.x, data.x)
	b := la.NewVector(data.n)
	la.MatTrVecMul(b, 1, data.x, data.y)
	la.DenSolve(data.θ, XtX, b, false)
}
<commit_msg>Fix typo<commit_after>// Copyright 2016 The Gosl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ml

import (
	"github.com/cpmech/gosl/la"
)

// LinReg implements functions to perform linear regression
type LinReg struct {
	e la.Vector // error = l - y
}

// NewLinReg returns new LinReg object
func NewLinReg() (o *LinReg) {
	o = new(LinReg)
	return
}

// Model implements the model equation: xᵀθ
//   x -- [nFeatures] x-values
//   θ -- [1+nFeatures] parameters
func (o *LinReg) Model(x, θ la.Vector) float64 {
	return θ[0] + la.VecDot(x, θ[1:])
}

// Cost computes the total cost
func (o *LinReg) Cost(data *RegData) float64 {
	if len(o.e) != data.m {
		o.e = la.NewVector(data.m)
	}
	la.MatVecMul(data.l, 1, data.x, data.θ)
	la.VecAdd(o.e, 1, data.l, -1, data.y)
	return la.VecDot(o.e, o.e) / float64(2*data.m)
}

// Deriv computes the derivative of the cost function: dC/dθ
//   Input:
//     data -- regression data
//   Output:
//     dCdθ -- derivative of cost function
func (o *LinReg) Deriv(dCdθ la.Vector, data *RegData) {
	if len(o.e) != data.m {
		o.e = la.NewVector(data.m)
	}
	la.MatVecMul(data.l, 1, data.x, data.θ)
	la.VecAdd(o.e, 1, data.l, -1, data.y)
	la.MatTrVecMul(dCdθ, 1.0/float64(data.m), data.x, o.e)
}

// CalcTheta calculates θ using the analytical solution
//   Solve:  XᵀX θ = Xᵀy
//   TODO: handle pseudo-inverse cases
func (o *LinReg) CalcTheta(data *RegData) {
	XtX := la.NewMatrix(data.n, data.n)
	la.MatTrMatMul(XtX, 1, data.x, data.x)
	b := la.NewVector(data.n)
	la.MatTrVecMul(b, 1, data.x, data.y)
	la.DenSolve(data.θ, XtX, b, false)
}
<|endoftext|>


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

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"path/filepath"
	"strings"
	"testing"
	"testing/quick"

	"github.com/googlecodelabs/tools/claat/render"
	"github.com/googlecodelabs/tools/claat/types"

	_ "github.com/googlecodelabs/tools/claat/parser/gdoc" // Explicitly register gdoc parser
)

type testTransport struct {
	roundTripper func(*http.Request) (*http.Response, error)
}

func (tt *testTransport) RoundTrip(r *http.Request) (*http.Response, error) {
	return tt.roundTripper(r)
}

func TestFetchRemote(t *testing.T) {
	const filename = "/file.txt"
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "GET" {
			t.Errorf("r.Method = %q; want GET", r.Method)
		}
		if r.URL.Path != filename {
			t.Errorf("r.URL.Path = %q; want %q", r.URL.Path, filename)
		}
		w.Write([]byte("test"))
	}))
	defer ts.Close()

	f, err := NewFetcher("", map[string]bool{}, nil)
	if err != nil {
		t.Fatal(err)
	}

	res, err := f.fetchRemote(ts.URL+filename, false)
	if err != nil {
		t.Fatal(err)
	}
	defer res.body.Close()
	if res.typ != SrcMarkdown {
		t.Errorf("typ = %q; want %q", res.typ, SrcMarkdown)
	}
	b, _ := ioutil.ReadAll(res.body)
	if s := string(b); s != "test" {
		t.Errorf("res = %q; want 'test'", s)
	}
}

func TestFetchRemoteDrive(t *testing.T) {
	const driveHost = "http://dummy"
	rt := &testTransport{func(r *http.Request) (*http.Response, error) {
		if r.Method != "GET" {
			t.Errorf("r.Method = %q; want GET", r.Method)
		}
		// metadata request
		if strings.HasSuffix(r.URL.Path, "/files/doc-123") {
			if v := r.FormValue("supportsTeamDrives"); v != "true" {
				t.Errorf("supportsTeamDrives = %q; want 'true'", v)
			}
			b := ioutil.NopCloser(strings.NewReader(`{
				"mimeType": "application/vnd.google-apps.document"
			}`))
			return &http.Response{Body: b, StatusCode: http.StatusOK}, nil
		}
		// export request
		if !strings.HasSuffix(r.URL.Path, "/doc-123/export") {
			t.Errorf("r.URL.Path = %q; want /doc-123/export suffix", r.URL.Path)
		}
		b := ioutil.NopCloser(strings.NewReader("test"))
		return &http.Response{Body: b, StatusCode: http.StatusOK}, nil
	}}

	f, err := NewFetcher("", map[string]bool{}, rt)
	if err != nil {
		t.Fatal(err)
	}

	res, err := f.fetchRemote("doc-123", false)
	if err != nil {
		t.Fatal(err)
	}
	defer res.body.Close()
	if res.typ != SrcGoogleDoc {
		t.Errorf("typ = %q; want %q", res.typ, SrcGoogleDoc)
	}
	b, _ := ioutil.ReadAll(res.body)
	if s := string(b); s != "test" {
		t.Errorf("res = %q; want 'test'", s)
	}
}

func TestSlurpWithFragment(t *testing.T) {
	dochtml, err := ioutil.ReadFile("testdata/gdoc.html")
	if err != nil {
		t.Fatal(err)
	}
	rt := &testTransport{func(r *http.Request) (*http.Response, error) {
		// metadata request
		if r.URL.Path == "/drive/v3/files/doc-123" {
			b := ioutil.NopCloser(strings.NewReader(`{
				"mimeType": "application/vnd.google-apps.document"
			}`))
			return &http.Response{Body: b, StatusCode: http.StatusOK}, nil
		}
		// main doc export request
		if r.URL.Path == "/drive/v3/files/doc-123/export" {
			b := ioutil.NopCloser(bytes.NewReader(dochtml))
			return &http.Response{Body: b, StatusCode: http.StatusOK}, nil
		}
		// import doc request, referenced in testdata/gdoc.html
		if r.URL.Path == "/drive/v3/files/import/export" {
			b := ioutil.NopCloser(strings.NewReader(`

I'm imported from elsewhere.

			`))
			return &http.Response{Body: b, StatusCode: http.StatusOK}, nil
		}
		return &http.Response{
			Body:       ioutil.NopCloser(strings.NewReader(r.URL.String())),
			StatusCode: http.StatusBadRequest,
		}, nil
	}}

	f, err := NewFetcher("", map[string]bool{}, rt)
	if err != nil {
		t.Fatal(err)
	}

	clab, err := f.SlurpCodelab("doc-123")
	if err != nil {
		t.Fatal(err)
	}
	var node *types.ImportNode
	for _, st := range clab.Steps {
		for _, n := range st.Content.Nodes {
			if n.Type() == types.NodeImport {
				node = n.(*types.ImportNode)
				break
			}
		}
	}
	if node == nil {
		t.Fatal("no import node found")
	}
	html, err := render.HTML("", node.Content)
	if err != nil {
		t.Fatal(err)
	}
	want := "imported from elsewhere"
	if !strings.Contains(string(html), want) {
		t.Errorf("%s does not contain %q", html, want)
	}
}

func TestGdocID(t *testing.T) {
	tests := []struct{ in, out string }{
		{"https://docs.google.com/document/d/foo", "foo"},
		{"https://docs.google.com/document/d/foo/edit", "foo"},
		{"https://docs.google.com/document/d/foo/edit#abc", "foo"},
		{"https://docs.google.com/document/d/foo/edit?bar=baz#abc", "foo"},
		{"foo", "foo"},
	}
	for i, test := range tests {
		out := gdocID(test.in)
		if out != test.out {
			t.Errorf("%d: gdocID(%q) = %q; want %q", i, test.in, out, test.out)
		}
	}
}

func TestRestrictPathToParent(t *testing.T) {
	tests := []struct {
		asset  string
		parent string

		wantPath string
		wantErr  bool
	}{
		{"imgroot.png", ".", "imgroot.png", false},
		{"imgroot.png", "foo/", "foo/imgroot.png", false},
		{"img/sub.png", "foo/", "foo/img/sub.png", false},
		{"imgroot.png", "/tmp/foo", "/tmp/foo/imgroot.png", false},
		{"/tmp/imgabs.png", "foo/", "", true},
		{"../imgup.png", "foo/", "", true},
		{"../imgup.png", "..", "", true},
		{"imgroot.png", "", "imgroot.png", false},
		{"", ".", ".", false},
		{"", "", ".", false},
	}
	for _, tc := range tests {
		t.Run(fmt.Sprintf("asset: %s, parent: %s", tc.asset, tc.parent), func(t *testing.T) {
			tc.wantPath = safeAbs(t, tc.wantPath)

			p, err := restrictPathToParent(tc.asset, tc.parent)

			if err != nil != tc.wantErr {
				t.Errorf("restrictPathToParent() error = %v, wantErr %v", err, tc.wantErr)
				return
			}
			if p != tc.wantPath {
				t.Errorf("restrictPathToParent() return: got %s, wanted %s", p, tc.wantPath)
			}
		})
	}
}

func TestFuzzRestrictPathToParent(t *testing.T) {
	checkInParent := func(elem, parent string) bool {
		_, err := restrictPathToParent(elem, parent)

		parent = safeAbs(t, parent)
		if !strings.HasPrefix(elem, "/") {
			elem = filepath.Join(parent, elem)
		}
		shouldOk := strings.HasPrefix(elem, parent)
		return shouldOk == (err == nil)
	}

	if err := quick.Check(checkInParent, nil); err != nil {
		t.Error(err)
	}
}

// safeAbs compute Abs of p and fail the test if not valid.
// Empty string return empty path.
func safeAbs(t *testing.T, p string) string {
	if p == "" {
		return p
	}
	p, err := filepath.Abs(p)
	if err != nil {
		t.Fatalf("Error in converting %s to abs path: %v", p, err)
	}
	return p
}
<commit_msg>Remove non-hermetic test cases from fetch_test.<commit_after>// Copyright 2016-2019 Google LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fetch

import (
	"fmt"
	"net/http"
	"path/filepath"
	"strings"
	"testing"
	"testing/quick"

	_ "github.com/googlecodelabs/tools/claat/parser/gdoc" // Explicitly register gdoc parser
)

type testTransport struct {
	roundTripper func(*http.Request) (*http.Response, error)
}

func (tt *testTransport) RoundTrip(r *http.Request) (*http.Response, error) {
	return tt.roundTripper(r)
}

func TestGdocID(t *testing.T) {
	tests := []struct{ in, out string }{
		{"https://docs.google.com/document/d/foo", "foo"},
		{"https://docs.google.com/document/d/foo/edit", "foo"},
		{"https://docs.google.com/document/d/foo/edit#abc", "foo"},
		{"https://docs.google.com/document/d/foo/edit?bar=baz#abc", "foo"},
		{"foo", "foo"},
	}
	for i, test := range tests {
		out := gdocID(test.in)
		if out != test.out {
			t.Errorf("%d: gdocID(%q) = %q; want %q", i, test.in, out, test.out)
		}
	}
}

func TestRestrictPathToParent(t *testing.T) {
	tests := []struct {
		asset  string
		parent string

		wantPath string
		wantErr  bool
	}{
		{"imgroot.png", ".", "imgroot.png", false},
		{"imgroot.png", "foo/", "foo/imgroot.png", false},
		{"img/sub.png", "foo/", "foo/img/sub.png", false},
		{"imgroot.png", "/tmp/foo", "/tmp/foo/imgroot.png", false},
		{"/tmp/imgabs.png", "foo/", "", true},
		{"../imgup.png", "foo/", "", true},
		{"../imgup.png", "..", "", true},
		{"imgroot.png", "", "imgroot.png", false},
		{"", ".", ".", false},
		{"", "", ".", false},
	}
	for _, tc := range tests {
		t.Run(fmt.Sprintf("asset: %s, parent: %s", tc.asset, tc.parent), func(t *testing.T) {
			tc.wantPath = safeAbs(t, tc.wantPath)

			p, err := restrictPathToParent(tc.asset, tc.parent)

			if err != nil != tc.wantErr {
				t.Errorf("restrictPathToParent() error = %v, wantErr %v", err, tc.wantErr)
				return
			}
			if p != tc.wantPath {
				t.Errorf("restrictPathToParent() return: got %s, wanted %s", p, tc.wantPath)
			}
		})
	}
}

func TestFuzzRestrictPathToParent(t *testing.T) {
	checkInParent := func(elem, parent string) bool {
		_, err := restrictPathToParent(elem, parent)

		parent = safeAbs(t, parent)
		if !strings.HasPrefix(elem, "/") {
			elem = filepath.Join(parent, elem)
		}
		shouldOk := strings.HasPrefix(elem, parent)
		return shouldOk == (err == nil)
	}

	if err := quick.Check(checkInParent, nil); err != nil {
		t.Error(err)
	}
}

// safeAbs compute Abs of p and fail the test if not valid.
// Empty string return empty path.
func safeAbs(t *testing.T, p string) string {
	if p == "" {
		return p
	}
	p, err := filepath.Abs(p)
	if err != nil {
		t.Fatalf("Error in converting %s to abs path: %v", p, err)
	}
	return p
}
<|endoftext|>


<commit_before>package trust

import (
	"fmt"
	"path"
	"sort"
	"strings"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/command/image"
	"github.com/docker/cli/cli/trust"
	"github.com/docker/notary/client"
	"github.com/docker/notary/tuf/data"
	"github.com/spf13/cobra"
)

func newSignCommand(dockerCli command.Cli) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "sign [OPTIONS] IMAGE:TAG",
		Short: "Sign an image",
		Args:  cli.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return signImage(dockerCli, args[0])
		},
	}
	return cmd
}

func signImage(cli command.Cli, imageName string) error {
	ctx, ref, repoInfo, authConfig, err := getImageReferencesAndAuth(cli, imageName)
	if err != nil {
		return err
	}

	notaryRepo, err := trust.GetNotaryRepository(cli, repoInfo, *authConfig, "push", "pull")
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}
	tag, err := getTag(ref)
	if err != nil {
		return err
	}
	if tag == "" {
		return fmt.Errorf("No tag specified for %s", imageName)
	}
	fmt.Fprintf(cli.Out(), "Signing and pushing trust metadata for %s\n", imageName)

	// get the latest repository metadata so we can figure out which roles to sign
	if err = notaryRepo.Update(false); err != nil {
		switch err.(type) {
		case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
			// before initializing a new repo, check that the image exists locally:
			if err := checkLocalImageExistence(ctx, cli, imageName); err != nil {
				return err
			}

			userRole := data.RoleName(path.Join(data.CanonicalTargetsRole.String(), authConfig.Username))
			if err := initNotaryRepoWithSigners(notaryRepo, userRole); err != nil {
				return trust.NotaryError(ref.Name(), err)
			}

			fmt.Fprintf(cli.Out(), "Created signer: %s\n", authConfig.Username)
			fmt.Fprintf(cli.Out(), "Finished initializing %q\n", notaryRepo.GetGUN().String())
		default:
			return trust.NotaryError(repoInfo.Name.Name(), err)
		}
	}
	requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, repoInfo.Index, "push")
	target, err := createTarget(notaryRepo, tag)
	if err != nil && strings.Contains(err.Error(), "No valid trust data for") {
		return image.TrustedPush(ctx, cli, repoInfo, ref, *authConfig, requestPrivilege)
	} else if err != nil {
		return err
	}
	otherSigners, err := getOtherSigners(notaryRepo, tag)
	if err != nil {
		return err
	}
	printOtherSigners(otherSigners)
	err = image.AddTargetToAllSignableRoles(notaryRepo, &target)
	if err == nil {
		err = notaryRepo.Publish()
	}
	if err != nil {
		fmt.Fprintf(cli.Out(), "Failed to sign %q:%s - %s\n", repoInfo.Name.Name(), tag, err.Error())
		return trust.NotaryError(repoInfo.Name.Name(), err)
	}
	fmt.Fprintf(cli.Out(), "Successfully signed %q:%s\n", repoInfo.Name.Name(), tag)
	return nil
}

func createTarget(notaryRepo *client.NotaryRepository, tag string) (client.Target, error) {
	target := &client.Target{}
	var err error
	if tag == "" {
		return *target, fmt.Errorf("No tag specified")
	}
	target.Name = tag
	target.Hashes, target.Length, err = getSignedManifestHashAndSize(notaryRepo, tag)
	return *target, err
}

func getSignedManifestHashAndSize(notaryRepo *client.NotaryRepository, tag string) (data.Hashes, int64, error) {
	targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
	if err != nil {
		return nil, 0, err
	}
	for _, tgt := range targets {
		if isReleasedTarget(tgt.Role.Name) {
			return tgt.Target.Hashes, tgt.Target.Length, nil
		}
	}
	return nil, 0, fmt.Errorf("No valid trust data for %s", tag)
}

func getOtherSigners(notaryRepo *client.NotaryRepository, tag string) ([]string, error) {
	targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
	var signers []string
	if err != nil {
		return nil, err
	}
	for _, tgt := range targets {
		if !isReleasedTarget(tgt.Role.Name) {
			signers = append(signers, notaryRoleToSigner(tgt.Role.Name))
		}
	}
	return signers, err
}

func printOtherSigners(otherSigners []string) {
	if len(otherSigners) != 0 {
		fmt.Println("Other signers of this tag:")
		fmt.Println(strings.Join(otherSigners, ", "))
	}
}

func initNotaryRepoWithSigners(notaryRepo *client.NotaryRepository, newSigner data.RoleName) error {
	rootKey, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
	if err != nil {
		return err
	}
	rootKeyID := rootKey.ID()

	// Initialize the notary repository with a remotely managed snapshot key
	if err := notaryRepo.Initialize([]string{rootKeyID}, data.CanonicalSnapshotRole); err != nil {
		return err
	}

	signerKey, err := getOrGenerateNotaryKey(notaryRepo, newSigner)
	if err != nil {
		return err
	}
	addStagedSigner(notaryRepo, newSigner, []data.PublicKey{signerKey})

	return notaryRepo.Publish()
}

// generates an ECDSA key without a GUN for the specified role
func getOrGenerateNotaryKey(notaryRepo *client.NotaryRepository, role data.RoleName) (data.PublicKey, error) {
	keys := notaryRepo.CryptoService.ListKeys(role)
	var err error
	var key data.PublicKey
	// always select the first key by ID
	if len(keys) > 0 {
		sort.Strings(keys)
		keyID := keys[0]
		privKey, _, err := notaryRepo.CryptoService.GetPrivateKey(keyID)
		if err != nil {
			return nil, err
		}
		key = data.PublicKeyFromPrivate(privKey)
	} else {
		key, err = notaryRepo.CryptoService.Create(role, "", data.ECDSAKey)
		if err != nil {
			return nil, err
		}
	}
	return key, nil
}

// stages changes to add a signer with the specified name and key(s).  Adds to targets/<name> and targets/releases
func addStagedSigner(notaryRepo *client.NotaryRepository, newSigner data.RoleName, signerKeys []data.PublicKey) {
	// create targets/<username>
	notaryRepo.AddDelegationRoleAndKeys(newSigner, signerKeys)
	notaryRepo.AddDelegationPaths(newSigner, []string{""})

	// create targets/releases
	notaryRepo.AddDelegationRoleAndKeys(trust.ReleasesRole, signerKeys)
	notaryRepo.AddDelegationPaths(trust.ReleasesRole, []string{""})
}
<commit_msg>use signer name for cryptoservice key generation and lookup<commit_after>package trust

import (
	"fmt"
	"path"
	"sort"
	"strings"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/command/image"
	"github.com/docker/cli/cli/trust"
	"github.com/docker/notary/client"
	"github.com/docker/notary/tuf/data"
	"github.com/spf13/cobra"
)

func newSignCommand(dockerCli command.Cli) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "sign [OPTIONS] IMAGE:TAG",
		Short: "Sign an image",
		Args:  cli.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return signImage(dockerCli, args[0])
		},
	}
	return cmd
}

func signImage(cli command.Cli, imageName string) error {
	ctx, ref, repoInfo, authConfig, err := getImageReferencesAndAuth(cli, imageName)
	if err != nil {
		return err
	}

	notaryRepo, err := trust.GetNotaryRepository(cli, repoInfo, *authConfig, "push", "pull")
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}
	tag, err := getTag(ref)
	if err != nil {
		return err
	}
	if tag == "" {
		return fmt.Errorf("No tag specified for %s", imageName)
	}
	fmt.Fprintf(cli.Out(), "Signing and pushing trust metadata for %s\n", imageName)

	// get the latest repository metadata so we can figure out which roles to sign
	if err = notaryRepo.Update(false); err != nil {
		switch err.(type) {
		case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
			// before initializing a new repo, check that the image exists locally:
			if err := checkLocalImageExistence(ctx, cli, imageName); err != nil {
				return err
			}

			userRole := data.RoleName(path.Join(data.CanonicalTargetsRole.String(), authConfig.Username))
			if err := initNotaryRepoWithSigners(notaryRepo, userRole); err != nil {
				return trust.NotaryError(ref.Name(), err)
			}

			fmt.Fprintf(cli.Out(), "Created signer: %s\n", authConfig.Username)
			fmt.Fprintf(cli.Out(), "Finished initializing %q\n", notaryRepo.GetGUN().String())
		default:
			return trust.NotaryError(repoInfo.Name.Name(), err)
		}
	}
	requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, repoInfo.Index, "push")
	target, err := createTarget(notaryRepo, tag)
	if err != nil && strings.Contains(err.Error(), "No valid trust data for") {
		return image.TrustedPush(ctx, cli, repoInfo, ref, *authConfig, requestPrivilege)
	} else if err != nil {
		return err
	}
	otherSigners, err := getOtherSigners(notaryRepo, tag)
	if err != nil {
		return err
	}
	printOtherSigners(otherSigners)
	err = image.AddTargetToAllSignableRoles(notaryRepo, &target)
	if err == nil {
		err = notaryRepo.Publish()
	}
	if err != nil {
		fmt.Fprintf(cli.Out(), "Failed to sign %q:%s - %s\n", repoInfo.Name.Name(), tag, err.Error())
		return trust.NotaryError(repoInfo.Name.Name(), err)
	}
	fmt.Fprintf(cli.Out(), "Successfully signed %q:%s\n", repoInfo.Name.Name(), tag)
	return nil
}

func createTarget(notaryRepo *client.NotaryRepository, tag string) (client.Target, error) {
	target := &client.Target{}
	var err error
	if tag == "" {
		return *target, fmt.Errorf("No tag specified")
	}
	target.Name = tag
	target.Hashes, target.Length, err = getSignedManifestHashAndSize(notaryRepo, tag)
	return *target, err
}

func getSignedManifestHashAndSize(notaryRepo *client.NotaryRepository, tag string) (data.Hashes, int64, error) {
	targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
	if err != nil {
		return nil, 0, err
	}
	for _, tgt := range targets {
		if isReleasedTarget(tgt.Role.Name) {
			return tgt.Target.Hashes, tgt.Target.Length, nil
		}
	}
	return nil, 0, fmt.Errorf("No valid trust data for %s", tag)
}

func getOtherSigners(notaryRepo *client.NotaryRepository, tag string) ([]string, error) {
	targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
	var signers []string
	if err != nil {
		return nil, err
	}
	for _, tgt := range targets {
		if !isReleasedTarget(tgt.Role.Name) {
			signers = append(signers, notaryRoleToSigner(tgt.Role.Name))
		}
	}
	return signers, err
}

func printOtherSigners(otherSigners []string) {
	if len(otherSigners) != 0 {
		fmt.Println("Other signers of this tag:")
		fmt.Println(strings.Join(otherSigners, ", "))
	}
}

func initNotaryRepoWithSigners(notaryRepo *client.NotaryRepository, newSigner data.RoleName) error {
	rootKey, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
	if err != nil {
		return err
	}
	rootKeyID := rootKey.ID()

	// Initialize the notary repository with a remotely managed snapshot key
	if err := notaryRepo.Initialize([]string{rootKeyID}, data.CanonicalSnapshotRole); err != nil {
		return err
	}

	signerKey, err := getOrGenerateNotaryKey(notaryRepo, newSigner)
	if err != nil {
		return err
	}
	addStagedSigner(notaryRepo, newSigner, []data.PublicKey{signerKey})

	return notaryRepo.Publish()
}

// generates an ECDSA key without a GUN for the specified role
func getOrGenerateNotaryKey(notaryRepo *client.NotaryRepository, role data.RoleName) (data.PublicKey, error) {
	// use the signer name in the PEM headers if this is a delegation key
	if data.IsDelegation(role) {
		role = data.RoleName(notaryRoleToSigner(role))
	}
	keys := notaryRepo.CryptoService.ListKeys(role)
	var err error
	var key data.PublicKey
	// always select the first key by ID
	if len(keys) > 0 {
		sort.Strings(keys)
		keyID := keys[0]
		privKey, _, err := notaryRepo.CryptoService.GetPrivateKey(keyID)
		if err != nil {
			return nil, err
		}
		key = data.PublicKeyFromPrivate(privKey)
	} else {
		key, err = notaryRepo.CryptoService.Create(role, "", data.ECDSAKey)
		if err != nil {
			return nil, err
		}
	}
	return key, nil
}

// stages changes to add a signer with the specified name and key(s).  Adds to targets/<name> and targets/releases
func addStagedSigner(notaryRepo *client.NotaryRepository, newSigner data.RoleName, signerKeys []data.PublicKey) {
	// create targets/<username>
	notaryRepo.AddDelegationRoleAndKeys(newSigner, signerKeys)
	notaryRepo.AddDelegationPaths(newSigner, []string{""})

	// create targets/releases
	notaryRepo.AddDelegationRoleAndKeys(trust.ReleasesRole, signerKeys)
	notaryRepo.AddDelegationPaths(trust.ReleasesRole, []string{""})
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package mungers

import (
	"path"
	"strings"

	"k8s.io/contrib/mungegithub/features"
	"k8s.io/contrib/mungegithub/github"
	"k8s.io/contrib/mungegithub/mungers/mungerutil"
	"k8s.io/kubernetes/pkg/util/sets"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
)

const maxDepth = 3

// ApprovalHandler will try to add "approved" label once
// all files of change has been approved by approvers.
type ApprovalHandler struct {
	features *features.Features
}

func init() {
	h := &ApprovalHandler{}
	RegisterMungerOrDie(h)
}

// Name is the name usable in --pr-mungers
func (*ApprovalHandler) Name() string { return "approval-handler" }

// RequiredFeatures is a slice of 'features' that must be provided
func (*ApprovalHandler) RequiredFeatures() []string {
	return []string{features.RepoFeatureName, features.AliasesFeature}
}

// Initialize will initialize the munger
func (h *ApprovalHandler) Initialize(config *github.Config, features *features.Features) error {
	h.features = features
	return nil
}

// EachLoop is called at the start of every munge loop
func (*ApprovalHandler) EachLoop() error { return nil }

// AddFlags will add any request flags to the cobra `cmd`
func (*ApprovalHandler) AddFlags(cmd *cobra.Command, config *github.Config) {}

// Munge is the workhorse the will actually make updates to the PR
// The algorithm goes as:
// - Initially, we set up approverMap
//   - Go through all comments after latest commit. If any approver said "/approve", add him to approverMap.
// - For each file, we see if any approver of this file is in approverMap.
//   - An approver of a file is defined as:
//     - It's known that each dir has a list of approvers. (This might not hold true. For usability, current situation is enough.)
//     - Approver of a dir is also the approver of child dirs.
//   - We look at top N (default 3) level dir approvers. For example, for file "/a/b/c/d/e", we might search for approver from
//     "/", "/a/", "/a/b/"
// - Iff all files has been approved, the bot will add "approved" label.
func (h *ApprovalHandler) Munge(obj *github.MungeObject) {
	if !obj.IsPR() {
		return
	}
	files, err := obj.ListFiles()
	if err != nil {
		glog.Errorf("failed to list files in this PR: %v", err)
		return
	}

	comments, err := getCommentsAfterLastModified(obj)
	if err != nil {
		glog.Errorf("failed to get comments in this PR: %v", err)
		return
	}

	approverMap := sets.String{}

	// from oldest to latest
	for i := len(comments) - 1; i >= 0; i-- {
		c := comments[i]

		if !mungerutil.IsValidUser(c.User) {
			continue
		}

		fields := strings.Fields(strings.TrimSpace(*c.Body))

		if len(fields) == 1 && strings.ToLower(fields[0]) == "/approve" {
			approverMap.Insert(*c.User.Login)
			continue
		}

		if len(fields) == 2 && strings.ToLower(fields[0]) == "/approve" && strings.ToLower(fields[1]) == "cancel" {
			approverMap.Delete(*c.User.Login)
		}
	}

	for _, file := range files {
		if !h.hasApproval(*file.Filename, approverMap, maxDepth) {
			return
		}
	}
	obj.AddLabel(approvedLabel)
}

func (h *ApprovalHandler) hasApproval(filename string, approverMap sets.String, depth int) bool {
	paths := strings.Split(filename, "/")
	p := ""
	for i := 0; i < len(paths) && i < depth; i++ {
		fileOwners := h.features.Repos.LeafAssignees(p)
		if fileOwners.Len() == 0 {
			glog.Warningf("Couldn't find an owner for path (%s)", p)
			continue
		}

		if h.features.Aliases != nil && h.features.Aliases.IsEnabled {
			fileOwners = h.features.Aliases.Expand(fileOwners)
		}

		for _, owner := range fileOwners.List() {
			if approverMap.Has(owner) {
				return true
			}
		}
		p = path.Join(p, paths[i])
	}
	return false
}
<commit_msg>rename: approverSet<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package mungers

import (
	"path"
	"strings"

	"k8s.io/contrib/mungegithub/features"
	"k8s.io/contrib/mungegithub/github"
	"k8s.io/contrib/mungegithub/mungers/mungerutil"
	"k8s.io/kubernetes/pkg/util/sets"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
)

const maxDepth = 3

// ApprovalHandler will try to add "approved" label once
// all files of change has been approved by approvers.
type ApprovalHandler struct {
	features *features.Features
}

func init() {
	h := &ApprovalHandler{}
	RegisterMungerOrDie(h)
}

// Name is the name usable in --pr-mungers
func (*ApprovalHandler) Name() string { return "approval-handler" }

// RequiredFeatures is a slice of 'features' that must be provided
func (*ApprovalHandler) RequiredFeatures() []string {
	return []string{features.RepoFeatureName, features.AliasesFeature}
}

// Initialize will initialize the munger
func (h *ApprovalHandler) Initialize(config *github.Config, features *features.Features) error {
	h.features = features
	return nil
}

// EachLoop is called at the start of every munge loop
func (*ApprovalHandler) EachLoop() error { return nil }

// AddFlags will add any request flags to the cobra `cmd`
func (*ApprovalHandler) AddFlags(cmd *cobra.Command, config *github.Config) {}

// Munge is the workhorse the will actually make updates to the PR
// The algorithm goes as:
// - Initially, we set up approverSet
//   - Go through all comments after latest commit. If any approver said "/approve", add him to approverSet.
// - For each file, we see if any approver of this file is in approverSet.
//   - An approver of a file is defined as:
//     - It's known that each dir has a list of approvers. (This might not hold true. For usability, current situation is enough.)
//     - Approver of a dir is also the approver of child dirs.
//   - We look at top N (default 3) level dir approvers. For example, for file "/a/b/c/d/e", we might search for approver from
//     "/", "/a/", "/a/b/"
// - Iff all files has been approved, the bot will add "approved" label.
func (h *ApprovalHandler) Munge(obj *github.MungeObject) {
	if !obj.IsPR() {
		return
	}
	files, err := obj.ListFiles()
	if err != nil {
		glog.Errorf("failed to list files in this PR: %v", err)
		return
	}

	comments, err := getCommentsAfterLastModified(obj)
	if err != nil {
		glog.Errorf("failed to get comments in this PR: %v", err)
		return
	}

	approverSet := sets.String{}

	// from oldest to latest
	for i := len(comments) - 1; i >= 0; i-- {
		c := comments[i]

		if !mungerutil.IsValidUser(c.User) {
			continue
		}

		fields := strings.Fields(strings.TrimSpace(*c.Body))

		if len(fields) == 1 && strings.ToLower(fields[0]) == "/approve" {
			approverSet.Insert(*c.User.Login)
			continue
		}

		if len(fields) == 2 && strings.ToLower(fields[0]) == "/approve" && strings.ToLower(fields[1]) == "cancel" {
			approverSet.Delete(*c.User.Login)
		}
	}

	for _, file := range files {
		if !h.hasApproval(*file.Filename, approverSet, maxDepth) {
			return
		}
	}
	obj.AddLabel(approvedLabel)
}

func (h *ApprovalHandler) hasApproval(filename string, approverSet sets.String, depth int) bool {
	paths := strings.Split(filename, "/")
	p := ""
	for i := 0; i < len(paths) && i < depth; i++ {
		fileOwners := h.features.Repos.LeafAssignees(p)
		if fileOwners.Len() == 0 {
			glog.Warningf("Couldn't find an owner for path (%s)", p)
			continue
		}

		if h.features.Aliases != nil && h.features.Aliases.IsEnabled {
			fileOwners = h.features.Aliases.Expand(fileOwners)
		}

		for _, owner := range fileOwners.List() {
			if approverSet.Has(owner) {
				return true
			}
		}
		p = path.Join(p, paths[i])
	}
	return false
}
<|endoftext|>


<commit_before>package driver

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"

	ctestutils "github.com/hashicorp/nomad/client/testutil"
)

func TestRktVersionRegex(t *testing.T) {
        input_rkt := "rkt version 0.8.1"
        input_appc := "appc version 1.2.0"
        expected_rkt := "0.8.1"
        expected_appc := "1.2.0"
        rktMatches := reRktVersion.FindStringSubmatch(input_rkt)
        appcMatches := reAppcVersion.FindStringSubmatch(input_appc)
        if rktMatches[1] != expected_rkt {
                fmt.Printf("Test failed; got %q; want %q\n", rktMatches[1], expected_rkt)
        }
        if appcMatches[1] != expected_appc {
                fmt.Printf("Test failed; got %q; want %q\n", appcMatches[1], expected_appc)
        }
}

func TestRktDriver_Handle(t *testing.T) {
	h := &rktHandle{
		proc:   &os.Process{Pid: 123},
		image:  "foo",
		doneCh: make(chan struct{}),
		waitCh: make(chan error, 1),
	}

	actual := h.ID()
	expected := `Rkt:{"Pid":123,"Image":"foo"}`
	if actual != expected {
		t.Errorf("Expected `%s`, found `%s`", expected, actual)
	}
}

// The fingerprinter test should always pass, even if rkt is not installed.
func TestRktDriver_Fingerprint(t *testing.T) {
	ctestutils.RktCompatible(t)
	d := NewRktDriver(testDriverContext(""))
	node := &structs.Node{
		Attributes: make(map[string]string),
	}
	apply, err := d.Fingerprint(&config.Config{}, node)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if !apply {
		t.Fatalf("should apply")
	}
	if node.Attributes["driver.rkt"] != "1" {
		t.Fatalf("Missing Rkt driver")
	}
	if node.Attributes["driver.rkt.version"] == "" {
		t.Fatalf("Missing Rkt driver version")
	}
	if node.Attributes["driver.rkt.appc.version"] == "" {
		t.Fatalf("Missing appc version for the Rkt driver")
	}
}

func TestRktDriver_Start(t *testing.T) {
	ctestutils.RktCompatible(t)
	// TODO: use test server to load from a fixture
	task := &structs.Task{
		Name: "etcd",
		Config: map[string]string{
			"trust_prefix": "coreos.com/etcd",
			"image":        "coreos.com/etcd:v2.0.4",
			"command":      "/etcd",
		},
	}

	driverCtx := testDriverContext(task.Name)
	ctx := testDriverExecContext(task, driverCtx)
	d := NewRktDriver(driverCtx)
	defer ctx.AllocDir.Destroy()

	handle, err := d.Start(ctx, task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle == nil {
		t.Fatalf("missing handle")
	}

	// Attempt to open
	handle2, err := d.Open(ctx, handle.ID())
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle2 == nil {
		t.Fatalf("missing handle")
	}

	// Clean up
	if err := handle.Kill(); err != nil {
		fmt.Printf("\nError killing Rkt test: %s", err)
	}
}

func TestRktDriver_Start_Wait(t *testing.T) {
	ctestutils.RktCompatible(t)
	task := &structs.Task{
		Name: "etcd",
		Config: map[string]string{
			"trust_prefix": "coreos.com/etcd",
			"image":        "coreos.com/etcd:v2.0.4",
			"command":      "/etcd",
			"args":         "--version",
		},
	}

	driverCtx := testDriverContext(task.Name)
	ctx := testDriverExecContext(task, driverCtx)
	d := NewRktDriver(driverCtx)
	defer ctx.AllocDir.Destroy()

	handle, err := d.Start(ctx, task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle == nil {
		t.Fatalf("missing handle")
	}
	defer handle.Kill()

	// Update should be a no-op
	err = handle.Update(task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	select {
	case err := <-handle.WaitCh():
		if err != nil {
			t.Fatalf("err: %v", err)
		}
	case <-time.After(5 * time.Second):
		t.Fatalf("timeout")
	}
}

func TestRktDriver_Start_Wait_Skip_Trust(t *testing.T) {
	ctestutils.RktCompatible(t)
	task := &structs.Task{
		Name: "etcd",
		Config: map[string]string{
			"image":   "coreos.com/etcd:v2.0.4",
			"command": "/etcd",
			"args":    "--version",
		},
	}

	driverCtx := testDriverContext(task.Name)
	ctx := testDriverExecContext(task, driverCtx)
	d := NewRktDriver(driverCtx)
	defer ctx.AllocDir.Destroy()

	handle, err := d.Start(ctx, task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle == nil {
		t.Fatalf("missing handle")
	}
	defer handle.Kill()

	// Update should be a no-op
	err = handle.Update(task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	select {
	case err := <-handle.WaitCh():
		if err != nil {
			t.Fatalf("err: %v", err)
		}
	case <-time.After(5 * time.Second):
		t.Fatalf("timeout")
	}
}

func TestRktDriver_Start_Wait_Logs(t *testing.T) {
	ctestutils.RktCompatible(t)
	task := &structs.Task{
		Name: "etcd",
		Config: map[string]string{
			"trust_prefix": "coreos.com/etcd",
			"image":        "coreos.com/etcd:v2.0.4",
			"command":      "/etcd",
			"args":         "--version",
		},
	}

	driverCtx := testDriverContext(task.Name)
	ctx := testDriverExecContext(task, driverCtx)
	d := NewRktDriver(driverCtx)
	defer ctx.AllocDir.Destroy()

	handle, err := d.Start(ctx, task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle == nil {
		t.Fatalf("missing handle")
	}
	defer handle.Kill()

	select {
	case err := <-handle.WaitCh():
		if err != nil {
			t.Fatalf("err: %v", err)
		}
	case <-time.After(5 * time.Second):
		t.Fatalf("timeout")
	}

	taskDir, ok := ctx.AllocDir.TaskDirs[task.Name]
	if !ok {
		t.Fatalf("Could not find task directory for task: %v", task)
	}
	stdout := filepath.Join(taskDir, allocdir.TaskLocal, fmt.Sprintf("%v.stdout", task.Name))
	data, err := ioutil.ReadFile(stdout)
	if err != nil {
		t.Fatalf("Failed to read tasks stdout: %v", err)
	}

	if len(data) == 0 {
		t.Fatal("Task's stdout is empty")
	}
}
<commit_msg>Format rkt_test<commit_after>package driver

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"

	ctestutils "github.com/hashicorp/nomad/client/testutil"
)

func TestRktVersionRegex(t *testing.T) {
	input_rkt := "rkt version 0.8.1"
	input_appc := "appc version 1.2.0"
	expected_rkt := "0.8.1"
	expected_appc := "1.2.0"
	rktMatches := reRktVersion.FindStringSubmatch(input_rkt)
	appcMatches := reAppcVersion.FindStringSubmatch(input_appc)
	if rktMatches[1] != expected_rkt {
		fmt.Printf("Test failed; got %q; want %q\n", rktMatches[1], expected_rkt)
	}
	if appcMatches[1] != expected_appc {
		fmt.Printf("Test failed; got %q; want %q\n", appcMatches[1], expected_appc)
	}
}

func TestRktDriver_Handle(t *testing.T) {
	h := &rktHandle{
		proc:   &os.Process{Pid: 123},
		image:  "foo",
		doneCh: make(chan struct{}),
		waitCh: make(chan error, 1),
	}

	actual := h.ID()
	expected := `Rkt:{"Pid":123,"Image":"foo"}`
	if actual != expected {
		t.Errorf("Expected `%s`, found `%s`", expected, actual)
	}
}

// The fingerprinter test should always pass, even if rkt is not installed.
func TestRktDriver_Fingerprint(t *testing.T) {
	ctestutils.RktCompatible(t)
	d := NewRktDriver(testDriverContext(""))
	node := &structs.Node{
		Attributes: make(map[string]string),
	}
	apply, err := d.Fingerprint(&config.Config{}, node)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if !apply {
		t.Fatalf("should apply")
	}
	if node.Attributes["driver.rkt"] != "1" {
		t.Fatalf("Missing Rkt driver")
	}
	if node.Attributes["driver.rkt.version"] == "" {
		t.Fatalf("Missing Rkt driver version")
	}
	if node.Attributes["driver.rkt.appc.version"] == "" {
		t.Fatalf("Missing appc version for the Rkt driver")
	}
}

func TestRktDriver_Start(t *testing.T) {
	ctestutils.RktCompatible(t)
	// TODO: use test server to load from a fixture
	task := &structs.Task{
		Name: "etcd",
		Config: map[string]string{
			"trust_prefix": "coreos.com/etcd",
			"image":        "coreos.com/etcd:v2.0.4",
			"command":      "/etcd",
		},
	}

	driverCtx := testDriverContext(task.Name)
	ctx := testDriverExecContext(task, driverCtx)
	d := NewRktDriver(driverCtx)
	defer ctx.AllocDir.Destroy()

	handle, err := d.Start(ctx, task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle == nil {
		t.Fatalf("missing handle")
	}

	// Attempt to open
	handle2, err := d.Open(ctx, handle.ID())
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle2 == nil {
		t.Fatalf("missing handle")
	}

	// Clean up
	if err := handle.Kill(); err != nil {
		fmt.Printf("\nError killing Rkt test: %s", err)
	}
}

func TestRktDriver_Start_Wait(t *testing.T) {
	ctestutils.RktCompatible(t)
	task := &structs.Task{
		Name: "etcd",
		Config: map[string]string{
			"trust_prefix": "coreos.com/etcd",
			"image":        "coreos.com/etcd:v2.0.4",
			"command":      "/etcd",
			"args":         "--version",
		},
	}

	driverCtx := testDriverContext(task.Name)
	ctx := testDriverExecContext(task, driverCtx)
	d := NewRktDriver(driverCtx)
	defer ctx.AllocDir.Destroy()

	handle, err := d.Start(ctx, task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle == nil {
		t.Fatalf("missing handle")
	}
	defer handle.Kill()

	// Update should be a no-op
	err = handle.Update(task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	select {
	case err := <-handle.WaitCh():
		if err != nil {
			t.Fatalf("err: %v", err)
		}
	case <-time.After(5 * time.Second):
		t.Fatalf("timeout")
	}
}

func TestRktDriver_Start_Wait_Skip_Trust(t *testing.T) {
	ctestutils.RktCompatible(t)
	task := &structs.Task{
		Name: "etcd",
		Config: map[string]string{
			"image":   "coreos.com/etcd:v2.0.4",
			"command": "/etcd",
			"args":    "--version",
		},
	}

	driverCtx := testDriverContext(task.Name)
	ctx := testDriverExecContext(task, driverCtx)
	d := NewRktDriver(driverCtx)
	defer ctx.AllocDir.Destroy()

	handle, err := d.Start(ctx, task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle == nil {
		t.Fatalf("missing handle")
	}
	defer handle.Kill()

	// Update should be a no-op
	err = handle.Update(task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	select {
	case err := <-handle.WaitCh():
		if err != nil {
			t.Fatalf("err: %v", err)
		}
	case <-time.After(5 * time.Second):
		t.Fatalf("timeout")
	}
}

func TestRktDriver_Start_Wait_Logs(t *testing.T) {
	ctestutils.RktCompatible(t)
	task := &structs.Task{
		Name: "etcd",
		Config: map[string]string{
			"trust_prefix": "coreos.com/etcd",
			"image":        "coreos.com/etcd:v2.0.4",
			"command":      "/etcd",
			"args":         "--version",
		},
	}

	driverCtx := testDriverContext(task.Name)
	ctx := testDriverExecContext(task, driverCtx)
	d := NewRktDriver(driverCtx)
	defer ctx.AllocDir.Destroy()

	handle, err := d.Start(ctx, task)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if handle == nil {
		t.Fatalf("missing handle")
	}
	defer handle.Kill()

	select {
	case err := <-handle.WaitCh():
		if err != nil {
			t.Fatalf("err: %v", err)
		}
	case <-time.After(5 * time.Second):
		t.Fatalf("timeout")
	}

	taskDir, ok := ctx.AllocDir.TaskDirs[task.Name]
	if !ok {
		t.Fatalf("Could not find task directory for task: %v", task)
	}
	stdout := filepath.Join(taskDir, allocdir.TaskLocal, fmt.Sprintf("%v.stdout", task.Name))
	data, err := ioutil.ReadFile(stdout)
	if err != nil {
		t.Fatalf("Failed to read tasks stdout: %v", err)
	}

	if len(data) == 0 {
		t.Fatal("Task's stdout is empty")
	}
}
<|endoftext|>


<commit_before>package main

import (
        "encoding/json"
        "flag"
        "fmt"
        "io/ioutil"
        "net/http"
        "strings"
        "time"
        "os"
)

type Stop struct {
        V            int     `json:"__v,int"`
        Id           string  `json:"_id"`
        City         string
        Name         string
        Sort_id      int
        Destinations []Destination
}

type Destination struct {
        V            int     `json:"__v,int"`
        Id           string  `json:"_id"`
        City         string
        Name         string
        Sort_id      int
        Destinations []string
}

type Time struct {
        FromId  string
        From    string
        ToId    string
        To      string
        Date    string
        //Arrival string
        Route   int
        Busstop string
        Hash    string
        Id      string  `json:"_id"`
        V       int     `json:"__v"`
}

func main() {
        busStopsURL := "http://rutebuss.no/stops/Tromsø"

        resp, err := http.Get(busStopsURL)
        if err != nil {
                fmt.Print("Bus stops could not be downlaoded...", err)
                return
        }

        body, err := ioutil.ReadAll(resp.Body)

        if err != nil {
                fmt.Println("Could not read body ", err)
                return
        }

        stops := make([]Stop, 100)

        err = json.Unmarshal(body, &stops)

        if err != nil {
                fmt.Println("Error contacting rutebuss.no")
                return
        }

        fromString := flag.String("from", "UiT",
                "The bus stop you are traveling from")
        toString := flag.String("to", "Sentrum",
                "The bus stop you are traveling to")

        invert := flag.Bool("i", false,
            "Switch the from and to values with each other")

        specificTime := flag.String("time", "now",
                "Specific time of departure. Formatted as hour:minute")

        flag.Usage = func(){
            fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
            flag.PrintDefaults()
            fmt.Fprintf(os.Stderr, "\nAvailible stops: \n")//+availibleStops)
            for i, _ := range stops {
                if i%2 == 0 {
                    if i == len(stops) - 1 {
                        fmt.Fprintln(os.Stderr, stops[i].Name)
                    } else {
                        fmt.Fprintf(os.Stderr, "%-20s%s\n", stops[i].Name, stops[i+1].Name)
                    }
                }
            }
        }

        flag.Parse()
        if *invert {
            tmp := fromString
            fromString = toString
            toString = tmp
        }

        fmt.Println("From", *fromString, "to", *toString)

        var from, to string
        for _, stop := range stops {
                if strings.ToLower(stop.Name) == strings.ToLower(*fromString) {
                        from = stop.Id
                }
                if strings.ToLower(stop.Name) == strings.ToLower(*toString) {
                        to = stop.Id
                }
        }

        if from == "" && to == "" {
                fmt.Println("Bus route ", from, "-", to, "does not exist")
                return
        }

        var t time.Time
        var timeString string

        if *specificTime != "now" {
            const layout = "15:04"

            location, _ := time.LoadLocation("Local")

            t, err = time.ParseInLocation(layout, *specificTime, location)

            if err != nil {
                fmt.Println("Error: Could not parse time:", *specificTime)
                fmt.Println(t)
                //flag.Usage()
                return
            }

            t_now := time.Now()
            y,m,d := t_now.Date()

            // date() gave day and month +1 :(
            d = d - 1
            mnth := int(m) - 1

            // since t object is 0000-00-00Thour:minute we need to add today's
            // date and everything.
            t = t.AddDate(y,mnth,d)

            timeString = t.UTC().Format(time.RFC3339)
        } else {
            t = time.Now()
            timeString = t.UTC().Format(time.RFC3339)
        }

        travelURL :=
                "http://rutebuss.no/departure?from=" + from + "&to=" + to + "&date=" + timeString

        resp, err = http.Get(travelURL)
        if err != nil {
                fmt.Print("Bus times could not be downlaoded...", err)
                return
        }

        body, err = ioutil.ReadAll(resp.Body)

        if err != nil {
                fmt.Println("Could not read body ", err)
                return
        }

        times := make([]Time, 10)

        err = json.Unmarshal(body, &times)

        if err != nil {
                fmt.Println("Bus route ", *fromString, "-", *toString, "does not exist")
                return
        }

        if len(times) == 0 {
                fmt.Println("Bus route ", *fromString, "-", *toString, "does not exist")
        }

        for _, departure_time := range times {

                departure, err := time.Parse(time.RFC3339, departure_time.Date)

                if err != nil {
                        fmt.Println("Parsing of date went horrible... ", err)
                }

                untilDeparture := departure.Sub(time.Now())
                untilDString := untilDeparture.String()
                untilDString = strings.Split(untilDString, ".")[0]
                untilDString = untilDString + "s"

                hour := time.Hour
                departure = departure.Add(hour)
                // Daylight savings bug. We'll have to look at it later.
                // departure = departure.Add(hour)

                tm := departure.Format(time.Kitchen)
                fmt.Println("Bus", departure_time.Route, "leaves at", tm, "in",
                        untilDString, "from", departure_time.Busstop)
        }

}
<commit_msg>Update busman.go<commit_after>package main

import (
        "encoding/json"
        "flag"
        "fmt"
        "io/ioutil"
        "net/http"
        "strings"
        "time"
        "os"
)

type Stop struct {
        V            int     `json:"__v,int"`
        Id           string  `json:"_id"`
        City         string
        Name         string
        Sort_id      int
        Destinations []Destination
}

type Destination struct {
        V            int     `json:"__v,int"`
        Id           string  `json:"_id"`
        City         string
        Name         string
        Sort_id      int
        Destinations []string
}

type Time struct {
        FromId  string
        From    string
        ToId    string
        To      string
        Date    string
        //Arrival string
        Route   int
        Busstop string
        Hash    string
        Id      string  `json:"_id"`
        V       int     `json:"__v"`
}

func main() {
        busStopsURL := "http://rutebuss.no/stops/Tromsø"

        resp, err := http.Get(busStopsURL)
        if err != nil {
                fmt.Print("Bus stops could not be downlaoded...", err)
                return
        }

        body, err := ioutil.ReadAll(resp.Body)

        if err != nil {
                fmt.Println("Could not read body ", err)
                return
        }

        stops := make([]Stop, 100)

        err = json.Unmarshal(body, &stops)

        if err != nil {
                fmt.Println("Error contacting rutebuss.no")
                return
        }

        fromString := flag.String("from", "UiT",
                "The bus stop you are traveling from")
        toString := flag.String("to", "Sentrum",
                "The bus stop you are traveling to")

        invert := flag.Bool("i", false,
            "Switch the from and to values with each other")

        specificTime := flag.String("time", "now",
                "Specific time of departure. Formatted as hour:minute")

        flag.Usage = func(){
            fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
            flag.PrintDefaults()
            fmt.Fprintf(os.Stderr, "\nAvailible stops: \n")//+availibleStops)
            for i, _ := range stops {
                if i%2 == 0 {
                    if i == len(stops) - 1 {
                        fmt.Fprintln(os.Stderr, stops[i].Name)
                    } else {
                        fmt.Fprintf(os.Stderr, "%-20s%s\n", stops[i].Name, stops[i+1].Name)
                    }
                }
            }
        }

        flag.Parse()
        if *invert {
            tmp := fromString
            fromString = toString
            toString = tmp
        }

        fmt.Println("From", *fromString, "to", *toString)

        var from, to string
        for _, stop := range stops {
                if strings.ToLower(stop.Name) == strings.ToLower(*fromString) {
                        from = stop.Id
                }
                if strings.ToLower(stop.Name) == strings.ToLower(*toString) {
                        to = stop.Id
                }
        }

        if from == "" && to == "" {
                fmt.Println("Bus route ", from, "-", to, "does not exist")
                return
        }

        var t time.Time
        var timeString string

        if *specificTime != "now" {
            const layout = "15:04"

            location, _ := time.LoadLocation("Local")

            t, err = time.ParseInLocation(layout, *specificTime, location)

            if err != nil {
                fmt.Println("Error: Could not parse time:", *specificTime)
                fmt.Println(t)
                //flag.Usage()
                return
            }

            t_now := time.Now()
            y,m,d := t_now.Date()

            // date() gave day and month +1 :(
            d = d - 1
            mnth := int(m) - 1

            // since t object is 0000-00-00Thour:minute we need to add today's
            // date and everything.
            t = t.AddDate(y,mnth,d)

            timeString = t.UTC().Format(time.RFC3339)
        } else {
            t = time.Now()
            timeString = t.UTC().Format(time.RFC3339)
        }

        travelURL :=
                "http://rutebuss.no/departure?from=" + from + "&to=" + to + "&date=" + timeString

        resp, err = http.Get(travelURL)
        if err != nil {
                fmt.Print("Bus times could not be downlaoded...", err)
                return
        }

        body, err = ioutil.ReadAll(resp.Body)

        if err != nil {
                fmt.Println("Could not read body ", err)
                return
        }

        times := make([]Time, 10)

        err = json.Unmarshal(body, &times)

        if err != nil {
                fmt.Println("Bus route ", *fromString, "-", *toString, "does not exist")
                return
        }

        if len(times) == 0 {
                fmt.Println("Bus route ", *fromString, "-", *toString, "does not exist")
        }

        for _, departure_time := range times {

                departure, err := time.Parse(time.RFC3339, departure_time.Date)

                if err != nil {
                        fmt.Println("Parsing of date went horrible... ", err)
                }

                untilDeparture := departure.Sub(time.Now())
                untilDString := untilDeparture.String()
                untilDString = strings.Split(untilDString, ".")[0]
                untilDString = untilDString + "s"

                hour := time.Hour
                departure = departure.Add(hour)
                // Daylight savings bug. We'll have to look at it later.
                departure = departure.Add(hour)

                tm := departure.Format(time.Kitchen)
                fmt.Println("Bus", departure_time.Route, "leaves at", tm, "in",
                        untilDString, "from", departure_time.Busstop)
        }

}
<|endoftext|>


<commit_before>package keeper

import (
	"context"

	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/dclauth/types"
)

func (k msgServer) ApproveRevokeAccount(goCtx context.Context, msg *types.MsgApproveRevokeAccount) (*types.MsgApproveRevokeAccountResponse, error) {
	ctx := sdk.UnwrapSDKContext(goCtx)

	signerAddr, err := sdk.AccAddressFromBech32(msg.Signer)
	if err != nil {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid Signer: (%s)", err)
	}

	// check that sender has enough rights to approve account revocation
	if !k.HasRole(ctx, signerAddr, types.Trustee) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"MsgApproveRevokeAccount transaction should be signed by an account with the %s role",
			types.Trustee,
		)
	}

	accAddr, err := sdk.AccAddressFromBech32(msg.Address)
	if err != nil {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid Address: (%s)", err)
	}

	// check that pending account revocation exists
	if !k.IsPendingAccountRevocationPresent(ctx, accAddr) {
		return nil, types.ErrPendingAccountRevocationDoesNotExist(msg.Address)
	}

	// get pending account revocation
	revoc, _ := k.GetPendingAccountRevocation(ctx, accAddr)

	// check if pending account revocation already has approval from signer
	if revoc.HasRevocationFrom(signerAddr) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"Pending account revocation associated with the address=%v already has approval from=%v",
			msg.Address,
			msg.Signer,
		)
	}
	grant := types.Grant{
		Address: signerAddr.String(),
		Time:    msg.Time,
		Info:    msg.Info,
	}
	// append approval
	revoc.Approvals = append(revoc.Approvals, &grant)

	// check if pending account revocation has enough approvals
	if len(revoc.Approvals) == k.AccountApprovalsCount(ctx) {
		// delete account record
		k.RemoveAccount(ctx, accAddr)

		// delete pending account revocation record
		k.RemovePendingAccountRevocation(ctx, accAddr)
	} else {
		// update pending account revocation record
		k.SetPendingAccountRevocation(ctx, revoc)
	}

	return &types.MsgApproveRevokeAccountResponse{}, nil
}
<commit_msg>Added implementation for saving map RevokedAccount<commit_after>package keeper

import (
	"context"

	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/dclauth/types"
)

func (k msgServer) ApproveRevokeAccount(goCtx context.Context, msg *types.MsgApproveRevokeAccount) (*types.MsgApproveRevokeAccountResponse, error) {
	ctx := sdk.UnwrapSDKContext(goCtx)

	signerAddr, err := sdk.AccAddressFromBech32(msg.Signer)
	if err != nil {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid Signer: (%s)", err)
	}

	// check that sender has enough rights to approve account revocation
	if !k.HasRole(ctx, signerAddr, types.Trustee) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"MsgApproveRevokeAccount transaction should be signed by an account with the %s role",
			types.Trustee,
		)
	}

	accAddr, err := sdk.AccAddressFromBech32(msg.Address)
	if err != nil {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid Address: (%s)", err)
	}

	// check that pending account revocation exists
	if !k.IsPendingAccountRevocationPresent(ctx, accAddr) {
		return nil, types.ErrPendingAccountRevocationDoesNotExist(msg.Address)
	}

	// get pending account revocation
	revoc, _ := k.GetPendingAccountRevocation(ctx, accAddr)

	// check if pending account revocation already has approval from signer
	if revoc.HasRevocationFrom(signerAddr) {
		return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized,
			"Pending account revocation associated with the address=%v already has approval from=%v",
			msg.Address,
			msg.Signer,
		)
	}
	grant := types.Grant{
		Address: signerAddr.String(),
		Time:    msg.Time,
		Info:    msg.Info,
	}
	// append approval
	revoc.Approvals = append(revoc.Approvals, &grant)

	// check if pending account revocation has enough approvals
	if len(revoc.Approvals) == k.AccountApprovalsCount(ctx) {
		// get account
		account, ok := k.GetAccountO(ctx, sdk.AccAddress(accAddr))

		// check we can get that account or can not
		if !ok {
			return nil, types.ErrAccountDoesNotExist(msg.Address)
		}

		// save to map RevokedAccount
		revokedAccount := types.NewRevokedAccount(&account, revoc.Approvals, msg.Info, msg.Time)

		k.SetRevokedAccount(ctx, *revokedAccount)
		// delete account record
		k.RemoveAccount(ctx, accAddr)

		// delete pending account revocation record
		k.RemovePendingAccountRevocation(ctx, accAddr)
	} else {
		// update pending account revocation record
		k.SetPendingAccountRevocation(ctx, revoc)
	}

	return &types.MsgApproveRevokeAccountResponse{}, nil
}
<|endoftext|>