<commit_before>package main

import (
	"errors"
	"fmt"
	"math"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/fatih/color"
	mkr "github.com/mackerelio/mackerel-client-go"
	"github.com/mackerelio/mkr/logger"
	"gopkg.in/urfave/cli.v1"
)

var commandAlerts = cli.Command{
	Name:      "alerts",
	Usage:     "Retrieve/Close alerts",
	ArgsUsage: "[--with-closed | -w] [--limit | -l]",
	Description: `
    Retrieve/Close alerts. With no subcommand specified, this will show all alerts.
    Requests APIs under "/api/v0/alerts". See https://mackerel.io/api-docs/entry/alerts .
`,
	Action: doAlertsRetrieve,
	Flags: []cli.Flag{
		cli.BoolFlag{Name: "with-closed, w", Usage: "Display open alert including close alert. default: false"},
		cli.IntFlag{Name: "limit, l", Value: defaultAlertsLimit, Usage: "Set the number of alerts to display."},
	},
	Subcommands: []cli.Command{
		{
			Name:      "list",
			Usage:     "list alerts",
			ArgsUsage: "[--service | -s <service>] [--host-status | -S <file>] [--color | -c] [--with-closed | -w] [--limit | -l]",
			Description: `
    Shows alerts in human-readable format.
`,
			Action: doAlertsList,
			Flags: []cli.Flag{
				cli.StringSliceFlag{
					Name:  "service, s",
					Value: &cli.StringSlice{},
					Usage: "Filters alerts by service. Multiple choices are allowed.",
				},
				cli.StringSliceFlag{
					Name:  "host-status, S",
					Value: &cli.StringSlice{},
					Usage: "Filters alerts by status of each host. Multiple choices are allowed.",
				},
				cli.BoolTFlag{Name: "color, c", Usage: "Colorize output. default: true"},
				cli.BoolFlag{Name: "with-closed, w", Usage: "Display open alert including close alert. default: false"},
				cli.IntFlag{Name: "limit, l", Value: defaultAlertsLimit, Usage: "Set the number of alerts to display."},
			},
		},
		{
			Name:      "close",
			Usage:     "close alerts",
			ArgsUsage: "<alertIds....>",
			Description: `
    Closes alerts. Multiple alert IDs can be specified.
`,
			Action: doAlertsClose,
			Flags: []cli.Flag{
				cli.StringFlag{Name: "reason, r", Value: "", Usage: "Reason of closing alert."},
				cli.BoolFlag{Name: "verbose, v", Usage: "Verbose output mode"},
			},
		},
	},
}

const defaultAlertsLimit int = 100

type alertSet struct {
	Alert   *mkr.Alert
	Host    *mkr.Host
	Monitor mkr.Monitor
}

func joinMonitorsAndHosts(client *mkr.Client, alerts []*mkr.Alert) []*alertSet {
	hostsJSON, err := client.FindHosts(&mkr.FindHostsParam{
		Statuses: []string{"working", "standby", "poweroff", "maintenance"},
	})
	logger.DieIf(err)

	hosts := map[string]*mkr.Host{}
	for _, host := range hostsJSON {
		hosts[host.ID] = host
	}

	monitorsJSON, err := client.FindMonitors()
	logger.DieIf(err)

	monitors := map[string]mkr.Monitor{}
	for _, monitor := range monitorsJSON {
		monitors[monitor.MonitorID()] = monitor
	}

	alertSets := []*alertSet{}
	for _, alert := range alerts {
		alertSets = append(
			alertSets,
			&alertSet{Alert: alert, Host: hosts[alert.HostID], Monitor: monitors[alert.MonitorID]},
		)
	}
	return alertSets
}

func formatJoinedAlert(alertSet *alertSet, colorize bool) string {
	const layout = "2006-01-02 15:04:05"

	host := alertSet.Host
	monitor := alertSet.Monitor
	alert := alertSet.Alert

	hostMsg := ""
	if host != nil {
		statusMsg := host.Status
		if host.IsRetired == true {
			statusMsg = "retired"
		}
		if colorize {
			switch statusMsg {
			case "working":
				statusMsg = color.BlueString("working")
			case "standby":
				statusMsg = color.GreenString("standby")
			case "poweroff":
				statusMsg = "poweroff"
			case "maintenance":
				statusMsg = color.YellowString("maintenance")
			}
		}
		hostMsg = fmt.Sprintf(" %s %s", host.Name, statusMsg)
		roleMsgs := []string{}
		for service, roles := range host.Roles {
			roleMsgs = append(roleMsgs, fmt.Sprintf("%s:%s", service, strings.Join(roles, ",")))
		}
		hostMsg += " [" + strings.Join(roleMsgs, ", ") + "]"
	}

	monitorMsg := ""
	if monitor != nil {
		switch m := monitor.(type) {
		case *mkr.MonitorConnectivity:
			monitorMsg = ""
		case *mkr.MonitorHostMetric:
			if alert.Status == "CRITICAL" && m.Critical != nil {
				monitorMsg = fmt.Sprintf("%s %.2f %s %.2f", m.Metric, alert.Value, m.Operator, *m.Critical)
			} else if alert.Status == "WARNING" && m.Warning != nil {
				monitorMsg = fmt.Sprintf("%s %.2f %s %.2f", m.Metric, alert.Value, m.Operator, *m.Warning)
			} else {
				monitorMsg = fmt.Sprintf("%s %.2f", m.Metric, alert.Value)
			}
		case *mkr.MonitorServiceMetric:
			if alert.Status == "CRITICAL" && m.Critical != nil {
				monitorMsg = fmt.Sprintf("%s %s %.2f %s %.2f", m.Service, m.Metric, alert.Value, m.Operator, *m.Critical)
			} else if alert.Status == "WARNING" && m.Warning != nil {
				monitorMsg = fmt.Sprintf("%s %s %.2f %s %.2f", m.Service, m.Metric, alert.Value, m.Operator, *m.Warning)
			} else {
				monitorMsg = fmt.Sprintf("%s %s %.2f", m.Service, m.Metric, alert.Value)
			}
		case *mkr.MonitorExternalHTTP:
			statusRegexp, _ := regexp.Compile("^[2345][0-9][0-9]$")
			switch alert.Status {
			case "CRITICAL":
				if statusRegexp.MatchString(alert.Message) && m.ResponseTimeCritical != nil {
					monitorMsg = fmt.Sprintf("%s %.2f > %.2f msec, status:%s", m.URL, alert.Value, *m.ResponseTimeCritical, alert.Message)
				} else {
					monitorMsg = fmt.Sprintf("%s %.2f msec, %s", m.URL, alert.Value, alert.Message)
				}
			case "WARNING":
				if statusRegexp.MatchString(alert.Message) && m.ResponseTimeWarning != nil {
					monitorMsg = fmt.Sprintf("%.2f > %.2f msec, status:%s", alert.Value, *m.ResponseTimeWarning, alert.Message)
				} else {
					monitorMsg = fmt.Sprintf("%.2f msec, %s", alert.Value, alert.Message)
				}
			default:
				monitorMsg = fmt.Sprintf("%.2f msec, status:%s", alert.Value, alert.Message)
			}
		case *mkr.MonitorExpression:
			expression := formatExpressionOneline(m.Expression)
			if alert.Status == "CRITICAL" && m.Critical != nil {
				monitorMsg = fmt.Sprintf("%s %.2f %s %.2f", expression, alert.Value, m.Operator, *m.Critical)
			} else if alert.Status == "WARNING" && m.Warning != nil {
				monitorMsg = fmt.Sprintf("%s %.2f %s %.2f", expression, alert.Value, m.Operator, *m.Warning)
			} else if alert.Status == "UNKNOWN" {
				monitorMsg = fmt.Sprintf("%s", expression)
			} else {
				monitorMsg = fmt.Sprintf("%s %.2f", expression, alert.Value)
			}
		default:
			monitorMsg = fmt.Sprintf("%s", monitor.MonitorType())
		}
		if monitorMsg == "" {
			monitorMsg = monitor.MonitorName()
		} else {
			monitorMsg = monitor.MonitorName() + " " + monitorMsg
		}
	}
	// If alert is caused by check monitoring, take monitorMsg from alert.message
	if alert.Type == "check" {
		monitorMsg = formatCheckMessage(alert.Message)
	}

	statusMsg := alert.Status
	if colorize {
		switch alert.Status {
		case "CRITICAL":
			statusMsg = color.RedString("CRITICAL ")
		case "WARNING":
			statusMsg = color.YellowString("WARNING ")
		case "OK":
			statusMsg = color.GreenString("OK ")
		case "UNKNOWN":
			statusMsg = "UNKNOWN "
		}
	}
	return fmt.Sprintf("%s %s %s %s%s", alert.ID, time.Unix(alert.OpenedAt, 0).Format(layout), statusMsg, monitorMsg, hostMsg)
}

var expressionNewlinePattern = regexp.MustCompile(`\s*[\r\n]+\s*`)

func formatExpressionOneline(expr string) string {
	expr = strings.Trim(expressionNewlinePattern.ReplaceAllString(expr, " "), " ")
	return strings.Replace(strings.Replace(expr, "( ", "(", -1), " )", ")", -1)
}

func formatCheckMessage(msg string) string {
	truncated := false
	if index := strings.IndexAny(msg, "\n\r"); index != -1 {
		msg = msg[0:index]
		truncated = true
	}
	if runes := []rune(msg); len(runes) > 100 {
		msg = string(runes[0:100])
		truncated = true
	}
	if truncated {
		msg = msg + "..."
	}
	return msg
}

func doAlertsRetrieve(c *cli.Context) error {
	client := newMackerelFromContext(c)
	withClosed := c.Bool("with-closed")
	alerts, err := fetchAlerts(client, withClosed, getAlertsLimit(c, withClosed))
	logger.DieIf(err)
	PrettyPrintJSON(alerts)
	return nil
}

func doAlertsList(c *cli.Context) error {
	filterServices := c.StringSlice("service")
	filterStatuses := c.StringSlice("host-status")
	client := newMackerelFromContext(c)
	withClosed := c.Bool("with-closed")
	alerts, err := fetchAlerts(client, withClosed, getAlertsLimit(c, withClosed))
	logger.DieIf(err)

	joinedAlerts := joinMonitorsAndHosts(client, alerts)
	for _, joinAlert := range joinedAlerts {
		if len(filterServices) > 0 {
			found := false
			for _, filterService := range filterServices {
				if joinAlert.Host != nil {
					if _, ok := joinAlert.Host.Roles[filterService]; ok {
						found = true
					}
				} else {
					var service string
					if m, ok := joinAlert.Monitor.(*mkr.MonitorServiceMetric); ok {
						service = m.Service
					} else if m, ok := joinAlert.Monitor.(*mkr.MonitorExternalHTTP); ok {
						service = m.Service
					}
					found = service == filterService
				}
			}
			if !found {
				continue
			}
		}
		if len(filterStatuses) > 0 {
			found := false
			for _, filterStatus := range filterStatuses {
				if joinAlert.Host != nil && joinAlert.Host.Status == filterStatus {
					found = true
				}
			}
			if !found {
				continue
			}
		}
		fmt.Fprintln(color.Output, formatJoinedAlert(joinAlert, c.BoolT("color")))
	}
	return nil
}

func getAlertsLimit(c *cli.Context, withClosed bool) int {
	if c.IsSet("limit") {
		return c.Int("limit")
	}
	if withClosed {
		return defaultAlertsLimit
	}
	// When -limit is not set, mkr alerts should print all the open alerts.
	return math.MaxInt32
}

func fetchAlerts(client *mkr.Client, withClosed bool, limit int) ([]*mkr.Alert, error) {
	if limit < 0 {
		return nil, errors.New("limit should not be negative")
	}
	var resp *mkr.AlertsResp
	var err error
	if withClosed {
		if resp, err = client.FindWithClosedAlerts(); err != nil {
			return nil, err
		}
		if resp.NextID != "" {
			for {
				if limit <= len(resp.Alerts) {
					break
				}
				nextResp, err := client.FindWithClosedAlertsByNextID(resp.NextID)
				if err != nil {
					return nil, err
				}
				resp.Alerts = append(resp.Alerts, nextResp.Alerts...)
				resp.NextID = nextResp.NextID
				if resp.NextID == "" {
					break
				}
				time.Sleep(1 * time.Second)
			}
		}
	} else {
		if resp, err = client.FindAlerts(); err != nil {
			return nil, err
		}
		if resp.NextID != "" {
			for {
				if limit <= len(resp.Alerts) {
					break
				}
				nextResp, err := client.FindAlertsByNextID(resp.NextID)
				if err != nil {
					return nil, err
				}
				resp.Alerts = append(resp.Alerts, nextResp.Alerts...)
				resp.NextID = nextResp.NextID
				if resp.NextID == "" {
					break
				}
				time.Sleep(1 * time.Second)
			}
		}
	}
	if len(resp.Alerts) > limit {
		resp.Alerts = resp.Alerts[:limit]
	}
	return resp.Alerts, nil
}

func doAlertsClose(c *cli.Context) error {
	isVerbose := c.Bool("verbose")
	argAlertIDs := c.Args()
	reason := c.String("reason")

	if len(argAlertIDs) < 1 {
		cli.ShowCommandHelp(c, "alerts")
		os.Exit(1)
	}

	client := newMackerelFromContext(c)
	for _, alertID := range argAlertIDs {
		alert, err := client.CloseAlert(alertID, reason)
		logger.DieIf(err)

		logger.Log("Alert closed", alertID)
		if isVerbose == true {
			PrettyPrintJSON(alert)
		}
	}
	return nil
}
<commit_msg>update description for -limit flag of alerts command<commit_after>package main

import (
	"errors"
	"fmt"
	"math"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/fatih/color"
	mkr "github.com/mackerelio/mackerel-client-go"
	"github.com/mackerelio/mkr/logger"
	"gopkg.in/urfave/cli.v1"
)

var commandAlerts = cli.Command{
	Name:      "alerts",
	Usage:     "Retrieve/Close alerts",
	ArgsUsage: "[--with-closed | -w] [--limit | -l]",
	Description: `
    Retrieve/Close alerts. With no subcommand specified, this will show all alerts.
    Requests APIs under "/api/v0/alerts". See https://mackerel.io/api-docs/entry/alerts .
`,
	Action: doAlertsRetrieve,
	Flags: []cli.Flag{
		cli.BoolFlag{Name: "with-closed, w", Usage: "Display open alert including close alert. default: false"},
		cli.IntFlag{Name: "limit, l", Value: defaultAlertsLimit, Usage: fmt.Sprintf("Set the number of alerts to display. Default is set to %d when -with-closed is set, otherwise all the open alerts are displayed.", defaultAlertsLimit)},
	},
	Subcommands: []cli.Command{
		{
			Name:      "list",
			Usage:     "list alerts",
			ArgsUsage: "[--service | -s <service>] [--host-status | -S <file>] [--color | -c] [--with-closed | -w] [--limit | -l]",
			Description: `
    Shows alerts in human-readable format.
`,
			Action: doAlertsList,
			Flags: []cli.Flag{
				cli.StringSliceFlag{
					Name:  "service, s",
					Value: &cli.StringSlice{},
					Usage: "Filters alerts by service. Multiple choices are allowed.",
				},
				cli.StringSliceFlag{
					Name:  "host-status, S",
					Value: &cli.StringSlice{},
					Usage: "Filters alerts by status of each host. Multiple choices are allowed.",
				},
				cli.BoolTFlag{Name: "color, c", Usage: "Colorize output. default: true"},
				cli.BoolFlag{Name: "with-closed, w", Usage: "Display open alert including close alert. default: false"},
				cli.IntFlag{Name: "limit, l", Value: defaultAlertsLimit, Usage: fmt.Sprintf("Set the number of alerts to display. Default is set to %d when -with-closed is set, otherwise all the open alerts are displayed.", defaultAlertsLimit)},
			},
		},
		{
			Name:      "close",
			Usage:     "close alerts",
			ArgsUsage: "<alertIds....>",
			Description: `
    Closes alerts. Multiple alert IDs can be specified.
`,
			Action: doAlertsClose,
			Flags: []cli.Flag{
				cli.StringFlag{Name: "reason, r", Value: "", Usage: "Reason of closing alert."},
				cli.BoolFlag{Name: "verbose, v", Usage: "Verbose output mode"},
			},
		},
	},
}

const defaultAlertsLimit int = 100

type alertSet struct {
	Alert   *mkr.Alert
	Host    *mkr.Host
	Monitor mkr.Monitor
}

func joinMonitorsAndHosts(client *mkr.Client, alerts []*mkr.Alert) []*alertSet {
	hostsJSON, err := client.FindHosts(&mkr.FindHostsParam{
		Statuses: []string{"working", "standby", "poweroff", "maintenance"},
	})
	logger.DieIf(err)

	hosts := map[string]*mkr.Host{}
	for _, host := range hostsJSON {
		hosts[host.ID] = host
	}

	monitorsJSON, err := client.FindMonitors()
	logger.DieIf(err)

	monitors := map[string]mkr.Monitor{}
	for _, monitor := range monitorsJSON {
		monitors[monitor.MonitorID()] = monitor
	}

	alertSets := []*alertSet{}
	for _, alert := range alerts {
		alertSets = append(
			alertSets,
			&alertSet{Alert: alert, Host: hosts[alert.HostID], Monitor: monitors[alert.MonitorID]},
		)
	}
	return alertSets
}

func formatJoinedAlert(alertSet *alertSet, colorize bool) string {
	const layout = "2006-01-02 15:04:05"

	host := alertSet.Host
	monitor := alertSet.Monitor
	alert := alertSet.Alert

	hostMsg := ""
	if host != nil {
		statusMsg := host.Status
		if host.IsRetired == true {
			statusMsg = "retired"
		}
		if colorize {
			switch statusMsg {
			case "working":
				statusMsg = color.BlueString("working")
			case "standby":
				statusMsg = color.GreenString("standby")
			case "poweroff":
				statusMsg = "poweroff"
			case "maintenance":
				statusMsg = color.YellowString("maintenance")
			}
		}
		hostMsg = fmt.Sprintf(" %s %s", host.Name, statusMsg)
		roleMsgs := []string{}
		for service, roles := range host.Roles {
			roleMsgs = append(roleMsgs, fmt.Sprintf("%s:%s", service, strings.Join(roles, ",")))
		}
		hostMsg += " [" + strings.Join(roleMsgs, ", ") + "]"
	}

	monitorMsg := ""
	if monitor != nil {
		switch m := monitor.(type) {
		case *mkr.MonitorConnectivity:
			monitorMsg = ""
		case *mkr.MonitorHostMetric:
			if alert.Status == "CRITICAL" && m.Critical != nil {
				monitorMsg = fmt.Sprintf("%s %.2f %s %.2f", m.Metric, alert.Value, m.Operator, *m.Critical)
			} else if alert.Status == "WARNING" && m.Warning != nil {
				monitorMsg = fmt.Sprintf("%s %.2f %s %.2f", m.Metric, alert.Value, m.Operator, *m.Warning)
			} else {
				monitorMsg = fmt.Sprintf("%s %.2f", m.Metric, alert.Value)
			}
		case *mkr.MonitorServiceMetric:
			if alert.Status == "CRITICAL" && m.Critical != nil {
				monitorMsg = fmt.Sprintf("%s %s %.2f %s %.2f", m.Service, m.Metric, alert.Value, m.Operator, *m.Critical)
			} else if alert.Status == "WARNING" && m.Warning != nil {
				monitorMsg = fmt.Sprintf("%s %s %.2f %s %.2f", m.Service, m.Metric, alert.Value, m.Operator, *m.Warning)
			} else {
				monitorMsg = fmt.Sprintf("%s %s %.2f", m.Service, m.Metric, alert.Value)
			}
		case *mkr.MonitorExternalHTTP:
			statusRegexp, _ := regexp.Compile("^[2345][0-9][0-9]$")
			switch alert.Status {
			case "CRITICAL":
				if statusRegexp.MatchString(alert.Message) && m.ResponseTimeCritical != nil {
					monitorMsg = fmt.Sprintf("%s %.2f > %.2f msec, status:%s", m.URL, alert.Value, *m.ResponseTimeCritical, alert.Message)
				} else {
					monitorMsg = fmt.Sprintf("%s %.2f msec, %s", m.URL, alert.Value, alert.Message)
				}
			case "WARNING":
				if statusRegexp.MatchString(alert.Message) && m.ResponseTimeWarning != nil {
					monitorMsg = fmt.Sprintf("%.2f > %.2f msec, status:%s", alert.Value, *m.ResponseTimeWarning, alert.Message)
				} else {
					monitorMsg = fmt.Sprintf("%.2f msec, %s", alert.Value, alert.Message)
				}
			default:
				monitorMsg = fmt.Sprintf("%.2f msec, status:%s", alert.Value, alert.Message)
			}
		case *mkr.MonitorExpression:
			expression := formatExpressionOneline(m.Expression)
			if alert.Status == "CRITICAL" && m.Critical != nil {
				monitorMsg = fmt.Sprintf("%s %.2f %s %.2f", expression, alert.Value, m.Operator, *m.Critical)
			} else if alert.Status == "WARNING" && m.Warning != nil {
				monitorMsg = fmt.Sprintf("%s %.2f %s %.2f", expression, alert.Value, m.Operator, *m.Warning)
			} else if alert.Status == "UNKNOWN" {
				monitorMsg = fmt.Sprintf("%s", expression)
			} else {
				monitorMsg = fmt.Sprintf("%s %.2f", expression, alert.Value)
			}
		default:
			monitorMsg = fmt.Sprintf("%s", monitor.MonitorType())
		}
		if monitorMsg == "" {
			monitorMsg = monitor.MonitorName()
		} else {
			monitorMsg = monitor.MonitorName() + " " + monitorMsg
		}
	}
	// If alert is caused by check monitoring, take monitorMsg from alert.message
	if alert.Type == "check" {
		monitorMsg = formatCheckMessage(alert.Message)
	}

	statusMsg := alert.Status
	if colorize {
		switch alert.Status {
		case "CRITICAL":
			statusMsg = color.RedString("CRITICAL ")
		case "WARNING":
			statusMsg = color.YellowString("WARNING ")
		case "OK":
			statusMsg = color.GreenString("OK ")
		case "UNKNOWN":
			statusMsg = "UNKNOWN "
		}
	}
	return fmt.Sprintf("%s %s %s %s%s", alert.ID, time.Unix(alert.OpenedAt, 0).Format(layout), statusMsg, monitorMsg, hostMsg)
}

var expressionNewlinePattern = regexp.MustCompile(`\s*[\r\n]+\s*`)

func formatExpressionOneline(expr string) string {
	expr = strings.Trim(expressionNewlinePattern.ReplaceAllString(expr, " "), " ")
	return strings.Replace(strings.Replace(expr, "( ", "(", -1), " )", ")", -1)
}

func formatCheckMessage(msg string) string {
	truncated := false
	if index := strings.IndexAny(msg, "\n\r"); index != -1 {
		msg = msg[0:index]
		truncated = true
	}
	if runes := []rune(msg); len(runes) > 100 {
		msg = string(runes[0:100])
		truncated = true
	}
	if truncated {
		msg = msg + "..."
	}
	return msg
}

func doAlertsRetrieve(c *cli.Context) error {
	client := newMackerelFromContext(c)
	withClosed := c.Bool("with-closed")
	alerts, err := fetchAlerts(client, withClosed, getAlertsLimit(c, withClosed))
	logger.DieIf(err)
	PrettyPrintJSON(alerts)
	return nil
}

func doAlertsList(c *cli.Context) error {
	filterServices := c.StringSlice("service")
	filterStatuses := c.StringSlice("host-status")
	client := newMackerelFromContext(c)
	withClosed := c.Bool("with-closed")
	alerts, err := fetchAlerts(client, withClosed, getAlertsLimit(c, withClosed))
	logger.DieIf(err)

	joinedAlerts := joinMonitorsAndHosts(client, alerts)
	for _, joinAlert := range joinedAlerts {
		if len(filterServices) > 0 {
			found := false
			for _, filterService := range filterServices {
				if joinAlert.Host != nil {
					if _, ok := joinAlert.Host.Roles[filterService]; ok {
						found = true
					}
				} else {
					var service string
					if m, ok := joinAlert.Monitor.(*mkr.MonitorServiceMetric); ok {
						service = m.Service
					} else if m, ok := joinAlert.Monitor.(*mkr.MonitorExternalHTTP); ok {
						service = m.Service
					}
					found = service == filterService
				}
			}
			if !found {
				continue
			}
		}
		if len(filterStatuses) > 0 {
			found := false
			for _, filterStatus := range filterStatuses {
				if joinAlert.Host != nil && joinAlert.Host.Status == filterStatus {
					found = true
				}
			}
			if !found {
				continue
			}
		}
		fmt.Fprintln(color.Output, formatJoinedAlert(joinAlert, c.BoolT("color")))
	}
	return nil
}

func getAlertsLimit(c *cli.Context, withClosed bool) int {
	if c.IsSet("limit") {
		return c.Int("limit")
	}
	if withClosed {
		return defaultAlertsLimit
	}
	// When -limit is not set, mkr alerts should print all the open alerts.
	return math.MaxInt32
}

func fetchAlerts(client *mkr.Client, withClosed bool, limit int) ([]*mkr.Alert, error) {
	if limit < 0 {
		return nil, errors.New("limit should not be negative")
	}
	var resp *mkr.AlertsResp
	var err error
	if withClosed {
		if resp, err = client.FindWithClosedAlerts(); err != nil {
			return nil, err
		}
		if resp.NextID != "" {
			for {
				if limit <= len(resp.Alerts) {
					break
				}
				nextResp, err := client.FindWithClosedAlertsByNextID(resp.NextID)
				if err != nil {
					return nil, err
				}
				resp.Alerts = append(resp.Alerts, nextResp.Alerts...)
				resp.NextID = nextResp.NextID
				if resp.NextID == "" {
					break
				}
				time.Sleep(1 * time.Second)
			}
		}
	} else {
		if resp, err = client.FindAlerts(); err != nil {
			return nil, err
		}
		if resp.NextID != "" {
			for {
				if limit <= len(resp.Alerts) {
					break
				}
				nextResp, err := client.FindAlertsByNextID(resp.NextID)
				if err != nil {
					return nil, err
				}
				resp.Alerts = append(resp.Alerts, nextResp.Alerts...)
				resp.NextID = nextResp.NextID
				if resp.NextID == "" {
					break
				}
				time.Sleep(1 * time.Second)
			}
		}
	}
	if len(resp.Alerts) > limit {
		resp.Alerts = resp.Alerts[:limit]
	}
	return resp.Alerts, nil
}

func doAlertsClose(c *cli.Context) error {
	isVerbose := c.Bool("verbose")
	argAlertIDs := c.Args()
	reason := c.String("reason")

	if len(argAlertIDs) < 1 {
		cli.ShowCommandHelp(c, "alerts")
		os.Exit(1)
	}

	client := newMackerelFromContext(c)
	for _, alertID := range argAlertIDs {
		alert, err := client.CloseAlert(alertID, reason)
		logger.DieIf(err)

		logger.Log("Alert closed", alertID)
		if isVerbose == true {
			PrettyPrintJSON(alert)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package axslogparser

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

// Apache log parser
type Apache struct {
}

var logRe = regexp.MustCompile(
	`(?:(?P<vhost>\S+)\s)?` + // %v(The canonical ServerName/virtual host)
		`(?P<remote_addr>\S+)\s` + // %h(Remote Hostname) $remote_addr
		`\S+\s+` + // %l(Remote Logname)
		`(?P<remote_user>\S+)\s` + // $remote_user
		`\[(?P<time_local>\d{2}/\w{3}/\d{2}(?:\d{2}:){3}\d{2} [-+]\d{4})\]\s` + // $time_local
		`(?P<rest>.*)`)

// Parse for Parser interface
func (ap *Apache) Parse(line string) (*Log, error) {
	matches := logRe.FindStringSubmatch(line)
	if len(matches) < 1 {
		return nil, fmt.Errorf("not matched")
	}
	var rest string
	l := &Log{}
	for i, name := range logRe.SubexpNames() {
		switch name {
		case "vhost":
			l.VirtualHost = matches[i]
		case "remote_addr":
			l.Host = matches[i]
		case "remote_user":
			l.User = matches[i]
		case "time_local":
			l.Time, _ = time.Parse(clfTimeLayout, matches[i])
		case "rest":
			rest = matches[i]
		}
	}
	l.Request, rest = takeQuoted(rest)
	matches = strings.Fields(rest)
	if len(matches) > 1 {
		l.Status, _ = strconv.Atoi(matches[0])
		l.Size, _ = strconv.ParseUint(matches[1], 10, 64)
	}
	l.Referer, rest = takeQuoted(rest)
	l.UA, _ = takeQuoted(rest)
	l.breakdownRequest()
	return l, nil
}

func takeQuoted(line string) (string, string) {
	if line == "" {
		return "", ""
	}
	i := 0
	for ; i < len(line); i++ {
		if line[i] == '"' {
			i++
			break
		}
	}
	if i == len(line) {
		return "", ""
	}
	buf := &bytes.Buffer{}
	escaped := false
	for ; i < len(line); i++ {
		c := line[i]
		if !escaped {
			if c == '"' {
				break
			}
			if c == '\\' {
				escaped = true
				continue
			}
			buf.WriteByte(c)
			continue
		}
		escaped = false
		switch c {
		case 'n':
			buf.WriteByte('\n')
		case 't':
			buf.WriteByte('\t')
		case '\\':
			buf.WriteByte('\\')
		case '"':
			buf.WriteByte('"')
		default:
			buf.WriteByte(c)
		}
	}
	return buf.String(), line[i+1:]
}
<commit_msg>adjust regexp<commit_after>package axslogparser

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

// Apache log parser
type Apache struct {
}

var logRe = regexp.MustCompile(
	`^(?:(?P<vhost>\S+)\s)?` + // %v(The canonical ServerName/virtual host)
		`(?P<remote_addr>\S+)\s` + // %h(Remote Hostname) $remote_addr
		`\S+\s+` + // %l(Remote Logname)
		`(?P<remote_user>\S+)\s` + // $remote_user
		`\[(?P<time_local>\d{2}/\w{3}/\d{2}(?:\d{2}:){3}\d{2} [-+]\d{4})\]\s` + // $time_local
		`(?P<rest>.*)`)

// Parse for Parser interface
func (ap *Apache) Parse(line string) (*Log, error) {
	matches := logRe.FindStringSubmatch(line)
	if len(matches) < 1 {
		return nil, fmt.Errorf("not matched")
	}
	var rest string
	l := &Log{}
	for i, name := range logRe.SubexpNames() {
		switch name {
		case "vhost":
			l.VirtualHost = matches[i]
		case "remote_addr":
			l.Host = matches[i]
		case "remote_user":
			l.User = matches[i]
		case "time_local":
			l.Time, _ = time.Parse(clfTimeLayout, matches[i])
		case "rest":
			rest = matches[i]
		}
	}
	l.Request, rest = takeQuoted(rest)
	matches = strings.Fields(rest)
	if len(matches) > 1 {
		l.Status, _ = strconv.Atoi(matches[0])
		l.Size, _ = strconv.ParseUint(matches[1], 10, 64)
	}
	l.Referer, rest = takeQuoted(rest)
	l.UA, _ = takeQuoted(rest)
	l.breakdownRequest()
	return l, nil
}

func takeQuoted(line string) (string, string) {
	if line == "" {
		return "", ""
	}
	i := 0
	for ; i < len(line); i++ {
		if line[i] == '"' {
			i++
			break
		}
	}
	if i == len(line) {
		return "", ""
	}
	buf := &bytes.Buffer{}
	escaped := false
	for ; i < len(line); i++ {
		c := line[i]
		if !escaped {
			if c == '"' {
				break
			}
			if c == '\\' {
				escaped = true
				continue
			}
			buf.WriteByte(c)
			continue
		}
		escaped = false
		switch c {
		case 'n':
			buf.WriteByte('\n')
		case 't':
			buf.WriteByte('\t')
		case '\\':
			buf.WriteByte('\\')
		case '"':
			buf.WriteByte('"')
		default:
			buf.WriteByte(c)
		}
	}
	return buf.String(), line[i+1:]
}
<|endoftext|>


<commit_before>package route

import "encoding/binary"
import "netlink"
import "netlink/rtnetlink"
import "os"

type Message struct {
  header [12]byte
  attributes []netlink.Attribute
}

func NewMessage(afam byte, dl uint8, sl uint8, tos uint8, t Table, o Origin, s rtnetlink.Scope, T Type, f Flags)(*Message){
  hdr := [12]byte{afam, dl, sl, tos, byte(t), byte(o), byte(s), byte(T)}
  binary.LittleEndian.PutUint32(hdr[8:12], uint32(f))
  return &Message{
    header: hdr,
  }
}

func (self Message)AddressFamily()(byte){ return self.header[0] }
func (self Message)AddressDestLength()(uint8){ return self.header[1] }
func (self Message)AddressSourceLength()(uint8){ return self.header[2] }
func (self Message)TOS()(uint8){ return self.header[3] }
func (self Message)RoutingTable()(Table){ return Table(self.header[4]) }
func (self Message)RouteOrigin()(Origin){ return Origin(self.header[5]) }
func (self Message)AddressScope()(rtnetlink.Scope){ return rtnetlink.Scope(self.header[6]) }
func (self Message)RouteType()(Type){ return Type(self.header[7]) }
func (self Message)Flags()(Flags) { return Flags(binary.LittleEndian.Uint32(self.header[8:12])) }

func (self Message)Attributes()([]netlink.Attribute) { return self.attributes }
func (self *Message)AddAttribute(a netlink.Attribute)(){ self.attributes = append(self.attributes, a) }

func (self *Message)UnmarshalNetlink(in []byte, pad int)(err os.Error){
  if len(in) < 12 {
    err = os.NewError("Too short to be a valid Routing Message")
  }
  if err == nil {
    copy(self.header[0:12], in[0:12])
    self.attributes, err = netlink.UnmarshalAttributes(in[12:], pad)
  }
  return
}

func (self Message)MarshalNetlink(pad int)(out []byte, err os.Error){
  attrbytes, err := netlink.MarshalAttributes(self.attributes, pad)
  if err == nil {
    out = make([]byte, len(attrbytes) + 12)
    copy(out, self.header[0:])
    copy(out[12:], attrbytes)
  }
  return
}
<commit_msg>Use header-styled for Route;  rename struct to Header<commit_after>package route

import "encoding/binary"
import "netlink/rtnetlink"
import "os"

type Header [12]byte

func NewMessage(afam byte, dl uint8, sl uint8, tos uint8, t Table, o Origin, s rtnetlink.Scope, T Type, f Flags)(*Header){
  hdr := Header{afam, dl, sl, tos, byte(t), byte(o), byte(s), byte(T)}
  binary.LittleEndian.PutUint32(hdr[8:12], uint32(f))
  return &hdr
}

func (self Header)AddressFamily()(byte){ return self[0] }
func (self Header)AddressDestLength()(uint8){ return self[1] }
func (self Header)AddressSourceLength()(uint8){ return self[2] }
func (self Header)TOS()(uint8){ return self[3] }
func (self Header)RoutingTable()(Table){ return Table(self[4]) }
func (self Header)RouteOrigin()(Origin){ return Origin(self[5]) }
func (self Header)AddressScope()(rtnetlink.Scope){ return rtnetlink.Scope(self[6]) }
func (self Header)RouteType()(Type){ return Type(self[7]) }
func (self Header)Flags()(Flags) { return Flags(binary.LittleEndian.Uint32(self[8:12])) }

func (self *Header)UnmarshalNetlink(in []byte, pad int)(err os.Error){
  if len(in) < 12 {
    err = os.NewError("Too short to be a valid Routing Message")
  }
  if err == nil {
    copy(self[0:12], in[0:12])
  }
  return
}

func (self Header)MarshalNetlink(pad int)(out []byte, err os.Error){
  if err == nil {
    out = make([]byte, 12)
    copy(out, self[0:])
  }
  return
}
<|endoftext|>


<commit_before>package blobstore

import (
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/x509"
	"encoding/hex"
	"io"
)

type privateKey *rsa.PrivateKey

func createSignValidatedBlobFromReaderGenerator(
	readerGenerator func() io.Reader,
	privKey privateKey,
	dataVersion int64,
	storage BlobStorage,
) (
	// Return values
	bidRet string,
	keyRet string,
	err error,
) {

	// We're using hash of the private key to create the encryption data key
	dataKey := createDataHash(x509.MarshalPKCS1PrivateKey(privKey))

	// Version + encrypted data buffer
	verDataBuffer := bytes.Buffer{}
	serializeInt(dataVersion, &verDataBuffer)

	// Encrypt the data, note we're using the version bytes as IV
	encryptedWriter, key, err := createEncryptor(dataKey, verDataBuffer.Bytes(), &verDataBuffer)
	if err != nil {
		return
	}
	io.Copy(encryptedWriter, readerGenerator())

	// Calculate the signature of version + encrypted data blob
	signature, err := rsa.SignPKCS1v15(
		nil, privKey,
		crypto.SHA512,
		createDataHash(verDataBuffer.Bytes()))
	if err != nil {
		return
	}

	// Generate the public key blob
	pubKey, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)
	if err != nil {
		return
	}

	// Generate the BID from the public key
	bid := hex.EncodeToString(createDataHash(pubKey))

	// Open the blob for writing
	blobWriter, err := storage.NewBlobWriter(bid)
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			blobWriter.Cancel()
		}
	}()

	// Write blob header (without version)
	header := bytes.Buffer{}
	header.WriteByte(validationMethodSign)
	serializeBuffer(pubKey, &header)
	serializeBuffer(signature, &header)

	if _, err = blobWriter.Write(header.Bytes()); err != nil {
		return
	}

	// Write the version and encrypted data
	if _, err = blobWriter.Write(verDataBuffer.Bytes()); err != nil {
		return
	}

	// Ok, we're done here
	return bid, key, nil
}

func createReaderForSignedBlobData(reader io.Reader, bid, key string) (rawReader io.Reader, err error) {

	// Grab the public key blob
	pubkey, err := deserializeBuffer(reader, maxSanePubKeyLength)
	if err != nil {
		return
	}

	// Validate blob id agains public key
	if hex.EncodeToString(createDataHash(pubkey)) != bid {
		return nil, ErrInvalidPublicKeyBid
	}

	// Parse the public key
	pubKeyParsedRaw, err := x509.ParsePKIXPublicKey(pubkey)
	if err != nil {
		return
	}
	pubKeyParsed, ok := pubKeyParsedRaw.(*rsa.PublicKey)
	if !ok {
		return nil, ErrUnknownPublicKeyType
	}

	// Read the signature
	signature, err := deserializeBuffer(reader, maxSaneSignatureLength)
	if err != nil {
		return
	}

	// Read the version
	version, err := deserializeInt(reader)
	if err != nil {
		return
	}

	// TODO: Create validating reader that will check the signature when
	//       we reach EOF
	_, _ = signature, pubKeyParsed

	// Create the decryptor of the content
	verBuffer := bytes.Buffer{}
	serializeInt(version, &verBuffer)
	return createDecryptor(key, verBuffer.Bytes(), reader)
}

func createReaderForSignedBlob(bid string, key string, storage BlobStorage) (rawReader io.Reader, err error) {

	// Get the reader
	encryptedReader, err := storage.NewBlobReader(bid)
	if err != nil {
		return
	}

	// Test the validation method
	validationType, err := deserializeInt(encryptedReader)
	if err != nil {
		return
	}
	if validationType != validationMethodSign {
		return nil, ErrInvalidValidationMethod
	}

	// Get the encryptor
	return createReaderForSignedBlobData(encryptedReader, bid, key)
}
<commit_msg>Make sure to finalize the blob<commit_after>package blobstore

import (
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/x509"
	"encoding/hex"
	"io"
)

type privateKey *rsa.PrivateKey

func createSignValidatedBlobFromReaderGenerator(
	readerGenerator func() io.Reader,
	privKey privateKey,
	dataVersion int64,
	storage BlobStorage,
) (
	// Return values
	bidRet string,
	keyRet string,
	err error,
) {

	// We're using hash of the private key to create the encryption data key
	dataKey := createDataHash(x509.MarshalPKCS1PrivateKey(privKey))

	// Version + encrypted data buffer
	verDataBuffer := bytes.Buffer{}
	serializeInt(dataVersion, &verDataBuffer)

	// Encrypt the data, note we're using the version bytes as IV
	encryptedWriter, key, err := createEncryptor(dataKey, verDataBuffer.Bytes(), &verDataBuffer)
	if err != nil {
		return
	}
	io.Copy(encryptedWriter, readerGenerator())

	// Calculate the signature of version + encrypted data blob
	signature, err := rsa.SignPKCS1v15(
		nil, privKey,
		crypto.SHA512,
		createDataHash(verDataBuffer.Bytes()))
	if err != nil {
		return
	}

	// Generate the public key blob
	pubKey, err := x509.MarshalPKIXPublicKey(&privKey.PublicKey)
	if err != nil {
		return
	}

	// Generate the BID from the public key
	bid := hex.EncodeToString(createDataHash(pubKey))

	// Open the blob for writing
	blobWriter, err := storage.NewBlobWriter(bid)
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			blobWriter.Cancel()
		}
	}()

	// Write blob header (without version)
	header := bytes.Buffer{}
	header.WriteByte(validationMethodSign)
	serializeBuffer(pubKey, &header)
	serializeBuffer(signature, &header)

	if _, err = blobWriter.Write(header.Bytes()); err != nil {
		return
	}

	// Write the version and encrypted data
	if _, err = blobWriter.Write(verDataBuffer.Bytes()); err != nil {
		return
	}

	// Finalize the blob
	if err = blobWriter.Finalize(); err != nil {
		return
	}

	// Ok, we're done here
	return bid, key, nil
}

func createReaderForSignedBlobData(reader io.Reader, bid, key string) (rawReader io.Reader, err error) {

	// Grab the public key blob
	pubkey, err := deserializeBuffer(reader, maxSanePubKeyLength)
	if err != nil {
		return
	}

	// Validate blob id agains public key
	if hex.EncodeToString(createDataHash(pubkey)) != bid {
		return nil, ErrInvalidPublicKeyBid
	}

	// Parse the public key
	pubKeyParsedRaw, err := x509.ParsePKIXPublicKey(pubkey)
	if err != nil {
		return
	}
	pubKeyParsed, ok := pubKeyParsedRaw.(*rsa.PublicKey)
	if !ok {
		return nil, ErrUnknownPublicKeyType
	}

	// Read the signature
	signature, err := deserializeBuffer(reader, maxSaneSignatureLength)
	if err != nil {
		return
	}

	// Read the version
	version, err := deserializeInt(reader)
	if err != nil {
		return
	}

	// TODO: Create validating reader that will check the signature when
	//       we reach EOF
	_, _ = signature, pubKeyParsed

	// Create the decryptor of the content
	verBuffer := bytes.Buffer{}
	serializeInt(version, &verBuffer)
	return createDecryptor(key, verBuffer.Bytes(), reader)
}

func createReaderForSignedBlob(bid string, key string, storage BlobStorage) (rawReader io.Reader, err error) {

	// Get the reader
	encryptedReader, err := storage.NewBlobReader(bid)
	if err != nil {
		return
	}

	// Test the validation method
	validationType, err := deserializeInt(encryptedReader)
	if err != nil {
		return
	}
	if validationType != validationMethodSign {
		return nil, ErrInvalidValidationMethod
	}

	// Get the encryptor
	return createReaderForSignedBlobData(encryptedReader, bid, key)
}
<|endoftext|>


<commit_before>package imagick

/*
#cgo !no_pkgconfig pkg-config: MagickWand MagickCore
#include <wand/MagickWand.h>
*/
import "C"

import (
	"fmt"
	"unsafe"
)

type MagickWand struct {
	mw *C.MagickWand
}

func NewMagickWand() *MagickWand {
	return &MagickWand{mw: C.NewMagickWand()}
}

func (mw *MagickWand) Destroy() {
	if mw.mw == nil {
		return
	}
	mw.mw = C.DestroyMagickWand(mw.mw)
	C.free(unsafe.Pointer(mw.mw))
	mw.mw = nil
}

func (mw *MagickWand) GetImageBlob() []byte {
	clen := C.size_t(0)
	csBlob := C.MagickGetImageBlob(mw.mw, &clen)
	defer mw.relinquishMemory(unsafe.Pointer(csBlob))
	return C.GoBytes(unsafe.Pointer(csBlob), C.int(clen))
}

func (mw *MagickWand) ReadImageBlob(blob []byte) error {
	if len(blob) == 0 {
		return fmt.Errorf("Blob can not be empty")
	}
	res := C.MagickReadImageBlob(mw.mw, unsafe.Pointer(&blob[0]), C.size_t(len(blob)))
	return mw.checkResult(BooleanType(res))
}

func (mw *MagickWand) GetImageHeight() uint {
	return uint(C.MagickGetImageHeight(mw.mw))
}

func (mw *MagickWand) GetImageWidth() uint {
	return uint(C.MagickGetImageWidth(mw.mw))
}

func (mw *MagickWand) CommentImage(comment string) error {
	csComment := C.CString(comment)
	defer C.free(unsafe.Pointer(csComment))
	return mw.checkResult(BooleanType(C.MagickCommentImage(mw.mw, csComment)))
}

func (mw *MagickWand) ThumbnailImage(cols, rows uint) error {
	return mw.checkResult(BooleanType(C.MagickThumbnailImage(mw.mw, C.size_t(cols), C.size_t(rows))))
}

func (mw *MagickWand) ScaleImage(cols, rows uint) error {
	return mw.checkResult(BooleanType(C.MagickScaleImage(mw.mw, C.size_t(cols), C.size_t(rows))))
}

func (mw *MagickWand) CropImage(width, height uint, x, y int) error {
	res := C.MagickCropImage(mw.mw, C.size_t(width), C.size_t(height), C.ssize_t(x), C.ssize_t(y))
	return mw.checkResult(BooleanType(res))
}

func (mw *MagickWand) FlipImage() error {
	return mw.checkResult(BooleanType(C.MagickFlipImage(mw.mw)))
}

func (mw *MagickWand) RotateImage(background *PixelWand, degrees float64) error {
	return mw.checkResult(BooleanType(C.MagickRotateImage(mw.mw, background.pw, C.double(degrees))))
}

func (mw *MagickWand) FlopImage() error {
	return mw.checkResult(BooleanType(C.MagickFlopImage(mw.mw)))
}

func (mw *MagickWand) GetImageOrientation() OrientationType {
	return OrientationType(C.MagickGetImageOrientation(mw.mw))
}

func (mw *MagickWand) SetImageOrientation(orientation OrientationType) error {
	res := C.MagickSetImageOrientation(mw.mw, C.OrientationType(orientation))
	return mw.checkResult(BooleanType(res))
}

func (mw *MagickWand) ReadImage(filename string) error {
	csFilename := C.CString(filename)
	defer C.free(unsafe.Pointer(csFilename))
	return mw.checkResult(BooleanType(C.MagickReadImage(mw.mw, csFilename)))
}

func (mw *MagickWand) CompositeImage(source *MagickWand, compose CompositeOperator, x, y int) error {
	res := C.MagickCompositeImage(mw.mw, source.mw, C.CompositeOperator(compose), C.ssize_t(x), C.ssize_t(y))
	return mw.checkResult(BooleanType(res))
}

func (mw *MagickWand) checkResult(res BooleanType) error {
	if res == BOOLEAN_TYPE_TRUE {
		return nil
	}
	return mw.GetLastError()
}

func (mw *MagickWand) GetLastError() error {
	var exceptionType C.ExceptionType
	csDescription := C.MagickGetException(mw.mw, &exceptionType)
	defer mw.relinquishMemory(unsafe.Pointer(csDescription))
	if ExceptionType(exceptionType) != EXCEPTION_UNDEFINED {
		mw.clearException()
		return &MagickWandException{ExceptionType(C.int(exceptionType)), C.GoString(csDescription)}
	}
	return nil
}

func (mw *MagickWand) relinquishMemory(ptr unsafe.Pointer) {
	C.MagickRelinquishMemory(ptr)
}

func (mw *MagickWand) clearException() bool {
	return BOOLEAN_TYPE_TRUE == BooleanType(C.MagickClearException(mw.mw))
}
<commit_msg>ExceptionType should cast result to int<commit_after>package imagick

/*
#cgo !no_pkgconfig pkg-config: MagickWand MagickCore
#include <wand/MagickWand.h>
*/
import "C"

import (
	"fmt"
	"unsafe"
)

type MagickWand struct {
	mw *C.MagickWand
}

func NewMagickWand() *MagickWand {
	return &MagickWand{mw: C.NewMagickWand()}
}

func (mw *MagickWand) Destroy() {
	if mw.mw == nil {
		return
	}
	mw.mw = C.DestroyMagickWand(mw.mw)
	C.free(unsafe.Pointer(mw.mw))
	mw.mw = nil
}

func (mw *MagickWand) GetImageBlob() []byte {
	clen := C.size_t(0)
	csBlob := C.MagickGetImageBlob(mw.mw, &clen)
	defer mw.relinquishMemory(unsafe.Pointer(csBlob))
	return C.GoBytes(unsafe.Pointer(csBlob), C.int(clen))
}

func (mw *MagickWand) ReadImageBlob(blob []byte) error {
	if len(blob) == 0 {
		return fmt.Errorf("Blob can not be empty")
	}
	res := C.MagickReadImageBlob(mw.mw, unsafe.Pointer(&blob[0]), C.size_t(len(blob)))
	return mw.checkResult(BooleanType(res))
}

func (mw *MagickWand) GetImageHeight() uint {
	return uint(C.MagickGetImageHeight(mw.mw))
}

func (mw *MagickWand) GetImageWidth() uint {
	return uint(C.MagickGetImageWidth(mw.mw))
}

func (mw *MagickWand) CommentImage(comment string) error {
	csComment := C.CString(comment)
	defer C.free(unsafe.Pointer(csComment))
	return mw.checkResult(BooleanType(C.MagickCommentImage(mw.mw, csComment)))
}

func (mw *MagickWand) ThumbnailImage(cols, rows uint) error {
	return mw.checkResult(BooleanType(C.MagickThumbnailImage(mw.mw, C.size_t(cols), C.size_t(rows))))
}

func (mw *MagickWand) ScaleImage(cols, rows uint) error {
	return mw.checkResult(BooleanType(C.MagickScaleImage(mw.mw, C.size_t(cols), C.size_t(rows))))
}

func (mw *MagickWand) CropImage(width, height uint, x, y int) error {
	res := C.MagickCropImage(mw.mw, C.size_t(width), C.size_t(height), C.ssize_t(x), C.ssize_t(y))
	return mw.checkResult(BooleanType(res))
}

func (mw *MagickWand) FlipImage() error {
	return mw.checkResult(BooleanType(C.MagickFlipImage(mw.mw)))
}

func (mw *MagickWand) RotateImage(background *PixelWand, degrees float64) error {
	return mw.checkResult(BooleanType(C.MagickRotateImage(mw.mw, background.pw, C.double(degrees))))
}

func (mw *MagickWand) FlopImage() error {
	return mw.checkResult(BooleanType(C.MagickFlopImage(mw.mw)))
}

func (mw *MagickWand) GetImageOrientation() OrientationType {
	return OrientationType(C.MagickGetImageOrientation(mw.mw))
}

func (mw *MagickWand) SetImageOrientation(orientation OrientationType) error {
	res := C.MagickSetImageOrientation(mw.mw, C.OrientationType(orientation))
	return mw.checkResult(BooleanType(res))
}

func (mw *MagickWand) ReadImage(filename string) error {
	csFilename := C.CString(filename)
	defer C.free(unsafe.Pointer(csFilename))
	return mw.checkResult(BooleanType(C.MagickReadImage(mw.mw, csFilename)))
}

func (mw *MagickWand) CompositeImage(source *MagickWand, compose CompositeOperator, x, y int) error {
	res := C.MagickCompositeImage(mw.mw, source.mw, C.CompositeOperator(compose), C.ssize_t(x), C.ssize_t(y))
	return mw.checkResult(BooleanType(res))
}

func (mw *MagickWand) checkResult(res BooleanType) error {
	if res == BOOLEAN_TYPE_TRUE {
		return nil
	}
	return mw.GetLastError()
}

func (mw *MagickWand) GetLastError() error {
	var exceptionType C.ExceptionType
	csDescription := C.MagickGetException(mw.mw, &exceptionType)
	defer mw.relinquishMemory(unsafe.Pointer(csDescription))
	if ExceptionType(exceptionType) != EXCEPTION_UNDEFINED {
		mw.clearException()
		return &MagickWandException{ExceptionType(exceptionType), C.GoString(csDescription)}
	}
	return nil
}

func (mw *MagickWand) relinquishMemory(ptr unsafe.Pointer) {
	C.MagickRelinquishMemory(ptr)
}

func (mw *MagickWand) clearException() bool {
	return BOOLEAN_TYPE_TRUE == BooleanType(C.MagickClearException(mw.mw))
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"sort"
	"strings"
)

type AgentInfoCommand struct {
	Meta
}

func (c *AgentInfoCommand) Help() string {
	helpText := `
Usage: nomad agent-info [options]

  Display status information about the local agent.

General Options:

  ` + generalOptionsUsage()
	return strings.TrimSpace(helpText)
}

func (c *AgentInfoCommand) Synopsis() string {
	return "Display status information about the local agent"
}

func (c *AgentInfoCommand) Run(args []string) int {
	flags := c.Meta.FlagSet("agent-info", FlagSetClient)
	flags.Usage = func() { c.Ui.Output(c.Help()) }
	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Check that we either got no jobs or exactly one.
	args = flags.Args()
	if len(args) > 0 {
		c.Ui.Error(c.Help())
		return 1
	}

	// Get the HTTP client
	client, err := c.Meta.Client()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
		return 1
	}

	// Query the agent info
	info, err := client.Agent().Self()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error querying agent info: %s", err))
		return 1
	}

	// Sort and output agent info
	var stats map[string]interface{}
	stats, _ = info["stats"]
	stats_keys := make([]string, 0, len(stats))
	for key := range stats {
		stats_keys = append(stats_keys, key)
	}
	sort.Strings(stats_keys)

	for _, key := range stats_keys {
		c.Ui.Output(key)
		d, _ := stats[key].(map[string]interface{})
		d_keys := make([]string, 0, len(d))
		for key := range d {
			d_keys = append(d_keys, key)
		}
		sort.Strings(d_keys)

		for _, key := range d_keys {
			c.Ui.Output(fmt.Sprintf("  %s = %v", key, d[key]))
		}
	}

	return 0
}
<commit_msg>small refactor<commit_after>package command

import (
	"fmt"
	"sort"
	"strings"
)

type AgentInfoCommand struct {
	Meta
}

func (c *AgentInfoCommand) Help() string {
	helpText := `
Usage: nomad agent-info [options]

  Display status information about the local agent.

General Options:

  ` + generalOptionsUsage()
	return strings.TrimSpace(helpText)
}

func (c *AgentInfoCommand) Synopsis() string {
	return "Display status information about the local agent"
}

func (c *AgentInfoCommand) Run(args []string) int {
	flags := c.Meta.FlagSet("agent-info", FlagSetClient)
	flags.Usage = func() { c.Ui.Output(c.Help()) }
	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Check that we either got no jobs or exactly one.
	args = flags.Args()
	if len(args) > 0 {
		c.Ui.Error(c.Help())
		return 1
	}

	// Get the HTTP client
	client, err := c.Meta.Client()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
		return 1
	}

	// Query the agent info
	info, err := client.Agent().Self()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error querying agent info: %s", err))
		return 1
	}

	// Sort and output agent info
	var stats map[string]interface{}
	stats, _ = info["stats"]
	statsKeys := make([]string, 0, len(stats))
	for key := range stats {
		statsKeys = append(statsKeys, key)
	}
	sort.Strings(statsKeys)

	for _, key := range statsKeys {
		c.Ui.Output(key)
		statsData, _ := stats[key].(map[string]interface{})
		statsDataKeys := make([]string, 0, len(statsData))
		for key := range statsData {
			statsDataKeys = append(statsDataKeys, key)
		}
		sort.Strings(statsDataKeys)

		for _, key := range statsDataKeys {
			c.Ui.Output(fmt.Sprintf("  %s = %v", key, statsData[key]))
		}
	}

	return 0
}
<|endoftext|>


<commit_before>// Copyright © 2016-2017 Phil Pennock.
// All rights reserved, except as granted under license.
// Licensed per file LICENSE.txt

package code

import (
	"encoding/hex"
	"errors"
	"regexp"
	"strconv"
	"strings"
	"unicode/utf8"

	"github.com/atotto/clipboard"
	"github.com/spf13/cobra"

	"github.com/philpennock/character/resultset"
	"github.com/philpennock/character/sources"
	"github.com/philpennock/character/unicode"

	"github.com/philpennock/character/commands/root"
)

var flags struct {
	base      intconvBase
	clipboard bool
	livevim   bool
	utf8hex   bool
}

// FIXME: make dedicated type, embed search info

// ErrUnknownCodepoint means the specified codepoint is not assigned
var ErrUnknownCodepoint = errors.New("unknown character codepoint")

// When decoding, we may encounter problems
type deferredError struct {
	arg string
	err error
}

var codeCmd = &cobra.Command{
	Use:   "code [codepoint ...]",
	Short: "shows character with codepoint",
	Run: func(cmd *cobra.Command, args []string) {
		if err := resultset.FlagsOkay(); err != nil {
			root.Errorf("%s\n", err)
			return
		}

		srcs := sources.NewFast()
		if flags.livevim {
			srcs.LoadLiveVim()
		}

		// If given utf8hex flag, then we need to pre-munge the parameters
		deferredErrors := make([]deferredError, 0, 20)

		if flags.utf8hex {
			// WAG the capacity
			newargs := make([]string, 0, len(args)*4)
			matchHexPairSeq := regexp.MustCompile(`^(?:[%=][0-9A-Fa-f]{2})+`)

			// If we have %-encoded, then take non-%-preceded entries as literal character
			// If we don't, then assume that we just have hex strings
			// Handle = too, for MIME HDR encoding
			// We handle either, but only one or the other per command-invocation.
			var escapeChar rune = 0

			for _, arg := range args {
				if escapeChar == 0 {
					if strings.ContainsRune(arg, '%') {
						escapeChar = '%'
					} else if strings.ContainsRune(arg, '=') {
						escapeChar = '='
					}
				}

				if escapeChar != 0 && strings.ContainsRune(arg, escapeChar) {
					for len(arg) > 0 {
						nextEscape := strings.IndexRune(arg, escapeChar)
						if nextEscape < 0 {
							for _, c := range arg {
								newargs = append(newargs, strconv.Itoa(int(c)))
							}
							arg = ""
							continue
						}
						if nextEscape > 0 {
							for _, c := range arg[:nextEscape] {
								newargs = append(newargs, strconv.Itoa(int(c)))
							}
							arg = arg[nextEscape:]
							// do not 'continue', handle inline immediately next
						}
						matches := matchHexPairSeq.FindStringSubmatch(arg)
						if matches == nil {
							emsg := "malformed " + string(escapeChar) + "hex sequene"
							deferredErrors = append(deferredErrors, deferredError{arg: arg, err: errors.New(emsg)})
							arg = ""
							continue
						}
						got := matches[0]
						arg = arg[len(got):]
						got = strings.Replace(got, string(escapeChar), "", -1)

						toAdd, defErr := codepointsFromHexString(got)
						if toAdd != nil {
							newargs = append(newargs, toAdd...)
						}
						if defErr != nil {
							deferredErrors = append(deferredErrors, *defErr)
							continue
						}
					}
				} else {
					toAdd, defErr := codepointsFromHexString(arg)
					if toAdd != nil {
						newargs = append(newargs, toAdd...)
					}
					if defErr != nil {
						deferredErrors = append(deferredErrors, *defErr)
						continue
					}
				}
			}
			args = newargs
		}

		results := resultset.New(srcs, len(args))
		for _, e := range deferredErrors {
			results.AddError(e.arg, e.err)
		}

		for _, arg := range args {
			ci, err := findCharInfoByCodepoint(srcs.Unicode, arg)
			if err != nil {
				root.Errored()
				results.AddError(arg, err)
				continue
			}
			results.AddCharInfo(ci)
		}

		if flags.clipboard {
			err := clipboard.WriteAll(results.StringPlain(results.RunePrintType()))
			if err != nil {
				root.Errored()
				results.AddError("<clipboard>", err)
			}
		}

		results.RenderPerCmdline(resultset.PRINT_RUNE)
	},
}

func init() {
	codeCmd.Flags().BoolVarP(&flags.clipboard, "clipboard", "c", false, "copy resulting chars to clipboard too")
	codeCmd.Flags().BoolVarP(&flags.livevim, "livevim", "l", false, "load full vim data (for verbose)")
	codeCmd.Flags().BoolVarP(&flags.utf8hex, "utf8hex", "H", false, "take UTF-8 Hex-encoded codepoint")
	codeCmd.Flags().VarP(&flags.base, "base", "b", "numeric base for code-ponts [default: usual parse rules]")
	resultset.RegisterCmdFlags(codeCmd, true) // verbose v | net-verbose N | internal-debug; enable oneline
	if clipboard.Unsupported {
		// We don't want to only register the flag if clipboard is supported,
		// because that makes client portability more problematic.  Instead, we
		// just hide it to avoid offering something we can't honour, even
		// though we'll accept the option (and show an error) if given.
		codeCmd.Flags().MarkHidden("clipboard")
	}
	// FIXME: support verbose results without tables
	root.AddCommand(codeCmd)
}

func findCharInfoByCodepoint(u unicode.Unicode, needle string) (unicode.CharInfo, error) {
	n32, err := strconv.ParseInt(needle, flags.base.Int(), 32)
	if err != nil {
		return unicode.CharInfo{}, err
	}
	n := rune(n32)

	if ci, ok := u.ByRune[n]; ok {
		return ci, nil
	}
	return unicode.CharInfo{}, ErrUnknownCodepoint
}

func codepointsFromHexString(hs string) ([]string, *deferredError) {
	seq, err := hex.DecodeString(hs)
	if err != nil {
		return nil, &deferredError{arg: hs, err: err}
	}
	res := make([]string, 0, len(seq))
	errorOffset := 0
	for len(seq) > 0 {
		r, sz := utf8.DecodeRune(seq)
		if r == utf8.RuneError && (sz == 0 || sz == 1) {
			return res, &deferredError{arg: hs[errorOffset*2:], err: errors.New("invalid rune")}
		}
		if sz == 0 {
			return res, &deferredError{arg: hs[errorOffset*2:], err: errors.New("API broken (rune size 0)")}
		}
		seq = seq[sz:]
		errorOffset += sz
		res = append(res, strconv.Itoa(int(r)))
	}
	return res, nil
}
<commit_msg>code: handle U+ prefix ⇒ base 16<commit_after>// Copyright © 2016-2017 Phil Pennock.
// All rights reserved, except as granted under license.
// Licensed per file LICENSE.txt

package code

import (
	"encoding/hex"
	"errors"
	"regexp"
	"strconv"
	"strings"
	"unicode/utf8"

	"github.com/atotto/clipboard"
	"github.com/spf13/cobra"

	"github.com/philpennock/character/resultset"
	"github.com/philpennock/character/sources"
	"github.com/philpennock/character/unicode"

	"github.com/philpennock/character/commands/root"
)

var flags struct {
	base      intconvBase
	clipboard bool
	livevim   bool
	utf8hex   bool
}

// FIXME: make dedicated type, embed search info

// ErrUnknownCodepoint means the specified codepoint is not assigned
var ErrUnknownCodepoint = errors.New("unknown character codepoint")

// When decoding, we may encounter problems
type deferredError struct {
	arg string
	err error
}

var codeCmd = &cobra.Command{
	Use:   "code [codepoint ...]",
	Short: "shows character with codepoint",
	Run: func(cmd *cobra.Command, args []string) {
		if err := resultset.FlagsOkay(); err != nil {
			root.Errorf("%s\n", err)
			return
		}

		srcs := sources.NewFast()
		if flags.livevim {
			srcs.LoadLiveVim()
		}

		// If given utf8hex flag, then we need to pre-munge the parameters
		deferredErrors := make([]deferredError, 0, 20)

		if flags.utf8hex {
			// WAG the capacity
			newargs := make([]string, 0, len(args)*4)
			matchHexPairSeq := regexp.MustCompile(`^(?:[%=][0-9A-Fa-f]{2})+`)

			// If we have %-encoded, then take non-%-preceded entries as literal character
			// If we don't, then assume that we just have hex strings
			// Handle = too, for MIME HDR encoding
			// We handle either, but only one or the other per command-invocation.
			var escapeChar rune = 0

			for _, arg := range args {
				if escapeChar == 0 {
					if strings.ContainsRune(arg, '%') {
						escapeChar = '%'
					} else if strings.ContainsRune(arg, '=') {
						escapeChar = '='
					}
				}

				if escapeChar != 0 && strings.ContainsRune(arg, escapeChar) {
					for len(arg) > 0 {
						nextEscape := strings.IndexRune(arg, escapeChar)
						if nextEscape < 0 {
							for _, c := range arg {
								newargs = append(newargs, strconv.Itoa(int(c)))
							}
							arg = ""
							continue
						}
						if nextEscape > 0 {
							for _, c := range arg[:nextEscape] {
								newargs = append(newargs, strconv.Itoa(int(c)))
							}
							arg = arg[nextEscape:]
							// do not 'continue', handle inline immediately next
						}
						matches := matchHexPairSeq.FindStringSubmatch(arg)
						if matches == nil {
							emsg := "malformed " + string(escapeChar) + "hex sequence"
							deferredErrors = append(deferredErrors, deferredError{arg: arg, err: errors.New(emsg)})
							arg = ""
							continue
						}
						got := matches[0]
						arg = arg[len(got):]
						got = strings.Replace(got, string(escapeChar), "", -1)

						toAdd, defErr := codepointsFromHexString(got)
						if toAdd != nil {
							newargs = append(newargs, toAdd...)
						}
						if defErr != nil {
							deferredErrors = append(deferredErrors, *defErr)
							continue
						}
					}
				} else {
					toAdd, defErr := codepointsFromHexString(arg)
					if toAdd != nil {
						newargs = append(newargs, toAdd...)
					}
					if defErr != nil {
						deferredErrors = append(deferredErrors, *defErr)
						continue
					}
				}
			}
			args = newargs
		}

		results := resultset.New(srcs, len(args))
		for _, e := range deferredErrors {
			results.AddError(e.arg, e.err)
		}

		for _, arg := range args {
			ci, err := findCharInfoByCodepoint(srcs.Unicode, arg)
			if err != nil {
				root.Errored()
				results.AddError(arg, err)
				continue
			}
			results.AddCharInfo(ci)
		}

		if flags.clipboard {
			err := clipboard.WriteAll(results.StringPlain(results.RunePrintType()))
			if err != nil {
				root.Errored()
				results.AddError("<clipboard>", err)
			}
		}

		results.RenderPerCmdline(resultset.PRINT_RUNE)
	},
}

func init() {
	codeCmd.Flags().BoolVarP(&flags.clipboard, "clipboard", "c", false, "copy resulting chars to clipboard too")
	codeCmd.Flags().BoolVarP(&flags.livevim, "livevim", "l", false, "load full vim data (for verbose)")
	codeCmd.Flags().BoolVarP(&flags.utf8hex, "utf8hex", "H", false, "take UTF-8 Hex-encoded codepoint")
	codeCmd.Flags().VarP(&flags.base, "base", "b", "numeric base for code-ponts [default: usual parse rules]")
	resultset.RegisterCmdFlags(codeCmd, true) // verbose v | net-verbose N | internal-debug; enable oneline
	if clipboard.Unsupported {
		// We don't want to only register the flag if clipboard is supported,
		// because that makes client portability more problematic.  Instead, we
		// just hide it to avoid offering something we can't honour, even
		// though we'll accept the option (and show an error) if given.
		codeCmd.Flags().MarkHidden("clipboard")
	}
	// FIXME: support verbose results without tables
	root.AddCommand(codeCmd)
}

func findCharInfoByCodepoint(u unicode.Unicode, needle string) (unicode.CharInfo, error) {
	parseBase := flags.base.Int()
	if !flags.utf8hex && strings.HasPrefix(needle, "U+") {
		needle = needle[2:]
		parseBase = 16
	}
	n32, err := strconv.ParseInt(needle, parseBase, 32)
	if err != nil {
		return unicode.CharInfo{}, err
	}
	n := rune(n32)

	if ci, ok := u.ByRune[n]; ok {
		return ci, nil
	}
	return unicode.CharInfo{}, ErrUnknownCodepoint
}

func codepointsFromHexString(hs string) ([]string, *deferredError) {
	seq, err := hex.DecodeString(hs)
	if err != nil {
		return nil, &deferredError{arg: hs, err: err}
	}
	res := make([]string, 0, len(seq))
	errorOffset := 0
	for len(seq) > 0 {
		r, sz := utf8.DecodeRune(seq)
		if r == utf8.RuneError && (sz == 0 || sz == 1) {
			return res, &deferredError{arg: hs[errorOffset*2:], err: errors.New("invalid rune")}
		}
		if sz == 0 {
			return res, &deferredError{arg: hs[errorOffset*2:], err: errors.New("API broken (rune size 0)")}
		}
		seq = seq[sz:]
		errorOffset += sz
		res = append(res, strconv.Itoa(int(r)))
	}
	return res, nil
}
<|endoftext|>


<commit_before>package commands

var cmdSubmodule = &Command{
	Run:          submodule,
	GitExtension: true,
	Usage:        "submodule add [-p] OPTIONS [USER/]REPOSITORY DIRECTORY",
	Short:        "Initialize, update or inspect submodules",
	Long: `Submodule repository "git://github.com/USER/REPOSITORY.git" into
DIRECTORY as  with  git-submodule(1).  When  USER/  is  omitted,
assumes   your   GitHub  login.  With  -p,  use  private  remote
"git@github.com:USER/REPOSITORY.git".`,
}

func init() {
	CmdRunner.Use(cmdSubmodule)
}

/**
  $ gh submodule add jingweno/gh vendor/gh
  > git submodule add git://github.com/jingweno/gh.git vendor/gh

  $ gh submodule add -p jingweno/gh vendor/gh
  > git submodule add git@github.com:jingweno/gh.git vendor/gh

  $ gh submodule add -b gh --name gh jingweno/gh vendor/gh
  > git submodule add -b gh --name gh git://github.com/jingweno/gh.git vendor/gh
**/

func submodule(command *Command, args *Args) {
	if !args.IsParamsEmpty() {
		transformSubmoduleArgs(args)
	}
}

func transformSubmoduleArgs(args *Args) {
	var idx int
	if idx = args.IndexOfParam("add"); idx == -1 {
		return
	}
	args.RemoveParam(idx)
	transformCloneArgs(args)
	args.InsertParam(idx, "add")
}
<commit_msg>Log the submodule process.<commit_after>package commands

var cmdSubmodule = &Command{
	Run:          submodule,
	GitExtension: true,
	Usage:        "submodule add [-p] OPTIONS [USER/]REPOSITORY DIRECTORY",
	Short:        "Initialize, update or inspect submodules",
	Long: `Submodule repository "git://github.com/USER/REPOSITORY.git" into
DIRECTORY as  with  git-submodule(1).  When  USER/  is  omitted,
assumes   your   GitHub  login.  With  -p,  use  private  remote
"git@github.com:USER/REPOSITORY.git".`,
}

func init() {
	CmdRunner.Use(cmdSubmodule)
}

/**
  $ gh submodule add jingweno/gh vendor/gh
  > git submodule add git://github.com/jingweno/gh.git vendor/gh

  $ gh submodule add -p jingweno/gh vendor/gh
  > git submodule add git@github.com:jingweno/gh.git vendor/gh

  $ gh submodule add -b gh --name gh jingweno/gh vendor/gh
  > git submodule add -b gh --name gh git://github.com/jingweno/gh.git vendor/gh
**/

func submodule(command *Command, args *Args) {
	fmt.Println(args)
	if !args.IsParamsEmpty() {
		transformSubmoduleArgs(args)
	}
}

func transformSubmoduleArgs(args *Args) {
	var idx int
	if idx = args.IndexOfParam("add"); idx == -1 {
		fmt.Println("`add` not found, skipping")
		return
	}
	fmt.Println("`add` found")
	args.RemoveParam(idx)
	transformCloneArgs(args)
	args.InsertParam(idx, "add")
	fmt.Println(args)
}
<|endoftext|>


<commit_before>package pollarrho

import (
	"errors"
	"math"
)

func gcd(a, b int) int {
	if b == 0 {
		return a
	} else {
		return gcd(b, a%b)
	}
}

func multMod(a, b, m int) int {
	res := 0
	a = a % m
	for b != 0 {
		if (b & 1) != 0 {
			res = (res + a) % m
		}
		a = (a * 2) % m
		b = b / 2
	}
	return res
}

func PollarRho(num, c int) (int, error) {
	x := 1
	y := 1
	p := 1

	for p == 1 {
		x = (multMod(x, x, num) + c) % num
		ty := (multMod(y, y, num) + c) % num
		y = (multMod(ty, ty, num) + c) % num
		if x == y {
			if math.Sqrt(float64(num)) < float64(c) {
				return -1, errors.New("PollarRho: factor error")
			}
			return PollarRho(num, c+1)
		}

		p = gcd(num, int(math.Abs(float64(x-y))))

	}

	return p, nil
}

func Factor(num int) []int {
	var prims []int
	for num != 1 {
		p, err := PollarRho(num, 1)
		if err != nil {
			prims = append(prims, num)
			break
		}
		num = num / p
		prims = append(prims, p)

	}

	return prims
}
<commit_msg>要素のすべてが素数であるか確かめる関数を追加<commit_after>package pollarrho

import (
	"errors"
	"math"
)

func gcd(a, b int) int {
	if b == 0 {
		return a
	} else {
		return gcd(b, a%b)
	}
}

func multMod(a, b, m int) int {
	res := 0
	a = a % m
	for b != 0 {
		if (b & 1) != 0 {
			res = (res + a) % m
		}
		a = (a * 2) % m
		b = b / 2
	}
	return res
}

func PollarRho(num, c int) (int, error) {
	x := 1
	y := 1
	p := 1

	for p == 1 {
		x = (multMod(x, x, num) + c) % num
		ty := (multMod(y, y, num) + c) % num
		y = (multMod(ty, ty, num) + c) % num
		if x == y {
			if math.Sqrt(float64(num)) < float64(c) {
				return -1, errors.New("PollarRho: factor error")
			}
			return PollarRho(num, c+1)
		}

		p = gcd(num, int(math.Abs(float64(x-y))))

	}

	return p, nil
}

func allPrime(num []int) bool {
	for _, i := range num {
		_, err := PollarRho(i, 1)
		if err != nil {
			return false
		}
	}

	return true
}

func Factor(num int) []int {
	var prims []int
	for num != 1 {
		p, err := PollarRho(num, 1)
		if err != nil {
			prims = append(prims, num)
			break
		}
		num = num / p
		prims = append(prims, p)

	}

	return prims
}
<|endoftext|>


<commit_before>package net

import (
	"net"

	"github.com/v2ray/v2ray-core/common/log"
)

// Address represents a network address to be communicated with. It may be an IP address or domain
// address, not both. This interface doesn't resolve IP address for a given domain.
type Address interface {
	IP() net.IP     // IP of this Address
	Domain() string // Domain of this Address

	IsIPv4() bool   // True if this Address is an IPv4 address
	IsIPv6() bool   // True if this Address is an IPv6 address
	IsDomain() bool // True if this Address is an domain address

	String() string // String representation of this Address
}

func allZeros(data []byte) bool {
	for _, v := range data {
		if v != 0 {
			return false
		}
	}
	return true
}

// IPAddress creates an Address with given IP and port.
func IPAddress(ip []byte) Address {
	switch len(ip) {
	case net.IPv4len:
		return &IPv4Address{
			ip: [4]byte{ip[0], ip[1], ip[2], ip[3]},
		}
	case net.IPv6len:
		if allZeros(ip[0:10]) && ip[10] == 0xff && ip[11] == 0xff {
			return IPAddress(ip[12:16])
		}
		return &IPv6Address{
			ip: [16]byte{
				ip[0], ip[1], ip[2], ip[3],
				ip[4], ip[5], ip[6], ip[7],
				ip[8], ip[9], ip[10], ip[11],
				ip[12], ip[13], ip[14], ip[15],
			},
		}
	default:
		log.Error("Invalid IP format: %v", ip)
		return nil
	}
}

// DomainAddress creates an Address with given domain and port.
func DomainAddress(domain string) Address {
	return &DomainAddressImpl{
		domain: domain,
	}
}

type address struct {
}

type IPv4Address struct {
	ip [4]byte
}

func (addr *IPv4Address) IP() net.IP {
	return net.IP(addr.ip[:])
}

func (addr *IPv4Address) Domain() string {
	panic("Calling Domain() on an IPv4Address.")
}

func (addr *IPv4Address) IsIPv4() bool {
	return true
}

func (addr *IPv4Address) IsIPv6() bool {
	return false
}

func (addr *IPv4Address) IsDomain() bool {
	return false
}

func (this *IPv4Address) String() string {
	return this.IP().String()
}

type IPv6Address struct {
	ip [16]byte
}

func (addr *IPv6Address) IP() net.IP {
	return net.IP(addr.ip[:])
}

func (addr *IPv6Address) Domain() string {
	panic("Calling Domain() on an IPv6Address.")
}

func (addr *IPv6Address) IsIPv4() bool {
	return false
}

func (addr *IPv6Address) IsIPv6() bool {
	return true
}

func (addr *IPv6Address) IsDomain() bool {
	return false
}

func (this *IPv6Address) String() string {
	return "[" + this.IP().String() + "]"
}

type DomainAddressImpl struct {
	domain string
}

func (addr *DomainAddressImpl) IP() net.IP {
	panic("Calling IP() on a DomainAddress.")
}

func (addr *DomainAddressImpl) Domain() string {
	return addr.domain
}

func (addr *DomainAddressImpl) IsIPv4() bool {
	return false
}

func (addr *DomainAddressImpl) IsIPv6() bool {
	return false
}

func (addr *DomainAddressImpl) IsDomain() bool {
	return true
}

func (this *DomainAddressImpl) String() string {
	return this.domain
}
<commit_msg>simplify address<commit_after>package net

import (
	"net"

	"github.com/v2ray/v2ray-core/common/log"
)

// Address represents a network address to be communicated with. It may be an IP address or domain
// address, not both. This interface doesn't resolve IP address for a given domain.
type Address interface {
	IP() net.IP     // IP of this Address
	Domain() string // Domain of this Address

	IsIPv4() bool   // True if this Address is an IPv4 address
	IsIPv6() bool   // True if this Address is an IPv6 address
	IsDomain() bool // True if this Address is an domain address

	String() string // String representation of this Address
}

func allZeros(data []byte) bool {
	for _, v := range data {
		if v != 0 {
			return false
		}
	}
	return true
}

// IPAddress creates an Address with given IP and port.
func IPAddress(ip []byte) Address {
	switch len(ip) {
	case net.IPv4len:
		var addr IPv4Address = [4]byte{ip[0], ip[1], ip[2], ip[3]}
		return &addr
	case net.IPv6len:
		if allZeros(ip[0:10]) && ip[10] == 0xff && ip[11] == 0xff {
			return IPAddress(ip[12:16])
		}
		var addr IPv6Address = [16]byte{
			ip[0], ip[1], ip[2], ip[3],
			ip[4], ip[5], ip[6], ip[7],
			ip[8], ip[9], ip[10], ip[11],
			ip[12], ip[13], ip[14], ip[15],
		}
		return &addr
	default:
		log.Error("Invalid IP format: %v", ip)
		return nil
	}
}

// DomainAddress creates an Address with given domain and port.
func DomainAddress(domain string) Address {
	var addr DomainAddressImpl = DomainAddressImpl(domain)
	return &addr
}

type IPv4Address [4]byte

func (addr *IPv4Address) IP() net.IP {
	return net.IP(addr[:])
}

func (addr *IPv4Address) Domain() string {
	panic("Calling Domain() on an IPv4Address.")
}

func (addr *IPv4Address) IsIPv4() bool {
	return true
}

func (addr *IPv4Address) IsIPv6() bool {
	return false
}

func (addr *IPv4Address) IsDomain() bool {
	return false
}

func (this *IPv4Address) String() string {
	return this.IP().String()
}

type IPv6Address [16]byte

func (addr *IPv6Address) IP() net.IP {
	return net.IP(addr[:])
}

func (addr *IPv6Address) Domain() string {
	panic("Calling Domain() on an IPv6Address.")
}

func (addr *IPv6Address) IsIPv4() bool {
	return false
}

func (addr *IPv6Address) IsIPv6() bool {
	return true
}

func (addr *IPv6Address) IsDomain() bool {
	return false
}

func (this *IPv6Address) String() string {
	return "[" + this.IP().String() + "]"
}

type DomainAddressImpl string

func (addr *DomainAddressImpl) IP() net.IP {
	panic("Calling IP() on a DomainAddress.")
}

func (addr *DomainAddressImpl) Domain() string {
	return string(*addr)
}

func (addr *DomainAddressImpl) IsIPv4() bool {
	return false
}

func (addr *DomainAddressImpl) IsIPv6() bool {
	return false
}

func (addr *DomainAddressImpl) IsDomain() bool {
	return true
}

func (this *DomainAddressImpl) String() string {
	return this.Domain()
}
<|endoftext|>


<commit_before>package gateway

import (
	"errors"
	"log"
	"net"
	"os"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/sync"
)

const (
	// maxStrikes is the number of "strikes" that can be incurred by a peer
	// before it will be removed.
	// TODO: need a way to whitelist peers (e.g. hosts)
	maxStrikes = 5
)

var (
	errNoPeers     = errors.New("no peers")
	errUnreachable = errors.New("peer did not respond to ping")
)

// Gateway implements the modules.Gateway interface.
type Gateway struct {
	listener net.Listener
	myAddr   modules.NetAddress

	// handlers are the RPCs that the Gateway can handle.
	handlers map[rpcID]modules.RPCFunc
	// initRPCs are the RPCs that the Gateway calls upon connecting to a peer.
	initRPCs map[string]modules.RPCFunc

	// peers are the nodes we are currently connected to.
	peers map[modules.NetAddress]*peer

	// nodes is a list of all known nodes (i.e. potential peers) on the
	// network.
	// TODO: map to a timestamp?
	nodes map[modules.NetAddress]struct{}

	persistDir string
	log        *log.Logger
	mu         *sync.RWMutex
}

// Address returns the NetAddress of the Gateway.
func (g *Gateway) Address() modules.NetAddress {
	id := g.mu.RLock()
	defer g.mu.RUnlock(id)
	return g.myAddr
}

// Close stops the Gateway's listener process.
func (g *Gateway) Close() error {
	return g.listener.Close()
}

// New returns an initialized Gateway.
func New(addr string, persistDir string) (g *Gateway, err error) {
	// Create the directory if it doesn't exist.
	err = os.MkdirAll(persistDir, 0700)
	if err != nil {
		return
	}

	// Create the logger.
	logger, err := makeLogger(persistDir)
	if err != nil {
		return
	}

	g = &Gateway{
		handlers:   make(map[rpcID]modules.RPCFunc),
		initRPCs:   make(map[string]modules.RPCFunc),
		peers:      make(map[modules.NetAddress]*peer),
		nodes:      make(map[modules.NetAddress]struct{}),
		persistDir: persistDir,
		mu:         sync.New(modules.SafeMutexDelay, 2),
		log:        logger,
	}

	// Register RPCs.
	g.RegisterRPC("ShareNodes", g.shareNodes)
	g.RegisterRPC("RelayNode", g.relayNode)
	g.RegisterConnectCall("ShareNodes", g.requestNodes)
	g.RegisterConnectCall("RelayNode", g.sendAddress)

	g.log.Println("INFO: gateway created, started logging")

	// Create listener and set address.
	g.listener, err = net.Listen("tcp", addr)
	if err != nil {
		return
	}
	_, port, _ := net.SplitHostPort(g.listener.Addr().String())
	g.myAddr = modules.NetAddress(net.JoinHostPort(modules.ExternalIP, port))

	g.log.Println("INFO: our address is", g.myAddr)

	// Spawn the primary listener.
	go g.listen()

	// Load the old peer list. If it doesn't exist, no problem, but if it does,
	// we want to know about any errors preventing us from loading it.
	if loadErr := g.load(); loadErr != nil && !os.IsNotExist(loadErr) {
		return nil, loadErr
	}

	// Spawn the connector loop. This will continually attempt to add nodes as
	// peers to ensure we stay well-connected.
	go g.makeOutboundConnections()

	return
}

// enforce that Gateway satisfies the modules.Gateway interface
var _ modules.Gateway = (*Gateway)(nil)
<commit_msg>save node list on close<commit_after>package gateway

import (
	"errors"
	"log"
	"net"
	"os"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/sync"
)

const (
	// maxStrikes is the number of "strikes" that can be incurred by a peer
	// before it will be removed.
	// TODO: need a way to whitelist peers (e.g. hosts)
	maxStrikes = 5
)

var (
	errNoPeers     = errors.New("no peers")
	errUnreachable = errors.New("peer did not respond to ping")
)

// Gateway implements the modules.Gateway interface.
type Gateway struct {
	listener net.Listener
	myAddr   modules.NetAddress

	// handlers are the RPCs that the Gateway can handle.
	handlers map[rpcID]modules.RPCFunc
	// initRPCs are the RPCs that the Gateway calls upon connecting to a peer.
	initRPCs map[string]modules.RPCFunc

	// peers are the nodes we are currently connected to.
	peers map[modules.NetAddress]*peer

	// nodes is a list of all known nodes (i.e. potential peers) on the
	// network.
	// TODO: map to a timestamp?
	nodes map[modules.NetAddress]struct{}

	persistDir string
	log        *log.Logger
	mu         *sync.RWMutex
}

// Address returns the NetAddress of the Gateway.
func (g *Gateway) Address() modules.NetAddress {
	id := g.mu.RLock()
	defer g.mu.RUnlock(id)
	return g.myAddr
}

// Close saves the state of the Gateway and stops the listener process.
func (g *Gateway) Close() error {
	id := g.mu.RLock()
	defer g.mu.RUnlock(id)
	err := g.save()
	if err != nil {
		return err
	}
	return g.listener.Close()
}

// New returns an initialized Gateway.
func New(addr string, persistDir string) (g *Gateway, err error) {
	// Create the directory if it doesn't exist.
	err = os.MkdirAll(persistDir, 0700)
	if err != nil {
		return
	}

	// Create the logger.
	logger, err := makeLogger(persistDir)
	if err != nil {
		return
	}

	g = &Gateway{
		handlers:   make(map[rpcID]modules.RPCFunc),
		initRPCs:   make(map[string]modules.RPCFunc),
		peers:      make(map[modules.NetAddress]*peer),
		nodes:      make(map[modules.NetAddress]struct{}),
		persistDir: persistDir,
		mu:         sync.New(modules.SafeMutexDelay, 2),
		log:        logger,
	}

	// Register RPCs.
	g.RegisterRPC("ShareNodes", g.shareNodes)
	g.RegisterRPC("RelayNode", g.relayNode)
	g.RegisterConnectCall("ShareNodes", g.requestNodes)
	g.RegisterConnectCall("RelayNode", g.sendAddress)

	g.log.Println("INFO: gateway created, started logging")

	// Create listener and set address.
	g.listener, err = net.Listen("tcp", addr)
	if err != nil {
		return
	}
	_, port, _ := net.SplitHostPort(g.listener.Addr().String())
	g.myAddr = modules.NetAddress(net.JoinHostPort(modules.ExternalIP, port))

	g.log.Println("INFO: our address is", g.myAddr)

	// Spawn the primary listener.
	go g.listen()

	// Load the old peer list. If it doesn't exist, no problem, but if it does,
	// we want to know about any errors preventing us from loading it.
	if loadErr := g.load(); loadErr != nil && !os.IsNotExist(loadErr) {
		return nil, loadErr
	}

	// Spawn the connector loop. This will continually attempt to add nodes as
	// peers to ensure we stay well-connected.
	go g.makeOutboundConnections()

	return
}

// enforce that Gateway satisfies the modules.Gateway interface
var _ modules.Gateway = (*Gateway)(nil)
<|endoftext|>


<commit_before><commit_msg>Role is a translation parameter in "assigning role" message to match behavior of original command, including coloration of role.<commit_after><|endoftext|>


<commit_before>package notificationsetting

import (
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/response"

	"github.com/koding/bongo"
)

// Create creates the notification settings with the channelId and accountId
func Create(u *url.URL, h http.Header, req *models.NotificationSetting, ctx *models.Context) (int, http.Header, interface{}, error) {
	if !ctx.IsLoggedIn() {
		return response.NewInvalidRequest(models.ErrNotLoggedIn)
	}

	channelId, err := fetchChannelIdwithParticipantCheck(u, ctx)
	if err != nil {
		return response.NewBadRequest(err)
	}

	req.AccountId = ctx.Client.Account.Id
	req.ChannelId = channelId

	if err := req.Create(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(req)
}

// Get gets the notification settings with id
// If any notification setting is not found in DB,
// returns 'Not Found' error , and it means that we'r gonna show default settings
func Get(u *url.URL, header http.Header, _ interface{}, ctx *models.Context) (int, http.Header, interface{}, error) {
	if !ctx.IsLoggedIn() {
		return response.NewInvalidRequest(models.ErrNotLoggedIn)
	}

	id, err := fetchChannelIdwithParticipantCheck(u, ctx)
	if err != nil {
		return response.NewBadRequest(err)
	}

	n := models.NewNotificationSetting()
	err = n.One(&bongo.Query{
		Selector: map[string]interface{}{
			"channel_id": id,
			"account_id": ctx.Client.Account.Id,
		}},
	)
	if err == bongo.RecordNotFound {
		return response.NewNotFound()
	}

	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(n)
}

// Update udpates the notification setting
func Update(u *url.URL, h http.Header, req *models.NotificationSetting, ctx *models.Context) (int, http.Header, interface{}, error) {
	id, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if !ctx.IsLoggedIn() {
		return response.NewInvalidRequest(models.ErrNotLoggedIn)
	}

	desktopSetting := req.DesktopSetting
	mobileSetting := req.MobileSetting
	isMuted := req.IsMuted
	isSuppressed := req.IsSuppressed

	if err := req.ById(id); err != nil {
		if err == bongo.RecordNotFound {
			return response.NewNotFound()
		}
		return response.NewBadRequest(err)
	}

	if req.Id == 0 {
		return response.NewBadRequest(err)
	}

	// check if notification setting's account is the same with requester account
	if req.AccountId != ctx.Client.Account.Id {
		return response.NewInvalidRequest(models.ErrAccountNotFound)
	}

	req.DesktopSetting = desktopSetting
	req.MobileSetting = mobileSetting
	req.IsMuted = isMuted
	req.IsSuppressed = isSuppressed

	if err := req.Update(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(req)
}

// Delete deletes the notification setting of the user
func Delete(u *url.URL, h http.Header, _ interface{}, ctx *models.Context) (int, http.Header, interface{}, error) {
	id, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	ns := models.NewNotificationSetting()
	ns.Id = id

	if err := ns.ById(id); err != nil {
		if err == bongo.RecordNotFound {
			return response.NewNotFound()
		}
		return response.NewBadRequest(err)
	}

	if ns.AccountId != ctx.Client.Account.Id {
		return response.NewInvalidRequest(models.ErrAccountNotFound)
	}

	if err := ns.Delete(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewDeleted()
}

func fetchChannelIdwithParticipantCheck(u *url.URL, context *models.Context) (int64, error) {
	channelId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return 0, err
	}

	c, err := models.Cache.Channel.ById(channelId)
	if err != nil {
		return 0, err
	}

	isParticipant, err := c.IsParticipant(context.Client.Account.Id)
	if err != nil {
		return 0, err
	}

	if !isParticipant {
		return 0, models.ErrAccountIsNotParticipant
	}

	return c.Id, nil
}
<commit_msg>go: notificationsetting is removed from parameters<commit_after>package notificationsetting

import (
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/response"

	"github.com/koding/bongo"
)

// Create creates the notification settings with the channelId and accountId
func Create(u *url.URL, h http.Header, req *models.NotificationSetting, ctx *models.Context) (int, http.Header, interface{}, error) {
	if !ctx.IsLoggedIn() {
		return response.NewInvalidRequest(models.ErrNotLoggedIn)
	}

	channelId, err := fetchChannelIdwithParticipantCheck(u, ctx)
	if err != nil {
		return response.NewBadRequest(err)
	}

	req.AccountId = ctx.Client.Account.Id
	req.ChannelId = channelId

	if err := req.Create(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(req)
}

// Get gets the notification settings with id
// If any notification setting is not found in DB,
// returns 'Not Found' error , and it means that we'r gonna show default settings
func Get(u *url.URL, header http.Header, _ interface{}, ctx *models.Context) (int, http.Header, interface{}, error) {
	if !ctx.IsLoggedIn() {
		return response.NewInvalidRequest(models.ErrNotLoggedIn)
	}

	id, err := fetchChannelIdwithParticipantCheck(u, ctx)
	if err != nil {
		return response.NewBadRequest(err)
	}

	n := models.NewNotificationSetting()
	err = n.One(&bongo.Query{
		Selector: map[string]interface{}{
			"channel_id": id,
			"account_id": ctx.Client.Account.Id,
		}},
	)
	if err == bongo.RecordNotFound {
		return response.NewNotFound()
	}

	if err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(n)
}

// Update udpates the notification setting
func Update(u *url.URL, h http.Header, a map[string]interface{}, ctx *models.Context) (int, http.Header, interface{}, error) {
	id, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if !ctx.IsLoggedIn() {
		return response.NewInvalidRequest(models.ErrNotLoggedIn)
	}

	req := models.NewNotificationSetting()

	if err := req.ById(id); err != nil {
		if err == bongo.RecordNotFound {
			return response.NewNotFound()
		}
		return response.NewBadRequest(err)
	}

	if req.Id == 0 {
		return response.NewBadRequest(err)
	}

	// check if notification setting's account is the same with requester account
	if req.AccountId != ctx.Client.Account.Id {
		return response.NewInvalidRequest(models.ErrAccountNotFound)
	}

	// Here we update notification setting with incoming request datas
	// if field have null or any value, then we update the field
	// otherwise we dont change any value of notification setting struct
	req = parseToNotificationSetting(a, req)

	if err := req.Update(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewOK(req)
}

// Delete deletes the notification setting of the user
func Delete(u *url.URL, h http.Header, _ interface{}, ctx *models.Context) (int, http.Header, interface{}, error) {
	id, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	ns := models.NewNotificationSetting()
	ns.Id = id

	if err := ns.ById(id); err != nil {
		if err == bongo.RecordNotFound {
			return response.NewNotFound()
		}
		return response.NewBadRequest(err)
	}

	if ns.AccountId != ctx.Client.Account.Id {
		return response.NewInvalidRequest(models.ErrAccountNotFound)
	}

	if err := ns.Delete(); err != nil {
		return response.NewBadRequest(err)
	}

	return response.NewDeleted()
}

func fetchChannelIdwithParticipantCheck(u *url.URL, context *models.Context) (int64, error) {
	channelId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return 0, err
	}

	c, err := models.Cache.Channel.ById(channelId)
	if err != nil {
		return 0, err
	}

	isParticipant, err := c.IsParticipant(context.Client.Account.Id)
	if err != nil {
		return 0, err
	}

	if !isParticipant {
		return 0, models.ErrAccountIsNotParticipant
	}

	return c.Id, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Qubit Digital Ltd.
// 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 logspray is a collection of tools for streaming and indexing
// large volumes of dynamic logs.

package kinesis

import (
	"bytes"
	"compress/gzip"
	"context"
	"encoding/json"

	"github.com/QubitProducts/logspray/proto/logspray"
	"github.com/QubitProducts/logspray/sources"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/golang/glog"
	"github.com/pkg/errors"
)

// MessageReader is a log source that reads from kinesis shard.
type MessageReader struct {
	shardIterator   *string
	kinesis         *kinesis.Kinesis
	stream          string
	messagesChannel chan Message
}

type Message struct {
	logsprayMsg *logspray.Message
	error       error
}

type KinesisMessage struct {
	LogEvents []interface{} `json:"logEvents"`
}

// ReadTarget creates a new log source from a kinesis shard
func (w *Watcher) ReadTarget(ctx context.Context, shardId string, fromStart bool) (sources.MessageReader, error) {
	shardIterator, err := w.shardIterator(ctx, shardId, fromStart)
	if err != nil {
		return nil, err
	}
	messagesChannel := make(chan Message, w.messagesChannelSize)

	msgReader := &MessageReader{
		shardIterator:   shardIterator,
		kinesis:         w.kinesis,
		stream:          w.stream,
		messagesChannel: messagesChannel,
	}

	go msgReader.startReadingFromKinesis(ctx)

	return msgReader, err
}

// MessageRead implements the LogSourcer interface
func (mr *MessageReader) MessageRead(ctx context.Context) (*logspray.Message, error) {
	message := <-mr.messagesChannel
	return message.logsprayMsg, message.error
}

func (w *Watcher) shardIterator(ctx context.Context, shardId string, fromStart bool) (*string, error) {
	shardIteratorType := aws.String("LATEST")
	if fromStart {
		shardIteratorType = aws.String("TRIM_HORIZON")
	}

	resp, err := w.kinesis.GetShardIteratorWithContext(ctx, &kinesis.GetShardIteratorInput{
		ShardId:           aws.String(shardId),
		ShardIteratorType: shardIteratorType,
		StreamName:        aws.String(w.stream),
	})
	if err != nil {
		return nil, errors.Wrap(err, "could not get shard iterator")
	}

	return resp.ShardIterator, ctx.Err()
}

func (mr *MessageReader) startReadingFromKinesis(ctx context.Context) {
	defer close(mr.messagesChannel)
	for {
		resp, kinesisErr := mr.kinesis.GetRecordsWithContext(ctx, &kinesis.GetRecordsInput{
			ShardIterator: mr.shardIterator,
			Limit:         aws.Int64(64),
		})

		if kinesisErr != nil {
			mr.messagesChannel <- Message{nil, kinesisErr}
			continue
		}

		mr.shardIterator = resp.NextShardIterator

		for _, r := range resp.Records {
			// decompressing data from kinesis
			reader := bytes.NewReader(r.Data)
			gzipReader, gzipErr := gzip.NewReader(reader)
			if gzipErr != nil {
				glog.Error(gzipErr)
				continue
			}

			kinesisMsg := KinesisMessage{}
			buf := new(bytes.Buffer)
			buf.ReadFrom(gzipReader)
			marshlingErr := json.Unmarshal(buf.Bytes(), &kinesisMsg)
			gzipReader.Close()
			if marshlingErr != nil {
				glog.Error(marshlingErr)
				continue
			}

			for _, log := range kinesisMsg.LogEvents {
				logsprayMsg, parseErr := parseLog(log)

				if parseErr != nil {
					glog.Error(parseErr)
					continue
				}

				msg := Message{logsprayMsg, nil}

				select {
				case <-ctx.Done():
					return
				case mr.messagesChannel <- msg:
				}
			}
		}
	}
}

func parseLog(log interface{}) (*logspray.Message, error) {
	logEvents, ok := log.(map[string]interface{})
	if !ok {
		return nil, errors.New("Failed to parse kinesis message")
	}

	message, ok := logEvents["message"].(string)
	if !ok {
		return nil, errors.New("Failed to parse message field in kinesis message")
	}

	timestamp, ok := logEvents["timestamp"].(string)
	if !ok {
		return nil, errors.New("Failed to parse timestamp field in kinesis message")
	}

	logsprayMsg := &logspray.Message{}
	logsprayMsg.Text = message
	logsprayMsg.Labels = map[string]string{
		"timestamp": timestamp,
	}

	return logsprayMsg, nil
}
<commit_msg>sources/kinesis: fix timestamp<commit_after>// Copyright 2016 Qubit Digital Ltd.
// 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 logspray is a collection of tools for streaming and indexing
// large volumes of dynamic logs.

package kinesis

import (
	"bytes"
	"compress/gzip"
	"context"
	"encoding/json"

	"github.com/QubitProducts/logspray/proto/logspray"
	"github.com/QubitProducts/logspray/sources"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/golang/glog"
	"github.com/golang/protobuf/ptypes/timestamp"
	"github.com/pkg/errors"
)

// MessageReader is a log source that reads from kinesis shard.
type MessageReader struct {
	shardIterator   *string
	kinesis         *kinesis.Kinesis
	stream          string
	messagesChannel chan Message
}

type Message struct {
	logsprayMsg *logspray.Message
	error       error
}

type KinesisMessage struct {
	LogEvents []interface{} `json:"logEvents"`
}

// ReadTarget creates a new log source from a kinesis shard
func (w *Watcher) ReadTarget(ctx context.Context, shardId string, fromStart bool) (sources.MessageReader, error) {
	shardIterator, err := w.shardIterator(ctx, shardId, fromStart)
	if err != nil {
		return nil, err
	}
	messagesChannel := make(chan Message, w.messagesChannelSize)

	msgReader := &MessageReader{
		shardIterator:   shardIterator,
		kinesis:         w.kinesis,
		stream:          w.stream,
		messagesChannel: messagesChannel,
	}

	go msgReader.startReadingFromKinesis(ctx)

	return msgReader, err
}

// MessageRead implements the LogSourcer interface
func (mr *MessageReader) MessageRead(ctx context.Context) (*logspray.Message, error) {
	message := <-mr.messagesChannel
	return message.logsprayMsg, message.error
}

func (w *Watcher) shardIterator(ctx context.Context, shardId string, fromStart bool) (*string, error) {
	shardIteratorType := aws.String("LATEST")
	if fromStart {
		shardIteratorType = aws.String("TRIM_HORIZON")
	}

	resp, err := w.kinesis.GetShardIteratorWithContext(ctx, &kinesis.GetShardIteratorInput{
		ShardId:           aws.String(shardId),
		ShardIteratorType: shardIteratorType,
		StreamName:        aws.String(w.stream),
	})
	if err != nil {
		return nil, errors.Wrap(err, "could not get shard iterator")
	}

	return resp.ShardIterator, ctx.Err()
}

func (mr *MessageReader) startReadingFromKinesis(ctx context.Context) {
	defer close(mr.messagesChannel)
	for {
		resp, kinesisErr := mr.kinesis.GetRecordsWithContext(ctx, &kinesis.GetRecordsInput{
			ShardIterator: mr.shardIterator,
			Limit:         aws.Int64(64),
		})

		if kinesisErr != nil {
			mr.messagesChannel <- Message{nil, kinesisErr}
			continue
		}

		mr.shardIterator = resp.NextShardIterator

		for _, r := range resp.Records {
			// decompressing data from kinesis
			reader := bytes.NewReader(r.Data)
			gzipReader, gzipErr := gzip.NewReader(reader)
			if gzipErr != nil {
				glog.Error(gzipErr)
				continue
			}

			kinesisMsg := KinesisMessage{}
			buf := new(bytes.Buffer)
			buf.ReadFrom(gzipReader)
			marshlingErr := json.Unmarshal(buf.Bytes(), &kinesisMsg)
			gzipReader.Close()
			if marshlingErr != nil {
				glog.Error(marshlingErr)
				continue
			}

			for _, log := range kinesisMsg.LogEvents {
				logsprayMsg, parseErr := parseLog(log)

				if parseErr != nil {
					glog.Error(parseErr)
					continue
				}

				msg := Message{logsprayMsg, nil}

				select {
				case <-ctx.Done():
					return
				case mr.messagesChannel <- msg:
				}
			}
		}
	}
}

func parseLog(log interface{}) (*logspray.Message, error) {
	logEvents, ok := log.(map[string]interface{})
	if !ok {
		return nil, errors.New("Failed to parse kinesis message")
	}

	message, ok := logEvents["message"].(string)
	if !ok {
		return nil, errors.New("Failed to parse message field in kinesis message")
	}

	milliSeconds := int64(logEvents["timestamp"].(float64))

	logsprayMsg := &logspray.Message{}
	logsprayMsg.Text = message

	logsprayMsg.Time = &timestamp.Timestamp{
		Nanos:   int32((milliSeconds % 1000) * 1000000),
		Seconds: milliSeconds / 1000,
	}

	return logsprayMsg, nil
}
<|endoftext|>