<commit_before>package watcher

import (
	"time"

	log "github.com/Sirupsen/logrus"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/batch"
	"k8s.io/kubernetes/pkg/apis/extensions"
	"k8s.io/kubernetes/pkg/client/restclient"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/watch"

	"github.com/InVisionApp/kit-overwatch/config"
	"github.com/InVisionApp/kit-overwatch/notifiers"
	"github.com/InVisionApp/kit-overwatch/notifiers/deps"
)

type Watcher struct {
	Client client.Client
	ClientConfig restclient.Config
	Config config.Config
}

type WatcherEvent struct {
	Event   api.Event
	WatchEvent watch.Event
}

type SentEvent struct {
	LastSent time.Time
	Count int
}

func New(cfg *config.Config) *Watcher {
	var c *client.Client
	var cErr error
	var clientConfig *restclient.Config

	if cfg.InCluster {
		var confErr error
		clientConfig, confErr = restclient.InClusterConfig()
		if confErr != nil {
			log.Fatalf("Unable to instantiate in cluster config: %v", cErr.Error())
		}
		c, cErr = client.New(clientConfig)
		if cErr != nil {
			log.Fatalf("Unable to instantiate kube client in cluster: %v", cErr.Error())
		}
	} else {
		clientConfig = &restclient.Config{
			Host: cfg.ClusterHost,
		}
		c, cErr = client.New(clientConfig)
		if cErr != nil {
			log.Fatalf("Unable to instantiate kube client: %v", cErr.Error())
		}
	}

	return &Watcher{
		Client: *c,
		ClientConfig: *clientConfig,
		Config: *cfg,
	}
}

func (w *Watcher) Watch() {
	startTime := time.Now()
	pastEvents := make(map[types.UID]WatcherEvent)
	sentEvents := make(map[types.UID]SentEvent)

	opts := api.ListOptions{
		ResourceVersion: "0",
	}
	cw, err := w.Client.Events(w.Config.Namespace).Watch(opts)
	if err != nil {
		log.Fatalf("Unable to instantiate events watcher: %v", err.Error())
	}

	// Get the events channel
	ec := cw.ResultChan()
	log.Info("Watching for events...")

	// Process event channel
	for we := range ec {
		log.Infof("%s event detected", we.Type)

		// When an event occurs, get list of events
		list, err := w.Client.Events(w.Config.Namespace).List(api.ListOptions{
			ResourceVersion: "0",
		})
		if err != nil {
			log.Fatalf("Unable to get events: %v", err.Error())
		}
		for _, e := range list.Items {
			// Only log if we haven't logged before
			past, ok := pastEvents[e.ObjectMeta.UID]
			if ok {
				// Only skip if the count hasn't increased
				if e.Count == past.Event.Count {
					log.Debugf("Skip: already notified for %s / %s / %s", e.ObjectMeta.UID, e.Reason, e.Message)
					continue
				}
			}

			// Remember this event so we don't send duplicate notifications
			pastEvents[e.ObjectMeta.UID] = WatcherEvent{
				Event: e,
				WatchEvent:   we,
			}

			// Only log events that have happened since the service started
			diff := startTime.Sub(e.LastTimestamp.Time)
			if int(diff.Minutes()) > 1 {
				log.Debugf("Skip: %s / %s / %s - %s happened more than a minute before service started", e.ObjectMeta.UID, e.Reason, e.Message, e.LastTimestamp)
				continue
			}

			// Throttle duplicate events so we don't notify too many times
			sent, ok := sentEvents[e.ObjectMeta.UID]
			var count int
			if ok {
				canSendAfter := sent.LastSent.Add(time.Minute * time.Duration(sent.Count))
				if time.Now().After(canSendAfter) {
					count = sent.Count + 1
				} else {
					log.Debugf("Skip: throttle back notifications %v minutes for %s / %s / %s", sent.Count, e.ObjectMeta.UID, e.Reason, e.Message)
					continue
				}
			}
			sentEvents[e.ObjectMeta.UID] = SentEvent{
				LastSent: time.Now(),
				Count: count,
			}

			// Generate and send the notification
			go w.notify(e)
		}
	}

	log.Fatalf("Event watching has ended")
}

func (w *Watcher) getLevel(e api.Event) string {
	reasonLevels := map[string]string{
		"SuccessfulCreate": "INFO",
		"SuccessfulDelete": "INFO",
		"ContainerCreating": "INFO",
		"Pulled": "INFO",
		"Pulling": "INFO",
		"Created": "INFO",
		"Starting": "INFO",
		"Started": "INFO",
		"Killing": "INFO",
		"NodeReady": "INFO",
		"ScalingReplicaSet": "INFO",
		"Scheduled": "INFO",
		"NodeNotReady": "WARN",
		"MAPPING": "WARN",
		"NodeOutOfDisk": "ERROR",
		"ImagePullBackOff": "ERROR",
		"FailedSync": "ERROR",
		"MissingClusterDNS": "ERROR",
		"RegisteredNode": "INFO",
		"TerminatingEvictedPod": "WARN",
		"RemovingNode": "WARN",
		"TerminatedAllPods": "WARN",
		"NodeHasSufficientDisk": "INFO",
		"NodeHasSufficientMemory": "INFO",
		"NodeNotSchedulable": "ERROR",
		"DeletingAllPods": "WARN",
		"DeletingNode": "WARN",
		"UpdatedLoadBalancer": "INFO",
	}

	var ok bool
	if _, ok = reasonLevels[e.Reason]; !ok {
		return "ERROR"
	}

	return reasonLevels[e.Reason]
}

func (w *Watcher) notify(e api.Event) {
	// Determine notification level
	level := w.getLevel(e)

	// Get label to use as mention in notification
	var mention string
	var rErr error
	var rOk bool
	ec, err := client.NewExtensions(&w.ClientConfig)
	if err != nil {
		log.Fatalf("Unable to instantiate new ExtensionsClient: %v", err.Error())
	}
	switch e.InvolvedObject.Kind {
	case "Pod":
		var resource *api.Pod
		resource, rErr = w.Client.Pods(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "Service":
		var resource *api.Service
		resource, rErr = w.Client.Services(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "Node":
		var resource *api.Node
		resource, rErr = w.Client.Nodes().Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "Deployment":
		var resource *extensions.Deployment
		resource, rErr = ec.Deployments(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "ReplicaSet":
		var resource *extensions.ReplicaSet
		resource, rErr = ec.ReplicaSets(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "Job":
		var resource *batch.Job
		resource, rErr = ec.Jobs(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "DaemonSet":
		var resource *extensions.DaemonSet
		resource, rErr = ec.DaemonSets(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	default:
		log.Debugf("Cannot retrieve label for unsported Kind: %s", e.InvolvedObject.Kind)
	}
	if rErr != nil {
		log.Warnf("Unable to get %s: %v", e.InvolvedObject.Kind, rErr.Error())
	}
	if !rOk {
		log.Warnf("Mention label not found for %s: %s, using default: %s", e.InvolvedObject.Kind, e.InvolvedObject.Name, w.Config.MentionDefault)
		mention = w.Config.MentionDefault
	}

	// Send notifications
	n := notifiers.New(&w.Config)
	notification := deps.Notification{
		Cluster: w.Config.ClusterName,
		Event:   e,
		Level:   level,
		Mention: mention,
	}
	n.SendAll(&notification)
}
<commit_msg>feat: added more reasons and what level they are<commit_after>package watcher

import (
	"time"

	log "github.com/Sirupsen/logrus"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/batch"
	"k8s.io/kubernetes/pkg/apis/extensions"
	"k8s.io/kubernetes/pkg/client/restclient"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/watch"

	"github.com/InVisionApp/kit-overwatch/config"
	"github.com/InVisionApp/kit-overwatch/notifiers"
	"github.com/InVisionApp/kit-overwatch/notifiers/deps"
)

type Watcher struct {
	Client client.Client
	ClientConfig restclient.Config
	Config config.Config
}

type WatcherEvent struct {
	Event   api.Event
	WatchEvent watch.Event
}

type SentEvent struct {
	LastSent time.Time
	Count int
}

func New(cfg *config.Config) *Watcher {
	var c *client.Client
	var cErr error
	var clientConfig *restclient.Config

	if cfg.InCluster {
		var confErr error
		clientConfig, confErr = restclient.InClusterConfig()
		if confErr != nil {
			log.Fatalf("Unable to instantiate in cluster config: %v", cErr.Error())
		}
		c, cErr = client.New(clientConfig)
		if cErr != nil {
			log.Fatalf("Unable to instantiate kube client in cluster: %v", cErr.Error())
		}
	} else {
		clientConfig = &restclient.Config{
			Host: cfg.ClusterHost,
		}
		c, cErr = client.New(clientConfig)
		if cErr != nil {
			log.Fatalf("Unable to instantiate kube client: %v", cErr.Error())
		}
	}

	return &Watcher{
		Client: *c,
		ClientConfig: *clientConfig,
		Config: *cfg,
	}
}

func (w *Watcher) Watch() {
	startTime := time.Now()
	pastEvents := make(map[types.UID]WatcherEvent)
	sentEvents := make(map[types.UID]SentEvent)

	opts := api.ListOptions{
		ResourceVersion: "0",
	}
	cw, err := w.Client.Events(w.Config.Namespace).Watch(opts)
	if err != nil {
		log.Fatalf("Unable to instantiate events watcher: %v", err.Error())
	}

	// Get the events channel
	ec := cw.ResultChan()
	log.Info("Watching for events...")

	// Process event channel
	for we := range ec {
		log.Infof("%s event detected", we.Type)

		// When an event occurs, get list of events
		list, err := w.Client.Events(w.Config.Namespace).List(api.ListOptions{
			ResourceVersion: "0",
		})
		if err != nil {
			log.Fatalf("Unable to get events: %v", err.Error())
		}
		for _, e := range list.Items {
			// Only log if we haven't logged before
			past, ok := pastEvents[e.ObjectMeta.UID]
			if ok {
				// Only skip if the count hasn't increased
				if e.Count == past.Event.Count {
					log.Debugf("Skip: already notified for %s / %s / %s", e.ObjectMeta.UID, e.Reason, e.Message)
					continue
				}
			}

			// Remember this event so we don't send duplicate notifications
			pastEvents[e.ObjectMeta.UID] = WatcherEvent{
				Event: e,
				WatchEvent:   we,
			}

			// Only log events that have happened since the service started
			diff := startTime.Sub(e.LastTimestamp.Time)
			if int(diff.Minutes()) > 1 {
				log.Debugf("Skip: %s / %s / %s - %s happened more than a minute before service started", e.ObjectMeta.UID, e.Reason, e.Message, e.LastTimestamp)
				continue
			}

			// Throttle duplicate events so we don't notify too many times
			sent, ok := sentEvents[e.ObjectMeta.UID]
			var count int
			if ok {
				canSendAfter := sent.LastSent.Add(time.Minute * time.Duration(sent.Count))
				if time.Now().After(canSendAfter) {
					count = sent.Count + 1
				} else {
					log.Debugf("Skip: throttle back notifications %v minutes for %s / %s / %s", sent.Count, e.ObjectMeta.UID, e.Reason, e.Message)
					continue
				}
			}
			sentEvents[e.ObjectMeta.UID] = SentEvent{
				LastSent: time.Now(),
				Count: count,
			}

			// Generate and send the notification
			go w.notify(e)
		}
	}

	log.Fatalf("Event watching has ended")
}

func (w *Watcher) getLevel(e api.Event) string {
	reasonLevels := map[string]string{
		"SuccessfulCreate": "INFO",
		"SuccessfulDelete": "INFO",
		"ContainerCreating": "INFO",
		"Pulled": "INFO",
		"Pulling": "INFO",
		"Created": "INFO",
		"Starting": "INFO",
		"Started": "INFO",
		"Killing": "INFO",
		"NodeReady": "INFO",
		"ScalingReplicaSet": "INFO",
		"Scheduled": "INFO",
		"NodeNotReady": "WARN",
		"MAPPING": "WARN",
		"UPDATE": "INFO",
		"DELETE": "INFO",
		"NodeOutOfDisk": "ERROR",
		"BackOff": "ERROR",
		"ImagePullBackOff": "ERROR",
		"FailedSync": "ERROR",
		"FreeDiskSpaceFailed": "WARN",
		"MissingClusterDNS": "ERROR",
		"RegisteredNode": "INFO",
		"TerminatingEvictedPod": "WARN",
		"RemovingNode": "WARN",
		"TerminatedAllPods": "WARN",
		"CreatedLoadBalancer": "INFO",
		"CreatingLoadBalancer": "INFO",
		"NodeHasSufficientDisk": "INFO",
		"NodeHasSufficientMemory": "INFO",
		"NodeNotSchedulable": "ERROR",
		"DeletingAllPods": "WARN",
		"DeletingNode": "WARN",
		"UpdatedLoadBalancer": "INFO",
	}

	var ok bool
	if _, ok = reasonLevels[e.Reason]; !ok {
		return "ERROR"
	}

	return reasonLevels[e.Reason]
}

func (w *Watcher) notify(e api.Event) {
	// Determine notification level
	level := w.getLevel(e)

	// Get label to use as mention in notification
	var mention string
	var rErr error
	var rOk bool
	ec, err := client.NewExtensions(&w.ClientConfig)
	if err != nil {
		log.Fatalf("Unable to instantiate new ExtensionsClient: %v", err.Error())
	}
	switch e.InvolvedObject.Kind {
	case "Pod":
		var resource *api.Pod
		resource, rErr = w.Client.Pods(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "Service":
		var resource *api.Service
		resource, rErr = w.Client.Services(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "Node":
		var resource *api.Node
		resource, rErr = w.Client.Nodes().Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "Deployment":
		var resource *extensions.Deployment
		resource, rErr = ec.Deployments(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "ReplicaSet":
		var resource *extensions.ReplicaSet
		resource, rErr = ec.ReplicaSets(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "Job":
		var resource *batch.Job
		resource, rErr = ec.Jobs(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	case "DaemonSet":
		var resource *extensions.DaemonSet
		resource, rErr = ec.DaemonSets(w.Config.Namespace).Get(e.InvolvedObject.Name)
		mention, rOk = resource.ObjectMeta.Labels[w.Config.MentionLabel]
	default:
		log.Debugf("Cannot retrieve label for unsported Kind: %s", e.InvolvedObject.Kind)
	}
	if rErr != nil {
		log.Warnf("Unable to get %s: %v", e.InvolvedObject.Kind, rErr.Error())
	}
	if !rOk {
		log.Warnf("Mention label not found for %s: %s, using default: %s", e.InvolvedObject.Kind, e.InvolvedObject.Name, w.Config.MentionDefault)
		mention = w.Config.MentionDefault
	}

	// Send notifications
	n := notifiers.New(&w.Config)
	notification := deps.Notification{
		Cluster: w.Config.ClusterName,
		Event:   e,
		Level:   level,
		Mention: mention,
	}
	n.SendAll(&notification)
}
<|endoftext|>


<commit_before>package cwl

import (
	"fmt"
	"sort"
	"strings"

	"github.com/robertkrimen/otto"
)

// Input represents "CommandInputParameter".
// @see http://www.commonwl.org/v1.0/CommandLineTool.html#CommandInputParameter
type Input struct {
	ID             string          `json:"id"`
	Label          string          `json:"label"`
	Doc            string          `json:"doc"`
	Format         string          `json:"format"`
	Binding        *Binding        `json:"inputBinding"`
	Default        *InputDefault   `json:"default"`
	Types          []Type          `json:"type"`
	SecondaryFiles []SecondaryFile `json:"secondary_files"`
	// Input.Provided is what provided by parameters.(json|yaml)
	Provided *Provided `json:"-"`
	// Requirement ..
	RequiredType *Type
	Requirements Requirements
}

// New constructs "Input" struct from interface{}.
func (input Input) New(i interface{}) *Input {
	dest := &Input{}
	switch x := i.(type) {
	case map[string]interface{}:
		for key, v := range x {
			switch key {
			case "id":
				dest.ID = v.(string)
			case "type":
				dest.Types = Type{}.NewList(v)
			case "label":
				dest.Label = v.(string)
			case "doc":
				dest.Doc = v.(string)
			case "inputBinding":
				dest.Binding = Binding{}.New(v)
			case "default":
				dest.Default = InputDefault{}.New(v)
			case "format":
				dest.Format = v.(string)
			case "secondaryFiles":
				dest.SecondaryFiles = SecondaryFile{}.NewList(v)
			}
		}
		if dest.Default != nil {
			dest.Default.ID = dest.ID
		}
	case string:
		dest.Types = Type{}.NewList(x)
	case []interface{}:
		for _, v := range x {
			dest.Types = append(dest.Types, Type{}.New(v))
		}
	}
	return dest
}

// flatten
func (input *Input) flatten(typ Type, binding *Binding, prov interface{}) []string {
	flattened := []string{}
	switch typ.Type {
	case "int": // Array of Int
		tobejoined := []string{}
		for _, e := range input.Provided.Raw.([]interface{}) {
			tobejoined = append(tobejoined, fmt.Sprintf("%v", e))
		}
		flattened = append(flattened, strings.Join(tobejoined, input.Binding.Separator))
	case "File": // Array of Files
		switch arr := input.Provided.Raw.(type) {
		case []string:
			// TODO:
		case []interface{}:
			separated := []string{}
			for _, e := range arr {
				switch v := e.(type) {
				case map[interface{}]interface{}:
					if binding != nil && binding.Prefix != "" {
						separated = append(separated, binding.Prefix)
					}
					separated = append(separated, fmt.Sprintf("%v", v["location"]))
				default:
					// TODO:
				}
			}
			// In case it's Array of Files, unlike array of int,
			// it's NOT gonna be joined with .Binding.Separator.
			flattened = append(flattened, separated...)
		}
	case "string": // Array of string
		switch arr := prov.(type) {
		case []interface{}:
			separated := []string{}
			for _, e := range arr {
				switch v := e.(type) {
				case string:
					if binding != nil && binding.Prefix != "" {
						separated = append(separated, binding.Prefix)
					}
					separated = append(separated, fmt.Sprintf("%v", v))
				default:
					// TODO
				}
			}
			flattened = append(flattened, separated...)
		default:
			// TODO
		}
	case "array":
		switch arr := prov.(type) {
		case []interface{}:
			flattened = append(flattened, input.flatten(typ.Items[0], typ.Binding, arr[0])...)
		default:
			// TODO
		}
	default:
		if input.RequiredType != nil {
			flattened = append(flattened, input.flattenWithRequiredType()...)
		} else {
			// TODO
		}
	}
	return flattened
}

func (input *Input) flattenWithRequiredType() []string {
	flattened := []string{}
	key, needed := input.Types[0].NeedRequirement()
	if !needed {
		return flattened
	}
	if input.RequiredType.Name != key {
		return flattened
	}
	switch provided := input.Provided.Raw.(type) {
	case []interface{}:
		for _, e := range provided {
			switch v := e.(type) {
			case map[interface{}]interface{}:
				for _, field := range input.RequiredType.Fields {
					val, ok := v[field.Name]
					if !ok {
						continue
					}
					if field.Binding == nil {
						// Without thinking anything, just append it!!!
						flattened = append(flattened, fmt.Sprintf("%v", val))
					} else {
						if field.Binding.Prefix != "" {
							if field.Binding.Separate {
								flattened = append(flattened, field.Binding.Prefix, fmt.Sprintf("%v", val))
							} else {
								// TODO: Join if .Separator is given
								flattened = append(flattened, fmt.Sprintf("%s%v", field.Binding.Prefix, val))
							}
						} else {
							switch v2 := val.(type) {
							case []interface{}:
								for _, val2 := range v2 {
									switch v3 := val2.(type) {
									case []interface{}:
									case map[interface{}]interface{}:
										for _, types := range input.Requirements[0].SchemaDefRequirement.Types {
											val3array := []string{}
											var val3count int = 0
											sort.Sort(types.Fields)
											for _, fields := range types.Fields {
												for key3, val3 := range v3 {
													if fields.Name == key3 {
														for _, val3type := range fields.Types {
															if val3type.Type == "" {
															} else {
																switch val3type.Type {
																case "enum":
																	for _, symbol := range val3type.Symbols {
																		if symbol == val3 {
																			val3array = append(val3array, fmt.Sprintf("%v", val3))
																			val3count = val3count + 1
																		}
																	}
																case "int":
																	if fields.Binding.Prefix != "" {
																		val3array = append(val3array, fields.Binding.Prefix, fmt.Sprintf("%v", val3))
																		val3count = val3count + 1
																	} else {
																		val3array = append(val3array, fmt.Sprintf("%v", val3))
																		val3count = val3count + 1
																	}
																}
															}
														}
													}
												}
											}
											if len(v3) == val3count {
												flattened = append(flattened, val3array...)
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return flattened
}

// Flatten ...
func (input *Input) Flatten() []string {
	if input.Provided == nil {
		// In case "input.Default == nil" should be validated by usage layer.
		if input.Default != nil {
			return input.Default.Flatten(input.Binding)
		} else {
			return []string{}
		}
	}
	flattened := []string{}
	if repr := input.Types[0]; len(input.Types) == 1 {
		switch repr.Type {
		case "array":
			flattened = append(flattened, input.flatten(repr.Items[0], repr.Binding, input.Provided.Raw)...)
		case "int":
			flattened = append(flattened, fmt.Sprintf("%v", input.Provided.Int))
		case "File":
			flattened = append(flattened, input.Provided.Entry.Location)
		default:
			flattened = append(flattened, fmt.Sprintf("%v", input.Provided))
		}
	}
	if input.Binding != nil && input.Binding.Prefix != "" {
		flattened = append([]string{input.Binding.Prefix}, flattened...)
	}

	return flattened
}

// Inputs represents "inputs" field in CWL.
type Inputs []*Input

// New constructs new "Inputs" struct.
func (ins Inputs) New(i interface{}) Inputs {
	dest := Inputs{}
	switch x := i.(type) {
	case []interface{}:
		for _, v := range x {
			dest = append(dest, Input{}.New(v))
		}
	case map[string]interface{}:
		for key, v := range x {
			input := Input{}.New(v)
			input.ID = key
			dest = append(dest, input)
		}
	}
	return dest
}

// Len for sorting.
func (ins Inputs) Len() int {
	return len(ins)
}

// Less for sorting.
func (ins Inputs) Less(i, j int) bool {
	prev, next := ins[i].Binding, ins[j].Binding
	switch [2]bool{prev == nil, next == nil} {
	case [2]bool{true, true}:
		return true
	case [2]bool{false, true}:
		return prev.Position < 0
	case [2]bool{true, false}:
		return next.Position > 0
	default:
		return prev.Position <= next.Position
	}
}

// Swap for sorting.
func (ins Inputs) Swap(i, j int) {
	ins[i], ins[j] = ins[j], ins[i]
}

// ToJavaScriptVM ...
func (ins Inputs) ToJavaScriptVM() (*otto.Otto, error) {
	self := map[string]map[string]interface{}{}
	for _, i := range ins {
		if i.Provided != nil && i.Provided.Entry != nil {
			self[i.ID] = map[string]interface{}{
				"path": i.Provided.Entry.Location,
			}
			continue
		}
		if i.Default != nil && i.Default.Entry != nil {
			self[i.ID] = map[string]interface{}{
				"path": i.Default.Entry.Location,
			}
			continue
		}
	}

	// No contents to load
	if len(self) == 0 {
		return nil, nil
	}

	vm := otto.New()
	if err := vm.Set("inputs", self); err != nil {
		return nil, err
	}
	return vm, nil
}
<commit_msg>Support input type string<commit_after>package cwl

import (
	"fmt"
	"sort"
	"strings"

	"github.com/robertkrimen/otto"
)

// Input represents "CommandInputParameter".
// @see http://www.commonwl.org/v1.0/CommandLineTool.html#CommandInputParameter
type Input struct {
	ID             string          `json:"id"`
	Label          string          `json:"label"`
	Doc            string          `json:"doc"`
	Format         string          `json:"format"`
	Binding        *Binding        `json:"inputBinding"`
	Default        *InputDefault   `json:"default"`
	Types          []Type          `json:"type"`
	SecondaryFiles []SecondaryFile `json:"secondary_files"`
	// Input.Provided is what provided by parameters.(json|yaml)
	Provided *Provided `json:"-"`
	// Requirement ..
	RequiredType *Type
	Requirements Requirements
}

// New constructs "Input" struct from interface{}.
func (input Input) New(i interface{}) *Input {
	dest := &Input{}
	switch x := i.(type) {
	case map[string]interface{}:
		for key, v := range x {
			switch key {
			case "id":
				dest.ID = v.(string)
			case "type":
				dest.Types = Type{}.NewList(v)
			case "label":
				dest.Label = v.(string)
			case "doc":
				dest.Doc = v.(string)
			case "inputBinding":
				dest.Binding = Binding{}.New(v)
			case "default":
				dest.Default = InputDefault{}.New(v)
			case "format":
				dest.Format = v.(string)
			case "secondaryFiles":
				dest.SecondaryFiles = SecondaryFile{}.NewList(v)
			}
		}
		if dest.Default != nil {
			dest.Default.ID = dest.ID
		}
	case string:
		dest.Types = Type{}.NewList(x)
	case []interface{}:
		for _, v := range x {
			dest.Types = append(dest.Types, Type{}.New(v))
		}
	}
	return dest
}

// flatten
func (input *Input) flatten(typ Type, binding *Binding, prov interface{}) []string {
	flattened := []string{}
	switch typ.Type {
	case "int": // Array of Int
		tobejoined := []string{}
		for _, e := range input.Provided.Raw.([]interface{}) {
			tobejoined = append(tobejoined, fmt.Sprintf("%v", e))
		}
		flattened = append(flattened, strings.Join(tobejoined, input.Binding.Separator))
	case "File": // Array of Files
		switch arr := input.Provided.Raw.(type) {
		case []string:
			// TODO:
		case []interface{}:
			separated := []string{}
			for _, e := range arr {
				switch v := e.(type) {
				case map[interface{}]interface{}:
					if binding != nil && binding.Prefix != "" {
						separated = append(separated, binding.Prefix)
					}
					separated = append(separated, fmt.Sprintf("%v", v["location"]))
				default:
					// TODO:
				}
			}
			// In case it's Array of Files, unlike array of int,
			// it's NOT gonna be joined with .Binding.Separator.
			flattened = append(flattened, separated...)
		}
	case "string": // Array of string
		switch arr := prov.(type) {
		case []interface{}:
			separated := []string{}
			for _, e := range arr {
				switch v := e.(type) {
				case string:
					if binding != nil && binding.Prefix != "" {
						separated = append(separated, binding.Prefix)
					}
					separated = append(separated, fmt.Sprintf("%v", v))
				default:
					// TODO
				}
			}
			flattened = append(flattened, separated...)
		default:
			// TODO
		}
	case "array":
		switch arr := prov.(type) {
		case []interface{}:
			flattened = append(flattened, input.flatten(typ.Items[0], typ.Binding, arr[0])...)
		default:
			// TODO
		}
	default:
		if input.RequiredType != nil {
			flattened = append(flattened, input.flattenWithRequiredType()...)
		} else {
			// TODO
		}
	}
	return flattened
}

func (input *Input) flattenWithRequiredType() []string {
	flattened := []string{}
	key, needed := input.Types[0].NeedRequirement()
	if !needed {
		return flattened
	}
	if input.RequiredType.Name != key {
		return flattened
	}
	switch provided := input.Provided.Raw.(type) {
	case []interface{}:
		for _, e := range provided {
			switch v := e.(type) {
			case map[interface{}]interface{}:
				for _, field := range input.RequiredType.Fields {
					val, ok := v[field.Name]
					if !ok {
						continue
					}
					if field.Binding == nil {
						// Without thinking anything, just append it!!!
						flattened = append(flattened, fmt.Sprintf("%v", val))
					} else {
						if field.Binding.Prefix != "" {
							if field.Binding.Separate {
								flattened = append(flattened, field.Binding.Prefix, fmt.Sprintf("%v", val))
							} else {
								// TODO: Join if .Separator is given
								flattened = append(flattened, fmt.Sprintf("%s%v", field.Binding.Prefix, val))
							}
						} else {
							switch v2 := val.(type) {
							case []interface{}:
								for _, val2 := range v2 {
									switch v3 := val2.(type) {
									case []interface{}:
									case map[interface{}]interface{}:
										for _, types := range input.Requirements[0].SchemaDefRequirement.Types {
											val3array := []string{}
											var val3count int = 0
											sort.Sort(types.Fields)
											for _, fields := range types.Fields {
												for key3, val3 := range v3 {
													if fields.Name == key3 {
														for _, val3type := range fields.Types {
															if val3type.Type == "" {
															} else {
																switch val3type.Type {
																case "enum":
																	for _, symbol := range val3type.Symbols {
																		if symbol == val3 {
																			val3array = append(val3array, fmt.Sprintf("%v", val3))
																			val3count = val3count + 1
																		}
																	}
																case "int":
																	if fields.Binding.Prefix != "" {
																		val3array = append(val3array, fields.Binding.Prefix, fmt.Sprintf("%v", val3))
																		val3count = val3count + 1
																	} else {
																		val3array = append(val3array, fmt.Sprintf("%v", val3))
																		val3count = val3count + 1
																	}
																}
															}
														}
													}
												}
											}
											if len(v3) == val3count {
												flattened = append(flattened, val3array...)
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return flattened
}

// Flatten ...
func (input *Input) Flatten() []string {
	if input.Provided == nil {
		// In case "input.Default == nil" should be validated by usage layer.
		if input.Default != nil {
			return input.Default.Flatten(input.Binding)
		} else {
			return []string{}
		}
	}
	flattened := []string{}
	if repr := input.Types[0]; len(input.Types) == 1 {
		switch repr.Type {
		case "array":
			flattened = append(flattened, input.flatten(repr.Items[0], repr.Binding, input.Provided.Raw)...)
		case "int":
			flattened = append(flattened, fmt.Sprintf("%v", input.Provided.Int))
		case "File":
			flattened = append(flattened, input.Provided.Entry.Location)
		default:
			flattened = append(flattened, fmt.Sprintf("%v", input.Provided))
		}
	}
	if input.Binding != nil && input.Binding.Prefix != "" {
		flattened = append([]string{input.Binding.Prefix}, flattened...)
	}

	return flattened
}

// Inputs represents "inputs" field in CWL.
type Inputs []*Input

// New constructs new "Inputs" struct.
func (ins Inputs) New(i interface{}) Inputs {
	dest := Inputs{}
	switch x := i.(type) {
	case []interface{}:
		for _, v := range x {
			dest = append(dest, Input{}.New(v))
		}
	case map[string]interface{}:
		for key, v := range x {
			input := Input{}.New(v)
			input.ID = key
			dest = append(dest, input)
		}
	}
	return dest
}

// Len for sorting.
func (ins Inputs) Len() int {
	return len(ins)
}

// Less for sorting.
func (ins Inputs) Less(i, j int) bool {
	prev, next := ins[i].Binding, ins[j].Binding
	switch [2]bool{prev == nil, next == nil} {
	case [2]bool{true, true}:
		return true
	case [2]bool{false, true}:
		return prev.Position < 0
	case [2]bool{true, false}:
		return next.Position > 0
	default:
		return prev.Position <= next.Position
	}
}

// Swap for sorting.
func (ins Inputs) Swap(i, j int) {
	ins[i], ins[j] = ins[j], ins[i]
}

// ToJavaScriptVM ...
func (ins Inputs) ToJavaScriptVM() (*otto.Otto, error) {
	self := map[string]interface{}{}
	for _, i := range ins {
		if i.Provided != nil && i.Provided.Entry != nil {
			self[i.ID] = map[string]interface{}{
				"path": i.Provided.Entry.Location,
			}
			continue
		}
		if i.Default != nil && i.Default.Entry != nil {
			self[i.ID] = map[string]interface{}{
				"path": i.Default.Entry.Location,
			}
			continue
		}
		if i.Types[0].Type == "string" {
			if i.Provided != nil {
				self[i.ID] = i.Provided.Raw
				continue
			}
		}
	}

	// No contents to load
	if len(self) == 0 {
		return nil, nil
	}

	vm := otto.New()
	if err := vm.Set("inputs", self); err != nil {
		return nil, err
	}
	return vm, nil
}
<|endoftext|>


<commit_before>package chromedp

import (
	"context"
	"fmt"
	"time"

	"github.com/knq/chromedp/cdp"
	"github.com/knq/chromedp/cdp/dom"
	"github.com/knq/chromedp/cdp/input"
	"github.com/knq/chromedp/kb"
)

// MouseAction is a mouse action.
func MouseAction(typ input.MouseType, x, y int64, opts ...MouseOption) Action {
	me := input.DispatchMouseEvent(typ, x, y)

	// apply opts
	for _, o := range opts {
		me = o(me)
	}

	return me
}

// MouseClickXY sends a left mouse button click (ie, mousePressed and
// mouseReleased event) at the X, Y location.
func MouseClickXY(x, y int64, opts ...MouseOption) Action {
	return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
		me := &input.DispatchMouseEventParams{
			Type:       input.MousePressed,
			X:          x,
			Y:          y,
			Button:     input.ButtonLeft,
			ClickCount: 1,
		}

		// apply opts
		for _, o := range opts {
			me = o(me)
		}

		err := me.Do(ctxt, h)
		if err != nil {
			return err
		}

		me.Type = input.MouseReleased
		return me.Do(ctxt, h)
	})
}

// MouseClickNode dispatches a mouse left button click event at the center of a
// specified node.
//
// Note that the window will be scrolled if the node is not within the window's
// viewport.
func MouseClickNode(n *cdp.Node, opts ...MouseOption) Action {
	return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
		var err error

		var pos []int
		err = EvaluateAsDevTools(fmt.Sprintf(scrollIntoViewJS, n.FullXPath()), &pos).Do(ctxt, h)
		if err != nil {
			return err
		}

		box, err := dom.GetBoxModel(n.NodeID).Do(ctxt, h)
		if err != nil {
			return err
		}

		c := len(box.Content)
		if c%2 != 0 || c < 1 {
			return ErrInvalidDimensions
		}

		var x, y int64
		for i := 0; i < c; i += 2 {
			x += int64(box.Content[i])
			y += int64(box.Content[i+1])
		}
		x /= int64(c / 2)
		y /= int64(c / 2)

		return MouseClickXY(x, y, opts...).Do(ctxt, h)
	})
}

// MouseOption is a mouse action option.
type MouseOption func(*input.DispatchMouseEventParams) *input.DispatchMouseEventParams

// Button is a mouse action option to set the button to click from a string.
func Button(btn string) MouseOption {
	return ButtonType(input.ButtonType(btn))
}

// ButtonType is a mouse action option to set the button to click.
func ButtonType(button input.ButtonType) MouseOption {
	return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
		return p.WithButton(button)
	}
}

// ButtonLeft is a mouse action option to set the button clicked as the left
// mouse button.
func ButtonLeft(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
	return p.WithButton(input.ButtonLeft)
}

// ButtonMiddle is a mouse action option to set the button clicked as the middle
// mouse button.
func ButtonMiddle(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
	return p.WithButton(input.ButtonMiddle)
}

// ButtonRight is a mouse action option to set the button clicked as the right
// mouse button.
func ButtonRight(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
	return p.WithButton(input.ButtonRight)
}

// ButtonNone is a mouse action option to set the button clicked as none (used
// for mouse movements).
func ButtonNone(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
	return p.WithButton(input.ButtonNone)
}

// ButtonModifiers is a mouse action option to add additional input modifiers
// for a button click.
func ButtonModifiers(modifiers ...input.Modifier) MouseOption {
	return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
		for _, m := range modifiers {
			p.Modifiers |= m
		}
		return p
	}
}

// ClickCount is a mouse action option to set the click count.
func ClickCount(n int) MouseOption {
	return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
		return p.WithClickCount(int64(n))
	}
}

// KeyAction will synthesize a keyDown, char, and keyUp event for each rune
// contained in keys along with any supplied key options.
//
// Note: only well known, "printable" characters will have "char" events
// synthesized.
func KeyAction(keys string, opts ...KeyOption) Action {
	return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
		var err error

		for _, r := range keys {
			for _, k := range kb.Encode(r) {
				err = k.Do(ctxt, h)
				if err != nil {
					return err
				}
			}

			// TODO: move to context
			time.Sleep(5 * time.Millisecond)
		}

		return nil
	})
}

// KeyActionNode dispatches a key event on a node.
func KeyActionNode(n *cdp.Node, keys string, opts ...KeyOption) Action {
	return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
		err := dom.Focus(n.NodeID).Do(ctxt, h)
		if err != nil {
			return err
		}

		return KeyAction(keys, opts...).Do(ctxt, h)
	})
}

// KeyOption is a key action option.
type KeyOption func(*input.DispatchKeyEventParams) *input.DispatchKeyEventParams

// KeyModifiers is a key action option to add additional modifiers on the key
// press.
func KeyModifiers(modifiers ...input.Modifier) KeyOption {
	return func(p *input.DispatchKeyEventParams) *input.DispatchKeyEventParams {
		for _, m := range modifiers {
			p.Modifiers |= m
		}
		return p
	}
}
<commit_msg>SendKeys randomize wait<commit_after>package chromedp

import (
	"context"
	"fmt"
	"math/rand"
	"time"

	"github.com/knq/chromedp/cdp"
	"github.com/knq/chromedp/cdp/dom"
	"github.com/knq/chromedp/cdp/input"
	"github.com/knq/chromedp/kb"
)

// MouseAction is a mouse action.
func MouseAction(typ input.MouseType, x, y int64, opts ...MouseOption) Action {
	me := input.DispatchMouseEvent(typ, x, y)

	// apply opts
	for _, o := range opts {
		me = o(me)
	}

	return me
}

// MouseClickXY sends a left mouse button click (ie, mousePressed and
// mouseReleased event) at the X, Y location.
func MouseClickXY(x, y int64, opts ...MouseOption) Action {
	return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
		me := &input.DispatchMouseEventParams{
			Type:       input.MousePressed,
			X:          x,
			Y:          y,
			Button:     input.ButtonLeft,
			ClickCount: 1,
		}

		// apply opts
		for _, o := range opts {
			me = o(me)
		}

		err := me.Do(ctxt, h)
		if err != nil {
			return err
		}

		me.Type = input.MouseReleased
		return me.Do(ctxt, h)
	})
}

// MouseClickNode dispatches a mouse left button click event at the center of a
// specified node.
//
// Note that the window will be scrolled if the node is not within the window's
// viewport.
func MouseClickNode(n *cdp.Node, opts ...MouseOption) Action {
	return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
		var err error

		var pos []int
		err = EvaluateAsDevTools(fmt.Sprintf(scrollIntoViewJS, n.FullXPath()), &pos).Do(ctxt, h)
		if err != nil {
			return err
		}

		box, err := dom.GetBoxModel(n.NodeID).Do(ctxt, h)
		if err != nil {
			return err
		}

		c := len(box.Content)
		if c%2 != 0 || c < 1 {
			return ErrInvalidDimensions
		}

		var x, y int64
		for i := 0; i < c; i += 2 {
			x += int64(box.Content[i])
			y += int64(box.Content[i+1])
		}
		x /= int64(c / 2)
		y /= int64(c / 2)

		return MouseClickXY(x, y, opts...).Do(ctxt, h)
	})
}

// MouseOption is a mouse action option.
type MouseOption func(*input.DispatchMouseEventParams) *input.DispatchMouseEventParams

// Button is a mouse action option to set the button to click from a string.
func Button(btn string) MouseOption {
	return ButtonType(input.ButtonType(btn))
}

// ButtonType is a mouse action option to set the button to click.
func ButtonType(button input.ButtonType) MouseOption {
	return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
		return p.WithButton(button)
	}
}

// ButtonLeft is a mouse action option to set the button clicked as the left
// mouse button.
func ButtonLeft(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
	return p.WithButton(input.ButtonLeft)
}

// ButtonMiddle is a mouse action option to set the button clicked as the middle
// mouse button.
func ButtonMiddle(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
	return p.WithButton(input.ButtonMiddle)
}

// ButtonRight is a mouse action option to set the button clicked as the right
// mouse button.
func ButtonRight(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
	return p.WithButton(input.ButtonRight)
}

// ButtonNone is a mouse action option to set the button clicked as none (used
// for mouse movements).
func ButtonNone(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
	return p.WithButton(input.ButtonNone)
}

// ButtonModifiers is a mouse action option to add additional input modifiers
// for a button click.
func ButtonModifiers(modifiers ...input.Modifier) MouseOption {
	return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
		for _, m := range modifiers {
			p.Modifiers |= m
		}
		return p
	}
}

// ClickCount is a mouse action option to set the click count.
func ClickCount(n int) MouseOption {
	return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
		return p.WithClickCount(int64(n))
	}
}

// KeyAction will synthesize a keyDown, char, and keyUp event for each rune
// contained in keys along with any supplied key options.
//
// Note: only well known, "printable" characters will have "char" events
// synthesized.
func KeyAction(keys string, opts ...KeyOption) Action {
	return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
		var err error

		for _, r := range keys {
			for _, k := range kb.Encode(r) {
				err = k.Do(ctxt, h)
				if err != nil {
					return err
				}
			}

			// TODO: move to context
			time.Sleep((time.Duration(rand.Intn(50)) + 50) * time.Millisecond)
		}

		return nil
	})
}

// KeyActionNode dispatches a key event on a node.
func KeyActionNode(n *cdp.Node, keys string, opts ...KeyOption) Action {
	return ActionFunc(func(ctxt context.Context, h cdp.Handler) error {
		err := dom.Focus(n.NodeID).Do(ctxt, h)
		if err != nil {
			return err
		}

		return KeyAction(keys, opts...).Do(ctxt, h)
	})
}

// KeyOption is a key action option.
type KeyOption func(*input.DispatchKeyEventParams) *input.DispatchKeyEventParams

// KeyModifiers is a key action option to add additional modifiers on the key
// press.
func KeyModifiers(modifiers ...input.Modifier) KeyOption {
	return func(p *input.DispatchKeyEventParams) *input.DispatchKeyEventParams {
		for _, m := range modifiers {
			p.Modifiers |= m
		}
		return p
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
)

type IPAddress struct {
	IP string `json:"ip"`
}

func jsonip(w http.ResponseWriter, r *http.Request) {
	host := net.ParseIP(r.Header["X-Forwarded-For"][len(r.Header["X-Forwarded-For"])-1]).String()
	jsonStr, _ := json.Marshal(IPAddress{host})

	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, string(jsonStr))
}

func textip(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		panic(err)
	}

	for k, _ := range r.Form {
		fmt.Println(k, r.Form[k])
	}

	host := net.ParseIP(r.Header["X-Forwarded-For"][len(r.Header["X-Forwarded-For"])-1]).String()

	w.Header().Set("Content-Type", "text/plain")
	fmt.Fprintf(w, host)
}

func NotFound(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(404)
}

func main() {
	http.HandleFunc("/json", jsonip)
	http.HandleFunc("/text", textip)

	err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
	if err != nil {
		panic(err)
	}
}
<commit_msg>Testing array.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
)

type IPAddress struct {
	IP string `json:"ip"`
}

func jsonip(w http.ResponseWriter, r *http.Request) {
	host := net.ParseIP(r.Header["X-Forwarded-For"][len(r.Header["X-Forwarded-For"])-1]).String()
	jsonStr, _ := json.Marshal(IPAddress{host})

	w.Header().Set("Content-Type", "application/json")
	fmt.Fprintf(w, string(jsonStr))
}

func textip(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		panic(err)
	}

	for k, _ := range r.Form {
		fmt.Println(k, r.Form[k][0])
	}

	host := net.ParseIP(r.Header["X-Forwarded-For"][len(r.Header["X-Forwarded-For"])-1]).String()

	w.Header().Set("Content-Type", "text/plain")
	fmt.Fprintf(w, host)
}

func NotFound(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(404)
}

func main() {
	http.HandleFunc("/json", jsonip)
	http.HandleFunc("/text", textip)

	err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>/*
Package Jamon is an INI-like configuration file parser. An example configuration
file may look like this:
	address=127.0.0.1:1234 # root-level values

	[defaults]
	key=value
	name=Gabriel

	[category]
	key=value
Trailing comments are also allowed, and root-level keys are only accepted at the
top of the file
*/
package jamon

import (
	"bufio"
	"os"
	"strings"
)

// A configuration type may hold multiple categories of settings
type Config map[string]Category

// A category holds key-value pairs of settings
type Category map[string]string

// Internal name for category that holds settings at root-level
const defaultCategory = "JAMON.NO_CATEGORY"

// Returns the value of a key that is not in any category. These keys should
// be placed at the top of the file with no title if desired.
func (c Config) Get(key string) string { return c[defaultCategory].Get(key) }

// Verifies if a key is available in the "no category" section
func (c Config) HasKey(key string) bool {
	_, ok := c[defaultCategory][key]
	return ok
}

// Returns a category by name. If the category does not exist, an empty category
// is returned. Errors are not returned here in order to allow chaining.
func (c Config) Category(name string) Category { return c[name] }

// Verifies if a category exists
func (c Config) HasCategory(category string) bool {
	_, ok := c[category]
	return ok
}

// Returns a key from a category
func (c Category) Get(key string) string { return c[key] }

// Verifies if the category has a key
func (c Category) HasKey(key string) bool {
	_, ok := c[key]
	return ok
}

// Loads a configuration file
func Load(filename string) (Config, error) {
	file, err := os.Open(filename)
	if err != nil {
		return Config{}, err
	}

	defer file.Close()

	reader := bufio.NewReader(file)
	config := Config{}
	currentCategory := defaultCategory

	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			break
		}

		isCategory, value, key, skip := parseLine(string(line))

		switch {
		case skip:
			continue

		case isCategory:
			currentCategory = value
			continue

		case config[currentCategory] == nil:
			config[currentCategory] = make(Category)
			fallthrough
		default:
			config[currentCategory][key] = value
		}
	}

	return config, nil
}

// Attempts to parse an entry in the config file. The first return value specifies
// whether 'value' is the name of a category or the value of a key.
func parseLine(line string) (isCategory bool, value, key string, skip bool) {
	line = strings.SplitN(line, "#", 2)[0]
	line = strings.Trim(line, " \t\r")

	// Is comment?
	if strings.HasPrefix(line, "#") || len(line) == 0 {
		skip = true
		return
	}

	// Is category?
	if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
		isCategory = true
		value = strings.Trim(line, "[]")
		return
	}

	// Attempt to parse key/value pair
	parts := strings.SplitN(line, "=", 2)
	if len(parts) < 2 {
		skip = true
		return
	}

	// Trim end-of-line comments
	key = parts[0]
	value = strings.TrimRight(parts[1], " ")

	return
}
<commit_msg>Comments++<commit_after>/*
Package Jamon is an INI-like configuration file parser. An example configuration
file may look like this:
	address=127.0.0.1:1234 # root-level values

	[defaults]
	key=value
	name=Gabriel

	[category]
	key=value
Trailing comments are also allowed, and root-level keys are only accepted at the
top of the file
*/
package jamon

import (
	"bufio"
	"os"
	"strings"
)

// A configuration type may hold multiple categories of settings
type Config map[string]Category

// A category holds key-value pairs of settings
type Category map[string]string

// Internal name for category that holds settings at root-level
const defaultCategory = "JAMON.NO_CATEGORY"

// Returns the value of a root-level key
func (c Config) Get(key string) string { return c[defaultCategory].Get(key) }

// Verifies the existence of a root-level key
func (c Config) HasKey(key string) bool {
	_, ok := c[defaultCategory][key]
	return ok
}

// Returns a category by name. If the category does not exist, an empty category
// is returned. This is to avoid multiple return values in order to facilitate
// chaining.
func (c Config) Category(name string) Category { return c[name] }

// Verifies if a category exists
func (c Config) HasCategory(category string) bool {
	_, ok := c[category]
	return ok
}

// Returns a key from a category
func (c Category) Get(key string) string { return c[key] }

// Verifies if the category has a key
func (c Category) HasKey(key string) bool {
	_, ok := c[key]
	return ok
}

// Loads a configuration file
func Load(filename string) (Config, error) {
	file, err := os.Open(filename)
	if err != nil {
		return Config{}, err
	}

	defer file.Close()

	reader := bufio.NewReader(file)
	config := Config{}
	currentCategory := defaultCategory

	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			break
		}

		isCategory, value, key, skip := parseLine(string(line))

		switch {
		case skip:
			continue

		case isCategory:
			currentCategory = value
			continue

		case config[currentCategory] == nil:
			config[currentCategory] = make(Category)
			fallthrough
		default:
			config[currentCategory][key] = value
		}
	}

	return config, nil
}

// Attempts to parse an entry in the config file. The first return value specifies
// whether 'value' is the name of a category or the value of a key. Skip indicates
// whether the line was a comment or could not be parsed.
func parseLine(line string) (isCategory bool, value, key string, skip bool) {
	line = strings.SplitN(line, "#", 2)[0]
	line = strings.Trim(line, " \t\r")

	// Is comment or empty line?
	if len(line) == 0 {
		skip = true
		return
	}

	// Is category?
	if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
		isCategory = true
		value = strings.Trim(line, "[]")
		return
	}

	// Is key/value pair?
	parts := strings.SplitN(line, "=", 2)
	if len(parts) < 2 {
		skip = true
		return
	}

	key = parts[0]
	value = strings.TrimRight(parts[1], " ")

	return
}
<|endoftext|>


<commit_before>package js

import (
	log "github.com/Sirupsen/logrus"
	"github.com/loadimpact/speedboat/stats"
	"github.com/robertkrimen/otto"
	"github.com/valyala/fasthttp"
	"time"
)

var (
	mRequests = stats.Stat{Name: "requests", Type: stats.HistogramType, Intent: stats.TimeIntent}
	mErrors   = stats.Stat{Name: "errors", Type: stats.CounterType}
)

type HTTPParams struct {
	Quiet   bool
	Headers map[string]string
}

type HTTPResponse struct {
	Status  int
	Headers map[string]string
	Body    string
}

func (res HTTPResponse) ToValue(vm *otto.Otto) (otto.Value, error) {
	obj, err := Make(vm, "HTTPResponse")
	if err != nil {
		return otto.UndefinedValue(), err
	}

	obj.Set("status", res.Status)
	obj.Set("headers", res.Headers)
	obj.Set("body", res.Body)

	return vm.ToValue(obj)
}

func (u *VU) HTTPRequest(method, url, body string, params HTTPParams) (HTTPResponse, error) {
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)

	req.Header.SetMethod(method)

	if method == "GET" || method == "HEAD" {
		req.SetRequestURI(putBodyInURL(url, body))
	} else if body != "" {
		req.SetRequestURI(url)
		req.SetBodyString(body)
	}

	for key, value := range params.Headers {
		req.Header.Set(key, value)
	}

	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)

	startTime := time.Now()
	err := u.Client.Do(req, resp)
	duration := time.Since(startTime)

	if !params.Quiet {
		u.Collector.Add(stats.Point{
			Stat: &mRequests,
			Tags: stats.Tags{
				"url":    url,
				"method": method,
				"status": resp.StatusCode(),
			},
			Values: stats.Values{"duration": float64(duration)},
		})
	}

	if err != nil {
		if !params.Quiet {
			u.Collector.Add(stats.Point{
				Stat: &mErrors,
				Tags: stats.Tags{
					"url":    url,
					"method": method,
					"status": resp.StatusCode(),
				},
				Values: stats.Value(1),
			})
		}
		return HTTPResponse{}, err
	}

	headers := make(map[string]string)
	resp.Header.VisitAll(func(key []byte, value []byte) {
		headers[string(key)] = string(value)
	})

	return HTTPResponse{
		Status:  resp.StatusCode(),
		Headers: headers,
		Body:    string(resp.Body()),
	}, nil
}

func (u *VU) Sleep(t float64) {
	time.Sleep(time.Duration(t * float64(time.Second)))
}

func (u *VU) Log(level, msg string, fields map[string]interface{}) {
	e := u.Runner.logger.WithFields(log.Fields(fields))

	switch level {
	case "debug":
		e.Debug(msg)
	case "info":
		e.Info(msg)
	case "warn":
		e.Warn(msg)
	case "error":
		e.Error(msg)
	}
}
<commit_msg>[fix] ...why did I do that<commit_after>package js

import (
	log "github.com/Sirupsen/logrus"
	"github.com/loadimpact/speedboat/stats"
	"github.com/robertkrimen/otto"
	"github.com/valyala/fasthttp"
	"time"
)

var (
	mRequests = stats.Stat{Name: "requests", Type: stats.HistogramType, Intent: stats.TimeIntent}
	mErrors   = stats.Stat{Name: "errors", Type: stats.CounterType}
)

type HTTPParams struct {
	Quiet   bool
	Headers map[string]string
}

type HTTPResponse struct {
	Status  int
	Headers map[string]string
	Body    string
}

func (res HTTPResponse) ToValue(vm *otto.Otto) (otto.Value, error) {
	obj, err := Make(vm, "HTTPResponse")
	if err != nil {
		return otto.UndefinedValue(), err
	}

	obj.Set("status", res.Status)
	obj.Set("headers", res.Headers)
	obj.Set("body", res.Body)

	return vm.ToValue(obj)
}

func (u *VU) HTTPRequest(method, url, body string, params HTTPParams) (HTTPResponse, error) {
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)

	req.Header.SetMethod(method)

	if method == "GET" || method == "HEAD" {
		req.SetRequestURI(putBodyInURL(url, body))
	} else {
		req.SetRequestURI(url)
		req.SetBodyString(body)
	}

	for key, value := range params.Headers {
		req.Header.Set(key, value)
	}

	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)

	startTime := time.Now()
	err := u.Client.Do(req, resp)
	duration := time.Since(startTime)

	if !params.Quiet {
		u.Collector.Add(stats.Point{
			Stat: &mRequests,
			Tags: stats.Tags{
				"url":    url,
				"method": method,
				"status": resp.StatusCode(),
			},
			Values: stats.Values{"duration": float64(duration)},
		})
	}

	if err != nil {
		if !params.Quiet {
			u.Collector.Add(stats.Point{
				Stat: &mErrors,
				Tags: stats.Tags{
					"url":    url,
					"method": method,
					"status": resp.StatusCode(),
				},
				Values: stats.Value(1),
			})
		}
		return HTTPResponse{}, err
	}

	headers := make(map[string]string)
	resp.Header.VisitAll(func(key []byte, value []byte) {
		headers[string(key)] = string(value)
	})

	return HTTPResponse{
		Status:  resp.StatusCode(),
		Headers: headers,
		Body:    string(resp.Body()),
	}, nil
}

func (u *VU) Sleep(t float64) {
	time.Sleep(time.Duration(t * float64(time.Second)))
}

func (u *VU) Log(level, msg string, fields map[string]interface{}) {
	e := u.Runner.logger.WithFields(log.Fields(fields))

	switch level {
	case "debug":
		e.Debug(msg)
	case "info":
		e.Info(msg)
	case "warn":
		e.Warn(msg)
	case "error":
		e.Error(msg)
	}
}
<|endoftext|>


<commit_before><commit_msg>PR #16<commit_after><|endoftext|>


<commit_before><commit_msg>separate out data logging in CPUUtilizationFlag for both timestamp as int64 and timestamp as a formatted string<commit_after><|endoftext|>


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

package kv

import (
	"bytes"
	"math"

	"github.com/juju/errors"
)

// Key represents high-level Key type.
type Key []byte

// Next returns the next key in byte-order.
func (k Key) Next() Key {
	// add 0x0 to the end of key
	buf := make([]byte, len([]byte(k))+1)
	copy(buf, []byte(k))
	return buf
}

// Cmp returns the comparison result of two key.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (k Key) Cmp(another Key) int {
	return bytes.Compare(k, another)
}

// EncodedKey represents encoded key in low-level storage engine.
type EncodedKey []byte

// Cmp returns the comparison result of two key.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (k EncodedKey) Cmp(another EncodedKey) int {
	return bytes.Compare(k, another)
}

// Next returns the next key in byte-order.
func (k EncodedKey) Next() EncodedKey {
	return EncodedKey(bytes.Join([][]byte{k, Key{0}}, nil))
}

// VersionProvider provides increasing IDs.
type VersionProvider interface {
	CurrentVersion() (Version, error)
}

// Version is the wrapper of KV's version.
type Version struct {
	Ver uint64
}

var (
	// MaxVersion is the maximum version, notice that it's not a valid version.
	MaxVersion = Version{Ver: math.MaxUint64}
	// MinVersion is the minimum version, it's not a valid version, too.
	MinVersion = Version{Ver: 0}
)

// NewVersion creates a new Version struct.
func NewVersion(v uint64) Version {
	return Version{
		Ver: v,
	}
}

// Cmp returns the comparison result of two versions.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (v Version) Cmp(another Version) int {
	if v.Ver > another.Ver {
		return 1
	} else if v.Ver < another.Ver {
		return -1
	}
	return 0
}

// DecodeFn is a function that decodes data after fetching from store.
type DecodeFn func(raw interface{}) (interface{}, error)

// EncodeFn is a function that encodes data before putting into store.
type EncodeFn func(raw interface{}) (interface{}, error)

// ErrNotCommitted is the error returned by CommitVersion when this
// transaction is not committed.
var ErrNotCommitted = errors.New("this transaction is not committed")

// Option is used for customizing kv store's behaviors during a transaction.
type Option int

// Options is an interface of a set of options. Each option is associated with a value.
type Options interface {
	// Get gets an option value.
	Get(opt Option) (v interface{}, ok bool)
}

const (
	// RangePrefetchOnCacheMiss directives that when dealing with a Get operation but failing to read data from cache,
	// it will launch a RangePrefetch to underlying storage instead of Get. The range starts from requested key and
	// has a limit of the option value. The feature is disabled if option value <= 0 or value type is not int.
	// This option is particularly useful when we have to do sequential Gets, e.g. table scans.
	RangePrefetchOnCacheMiss Option = iota + 1

	// PresumeKeyNotExists directives that when dealing with a Get operation but failing to read data from cache,
	// we presume that the key does not exist in Store. The actual existence will be checked before the
	// transaction's commit.
	// This option is an optimization for frequent checks during a transaction, e.g. batch inserts.
	PresumeKeyNotExists
)

// Retriever is the interface wraps the basic Get and Seek methods.
type Retriever interface {
	// Get gets the value for key k from KV storage.
	Get(k Key) ([]byte, error)
	// Seek searches for the entry with key k in KV storage.
	Seek(k Key) (Iterator, error)
}

// Mutator is the interface wraps the basic Set and Delete methods.
type Mutator interface {
	// Set sets the value for key k as v into KV storage.
	Set(k Key, v []byte) error
	// Delete removes the entry for key k from KV storage.
	Delete(k Key) error
}

// RetrieverMutator is the interface that groups Retriever and Mutator interface.
type RetrieverMutator interface {
	Retriever
	Mutator
}

// MemBuffer is the interface for transaction buffer of update in a transaction
type MemBuffer interface {
	RetrieverMutator
	// Release releases the buffer.
	Release()
}

// BufferStore is the interface that wraps a Retriever for read and contains a MemBuffer for buffered write.
type BufferStore interface {
	MemBuffer
	// WalkBuffer iterates all buffered kv pairs.
	WalkBuffer(f func(k Key, v []byte) error) error
	// Save saves buffered kv pairs into Mutator.
	Save(m Mutator) error
}

// UnionStore is an in-memory Store which contains a buffer for write and a
// snapshot for read.
type UnionStore interface {
	BufferStore
	// Inc increases the value for key k in KV storage by step.
	Inc(k Key, step int64) (int64, error)
	// GetInt64 get int64 which created by Inc method.
	GetInt64(k Key) (int64, error)
	// CheckLazyConditionPairs loads all lazy values from store then checks if all values are matched.
	// Lazy condition pairs should be checked before transaction commit.
	CheckLazyConditionPairs() error
	// BatchPrefetch fetches values from KV storage to cache for later use.
	BatchPrefetch(keys []Key) error
	// RangePrefetch fetches values in the range [start, end] from KV storage
	// to cache for later use. Maximum number of values is up to limit.
	RangePrefetch(start, end Key, limit int) error
	// SetOption sets an option with a value, when val is nil, uses the default
	// value of this option.
	SetOption(opt Option, val interface{})
	// DelOption deletes an option.
	DelOption(opt Option)
	// ReleaseSnapshot releases underlying snapshot.
	ReleaseSnapshot()
}

// Transaction defines the interface for operations inside a Transaction.
// This is not thread safe.
type Transaction interface {
	UnionStore
	// Commit commits the transaction operations to KV store.
	Commit() error
	// CommittedVersion returns the version of this committed transaction. If this
	// transaction has not been committed, returns ErrNotCommitted error.
	CommittedVersion() (Version, error)
	// Rollback undoes the transaction operations to KV store.
	Rollback() error
	// String implements fmt.Stringer interface.
	String() string
	// LockKeys tries to lock the entries with the keys in KV store.
	LockKeys(keys ...Key) error
}

// MvccSnapshot is used to get/seek a specific version in a snapshot.
type MvccSnapshot interface {
	// MvccGet returns the specific version of given key, if the version doesn't
	// exist, returns the nearest(lower) version's data.
	MvccGet(k Key, ver Version) ([]byte, error)
	// MvccIterator seeks to the key in the specific version's snapshot, if the
	// version doesn't exist, returns the nearest(lower) version's snaphot.
	NewMvccIterator(k Key, ver Version) Iterator
	// Release releases this snapshot.
	MvccRelease()
}

// Snapshot defines the interface for the snapshot fetched from KV store.
type Snapshot interface {
	Retriever
	// BatchGet gets a batch of values from snapshot.
	BatchGet(keys []Key) (map[string][]byte, error)
	// RangeGet gets values in the range [start, end] from snapshot. Maximum
	// number of values is up to limit.
	RangeGet(start, end Key, limit int) (map[string][]byte, error)
	// Release releases the snapshot to store.
	Release()
}

// Driver is the interface that must be implemented by a KV storage.
type Driver interface {
	// Open returns a new Storage.
	// The schema is the string for storage specific format.
	Open(schema string) (Storage, error)
}

// Storage defines the interface for storage.
// Isolation should be at least SI(SNAPSHOT ISOLATION)
type Storage interface {
	// Begin transaction
	Begin() (Transaction, error)
	// GetSnapshot gets a snaphot that is able to read any data which data is <= ver.
	// if ver is MaxVersion or > current max committed version, we will use current version for this snapshot.
	GetSnapshot(ver Version) (MvccSnapshot, error)
	// Close store
	Close() error
	// Storage's unique ID
	UUID() string
	// CurrentVersion returns current max committed version.
	CurrentVersion() (Version, error)
}

// FnKeyCmp is the function for iterator the keys
type FnKeyCmp func(key Key) bool

// Iterator is the interface for a interator on KV store.
type Iterator interface {
	Next() error
	Value() []byte
	Key() string
	Valid() bool
	Close()
}

// IndexIterator is the interface for iterator of index data on KV store.
type IndexIterator interface {
	Next() (k []interface{}, h int64, err error)
	Close()
}

// Index is the interface for index data on KV store.
type Index interface {
	Create(rw RetrieverMutator, indexedValues []interface{}, h int64) error                          // supports insert into statement
	Delete(rw RetrieverMutator, indexedValues []interface{}, h int64) error                          // supports delete from statement
	Drop(rw RetrieverMutator) error                                                                  // supports drop table, drop index statements
	Exist(rw RetrieverMutator, indexedValues []interface{}, h int64) (bool, int64, error)            // supports check index exist
	GenIndexKey(indexedValues []interface{}, h int64) (key []byte, distinct bool, err error)         // supports index check
	Seek(rw RetrieverMutator, indexedValues []interface{}) (iter IndexIterator, hit bool, err error) // supports where clause
	SeekFirst(rw RetrieverMutator) (iter IndexIterator, err error)                                   // supports aggregate min / ascending order by
}
<commit_msg>kv: add comments<commit_after>// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package kv

import (
	"bytes"
	"math"

	"github.com/juju/errors"
)

// Key represents high-level Key type.
type Key []byte

// Next returns the next key in byte-order.
func (k Key) Next() Key {
	// add 0x0 to the end of key
	buf := make([]byte, len([]byte(k))+1)
	copy(buf, []byte(k))
	return buf
}

// Cmp returns the comparison result of two key.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (k Key) Cmp(another Key) int {
	return bytes.Compare(k, another)
}

// EncodedKey represents encoded key in low-level storage engine.
type EncodedKey []byte

// Cmp returns the comparison result of two key.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (k EncodedKey) Cmp(another EncodedKey) int {
	return bytes.Compare(k, another)
}

// Next returns the next key in byte-order.
func (k EncodedKey) Next() EncodedKey {
	return EncodedKey(bytes.Join([][]byte{k, Key{0}}, nil))
}

// VersionProvider provides increasing IDs.
type VersionProvider interface {
	CurrentVersion() (Version, error)
}

// Version is the wrapper of KV's version.
type Version struct {
	Ver uint64
}

var (
	// MaxVersion is the maximum version, notice that it's not a valid version.
	MaxVersion = Version{Ver: math.MaxUint64}
	// MinVersion is the minimum version, it's not a valid version, too.
	MinVersion = Version{Ver: 0}
)

// NewVersion creates a new Version struct.
func NewVersion(v uint64) Version {
	return Version{
		Ver: v,
	}
}

// Cmp returns the comparison result of two versions.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (v Version) Cmp(another Version) int {
	if v.Ver > another.Ver {
		return 1
	} else if v.Ver < another.Ver {
		return -1
	}
	return 0
}

// DecodeFn is a function that decodes data after fetching from store.
type DecodeFn func(raw interface{}) (interface{}, error)

// EncodeFn is a function that encodes data before putting into store.
type EncodeFn func(raw interface{}) (interface{}, error)

// ErrNotCommitted is the error returned by CommitVersion when this
// transaction is not committed.
var ErrNotCommitted = errors.New("this transaction is not committed")

// Option is used for customizing kv store's behaviors during a transaction.
type Option int

// Options is an interface of a set of options. Each option is associated with a value.
type Options interface {
	// Get gets an option value.
	Get(opt Option) (v interface{}, ok bool)
}

const (
	// RangePrefetchOnCacheMiss directives that when dealing with a Get operation but failing to read data from cache,
	// it will launch a RangePrefetch to underlying storage instead of Get. The range starts from requested key and
	// has a limit of the option value. The feature is disabled if option value <= 0 or value type is not int.
	// This option is particularly useful when we have to do sequential Gets, e.g. table scans.
	RangePrefetchOnCacheMiss Option = iota + 1

	// PresumeKeyNotExists directives that when dealing with a Get operation but failing to read data from cache,
	// we presume that the key does not exist in Store. The actual existence will be checked before the
	// transaction's commit.
	// This option is an optimization for frequent checks during a transaction, e.g. batch inserts.
	PresumeKeyNotExists
)

// Retriever is the interface wraps the basic Get and Seek methods.
type Retriever interface {
	// Get gets the value for key k from kv store.
	// If corresponding kv pair does not exist, it returns nil and ErrNotExist.
	Get(k Key) ([]byte, error)
	// Seek creates an Iterator positioned on the first entry that k <= entry's key.
	// If such entry is not found, it returns a invalid Iterator with no error.
	// The Iterator must be Closed after use.
	Seek(k Key) (Iterator, error)
}

// Mutator is the interface wraps the basic Set and Delete methods.
type Mutator interface {
	// Set sets the value for key k as v into kv store.
	// v must NOT be nil or empty, otherwise it returns ErrCannotSetNilValue.
	Set(k Key, v []byte) error
	// Delete removes the entry for key k from kv store.
	Delete(k Key) error
}

// RetrieverMutator is the interface that groups Retriever and Mutator interfaces.
type RetrieverMutator interface {
	Retriever
	Mutator
}

// MemBuffer is an in-memory kv collection. It should be released after use.
type MemBuffer interface {
	RetrieverMutator
	// Release releases the buffer.
	Release()
}

// BufferStore is the interface that wraps a Retriever for read and a MemBuffer for buffered write.
type BufferStore interface {
	MemBuffer
	// WalkBuffer iterates all buffered kv pairs.
	WalkBuffer(f func(k Key, v []byte) error) error
	// Save saves buffered kv pairs into Mutator.
	Save(m Mutator) error
}

// UnionStore is a store that wraps a snapshot for read and a BufferStore for buffered write.
// Also, it provides some transaction related utilities.
type UnionStore interface {
	BufferStore
	// Inc increases the value for key k in KV storage by step.
	Inc(k Key, step int64) (int64, error)
	// GetInt64 get int64 which created by Inc method.
	GetInt64(k Key) (int64, error)
	// CheckLazyConditionPairs loads all lazy values from store then checks if all values are matched.
	// Lazy condition pairs should be checked before transaction commit.
	CheckLazyConditionPairs() error
	// BatchPrefetch fetches values from KV storage to cache for later use.
	BatchPrefetch(keys []Key) error
	// RangePrefetch fetches values in the range [start, end] from KV storage
	// to cache for later use. Maximum number of values is up to limit.
	RangePrefetch(start, end Key, limit int) error
	// SetOption sets an option with a value, when val is nil, uses the default
	// value of this option.
	SetOption(opt Option, val interface{})
	// DelOption deletes an option.
	DelOption(opt Option)
	// ReleaseSnapshot releases underlying snapshot.
	ReleaseSnapshot()
}

// Transaction defines the interface for operations inside a Transaction.
// This is not thread safe.
type Transaction interface {
	UnionStore
	// Commit commits the transaction operations to KV store.
	Commit() error
	// CommittedVersion returns the version of this committed transaction. If this
	// transaction has not been committed, returns ErrNotCommitted error.
	CommittedVersion() (Version, error)
	// Rollback undoes the transaction operations to KV store.
	Rollback() error
	// String implements fmt.Stringer interface.
	String() string
	// LockKeys tries to lock the entries with the keys in KV store.
	LockKeys(keys ...Key) error
}

// MvccSnapshot is used to get/seek a specific version in a snapshot.
type MvccSnapshot interface {
	// MvccGet returns the specific version of given key, if the version doesn't
	// exist, returns the nearest(lower) version's data.
	MvccGet(k Key, ver Version) ([]byte, error)
	// MvccIterator seeks to the key in the specific version's snapshot, if the
	// version doesn't exist, returns the nearest(lower) version's snaphot.
	NewMvccIterator(k Key, ver Version) Iterator
	// Release releases this snapshot.
	MvccRelease()
}

// Snapshot defines the interface for the snapshot fetched from KV store.
type Snapshot interface {
	Retriever
	// BatchGet gets a batch of values from snapshot.
	BatchGet(keys []Key) (map[string][]byte, error)
	// RangeGet gets values in the range [start, end] from snapshot. Maximum
	// number of values is up to limit.
	RangeGet(start, end Key, limit int) (map[string][]byte, error)
	// Release releases the snapshot to store.
	Release()
}

// Driver is the interface that must be implemented by a KV storage.
type Driver interface {
	// Open returns a new Storage.
	// The schema is the string for storage specific format.
	Open(schema string) (Storage, error)
}

// Storage defines the interface for storage.
// Isolation should be at least SI(SNAPSHOT ISOLATION)
type Storage interface {
	// Begin transaction
	Begin() (Transaction, error)
	// GetSnapshot gets a snaphot that is able to read any data which data is <= ver.
	// if ver is MaxVersion or > current max committed version, we will use current version for this snapshot.
	GetSnapshot(ver Version) (MvccSnapshot, error)
	// Close store
	Close() error
	// Storage's unique ID
	UUID() string
	// CurrentVersion returns current max committed version.
	CurrentVersion() (Version, error)
}

// FnKeyCmp is the function for iterator the keys
type FnKeyCmp func(key Key) bool

// Iterator is the interface for a interator on KV store.
type Iterator interface {
	Next() error
	Value() []byte
	Key() string
	Valid() bool
	Close()
}

// IndexIterator is the interface for iterator of index data on KV store.
type IndexIterator interface {
	Next() (k []interface{}, h int64, err error)
	Close()
}

// Index is the interface for index data on KV store.
type Index interface {
	Create(rw RetrieverMutator, indexedValues []interface{}, h int64) error                          // supports insert into statement
	Delete(rw RetrieverMutator, indexedValues []interface{}, h int64) error                          // supports delete from statement
	Drop(rw RetrieverMutator) error                                                                  // supports drop table, drop index statements
	Exist(rw RetrieverMutator, indexedValues []interface{}, h int64) (bool, int64, error)            // supports check index exist
	GenIndexKey(indexedValues []interface{}, h int64) (key []byte, distinct bool, err error)         // supports index check
	Seek(rw RetrieverMutator, indexedValues []interface{}) (iter IndexIterator, hit bool, err error) // supports where clause
	SeekFirst(rw RetrieverMutator) (iter IndexIterator, err error)                                   // supports aggregate min / ascending order by
}
<|endoftext|>


<commit_before><commit_msg>Improve git_trees.go coverage (#1741)<commit_after><|endoftext|>


<commit_before>package influxdb

import (
	"context"
)

// ErrLabelNotFound is the error for a missing Label.
const ErrLabelNotFound = ChronografError("label not found")

const (
	OpFindLabels         = "FindLabels"
	OpFindLabelByID      = "FindLabelByID"
	OpFindLabelMapping   = "FindLabelMapping"
	OpCreateLabel        = "CreateLabel"
	OpCreateLabelMapping = "CreateLabelMapping"
	OpUpdateLabel        = "UpdateLabel"
	OpDeleteLabel        = "DeleteLabel"
	OpDeleteLabelMapping = "DeleteLabelMapping"
)

// LabelService represents a service for managing resource labels
type LabelService interface {
	// FindLabelByID a single label by ID.
	FindLabelByID(ctx context.Context, id ID) (*Label, error)

	// FindLabels returns a list of labels that match a filter
	FindLabels(ctx context.Context, filter LabelFilter, opt ...FindOptions) ([]*Label, error)

	// FindResourceLabels returns a list of labels that belong to a resource
	FindResourceLabels(ctx context.Context, filter LabelMappingFilter) ([]*Label, error)

	// CreateLabel creates a new label
	CreateLabel(ctx context.Context, l *Label) error

	// CreateLabel maps a resource to an existing label
	CreateLabelMapping(ctx context.Context, m *LabelMapping) error

	// UpdateLabel updates a label with a changeset.
	UpdateLabel(ctx context.Context, id ID, upd LabelUpdate) (*Label, error)

	// DeleteLabel deletes a label
	DeleteLabel(ctx context.Context, id ID) error

	// DeleteLabelMapping deletes a label mapping
	DeleteLabelMapping(ctx context.Context, m *LabelMapping) error
}

// Label is a tag set on a resource, typically used for filtering on a UI.
type Label struct {
	ID         ID                `json:"id,omitempty"`
	Name       string            `json:"name"`
	Properties map[string]string `json:"properties,omitempty"`
}

// Validate returns an error if the label is invalid.
func (l *Label) Validate() error {
	if l.Name == "" {
		return &Error{
			Code: EInvalid,
			Msg:  "label name is required",
		}
	}

	return nil
}

// LabelMapping is used to map resource to its labels.
// It should not be shared directly over the HTTP API.
type LabelMapping struct {
	LabelID    *ID `json:"labelID"`
	ResourceID *ID
}

// Validate returns an error if the mapping is invalid.
func (l *LabelMapping) Validate() error {
	if !l.ResourceID.Valid() {
		return &Error{
			Code: EInvalid,
			Msg:  "resourceID is required",
		}
	}

	return nil
}

// LabelUpdate represents a changeset for a label.
// Only fields which are set are updated.
type LabelUpdate struct {
	Properties map[string]string `json:"properties,omitempty"`
}

// LabelFilter represents a set of filters that restrict the returned results.
type LabelFilter struct {
	ID   ID
	Name string
}

// LabelMappingFilter represents a set of filters that restrict the returned results.
type LabelMappingFilter struct {
	ResourceID ID
}
<commit_msg>fix(influxdb): label mappings reference label ID, resource ID, and resource type now<commit_after>package influxdb

import (
	"context"
)

// ErrLabelNotFound is the error for a missing Label.
const ErrLabelNotFound = ChronografError("label not found")

const (
	OpFindLabels         = "FindLabels"
	OpFindLabelByID      = "FindLabelByID"
	OpFindLabelMapping   = "FindLabelMapping"
	OpCreateLabel        = "CreateLabel"
	OpCreateLabelMapping = "CreateLabelMapping"
	OpUpdateLabel        = "UpdateLabel"
	OpDeleteLabel        = "DeleteLabel"
	OpDeleteLabelMapping = "DeleteLabelMapping"
)

// LabelService represents a service for managing resource labels
type LabelService interface {
	// FindLabelByID a single label by ID.
	FindLabelByID(ctx context.Context, id ID) (*Label, error)

	// FindLabels returns a list of labels that match a filter
	FindLabels(ctx context.Context, filter LabelFilter, opt ...FindOptions) ([]*Label, error)

	// FindResourceLabels returns a list of labels that belong to a resource
	FindResourceLabels(ctx context.Context, filter LabelMappingFilter) ([]*Label, error)

	// CreateLabel creates a new label
	CreateLabel(ctx context.Context, l *Label) error

	// CreateLabel maps a resource to an existing label
	CreateLabelMapping(ctx context.Context, m *LabelMapping) error

	// UpdateLabel updates a label with a changeset.
	UpdateLabel(ctx context.Context, id ID, upd LabelUpdate) (*Label, error)

	// DeleteLabel deletes a label
	DeleteLabel(ctx context.Context, id ID) error

	// DeleteLabelMapping deletes a label mapping
	DeleteLabelMapping(ctx context.Context, m *LabelMapping) error
}

// Label is a tag set on a resource, typically used for filtering on a UI.
type Label struct {
	ID         ID                `json:"id,omitempty"`
	Name       string            `json:"name"`
	Properties map[string]string `json:"properties,omitempty"`
}

// Validate returns an error if the label is invalid.
func (l *Label) Validate() error {
	if l.Name == "" {
		return &Error{
			Code: EInvalid,
			Msg:  "label name is required",
		}
	}

	return nil
}

// LabelMapping is used to map resource to its labels.
// It should not be shared directly over the HTTP API.
type LabelMapping struct {
	LabelID    ID `json:"labelID"`
	ResourceID ID
	ResourceType
}

// Validate returns an error if the mapping is invalid.
func (l *LabelMapping) Validate() error {

	// todo(leodido) > check LabelID is valid too?

	if !l.ResourceID.Valid() {
		return &Error{
			Code: EInvalid,
			Msg:  "resourceID is required",
		}
	}
	if err := l.ResourceType.Valid(); err != nil {
		return &Error{
			Code: EInvalid,
			Err:  err,
		}
	}

	return nil
}

// LabelUpdate represents a changeset for a label.
// Only fields which are set are updated.
type LabelUpdate struct {
	Properties map[string]string `json:"properties,omitempty"`
}

// LabelFilter represents a set of filters that restrict the returned results.
type LabelFilter struct {
	ID   ID
	Name string
}

// LabelMappingFilter represents a set of filters that restrict the returned results.
type LabelMappingFilter struct {
	ResourceID ID
}
<|endoftext|>


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

package walk

import . "github.com/lxn/go-winapi"

var labelOrigWndProcPtr uintptr
var _ subclassedWidget = &Label{}

type Label struct {
	WidgetBase
}

func NewLabel(parent Container) (*Label, error) {
	l := &Label{}

	if err := initChildWidget(
		l,
		parent,
		"STATIC",
		WS_VISIBLE|SS_CENTERIMAGE,
		0); err != nil {
		return nil, err
	}

	return l, nil
}

func (*Label) origWndProcPtr() uintptr {
	return labelOrigWndProcPtr
}

func (*Label) setOrigWndProcPtr(ptr uintptr) {
	labelOrigWndProcPtr = ptr
}

func (*Label) LayoutFlags() LayoutFlags {
	return GrowableVert
}

func (l *Label) MinSizeHint() Size {
	return l.calculateTextSize()
}

func (l *Label) SizeHint() Size {
	return l.calculateTextSize()
}

func (l *Label) Text() string {
	return widgetText(l.hWnd)
}

func (l *Label) SetText(value string) error {
	if value == l.Text() {
		return nil
	}

	if err := setWidgetText(l.hWnd, value); err != nil {
		return err
	}

	return l.updateParentLayout()
}
<commit_msg>Make sure labels get repainted when resized<commit_after>// Copyright 2010 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package walk

import . "github.com/lxn/go-winapi"

var labelOrigWndProcPtr uintptr
var _ subclassedWidget = &Label{}

type Label struct {
	WidgetBase
}

func NewLabel(parent Container) (*Label, error) {
	l := &Label{}

	if err := initChildWidget(
		l,
		parent,
		"STATIC",
		WS_VISIBLE|SS_CENTERIMAGE,
		0); err != nil {
		return nil, err
	}

	return l, nil
}

func (*Label) origWndProcPtr() uintptr {
	return labelOrigWndProcPtr
}

func (*Label) setOrigWndProcPtr(ptr uintptr) {
	labelOrigWndProcPtr = ptr
}

func (*Label) LayoutFlags() LayoutFlags {
	return GrowableVert
}

func (l *Label) MinSizeHint() Size {
	return l.calculateTextSize()
}

func (l *Label) SizeHint() Size {
	return l.calculateTextSize()
}

func (l *Label) Text() string {
	return widgetText(l.hWnd)
}

func (l *Label) SetText(value string) error {
	if value == l.Text() {
		return nil
	}

	if err := setWidgetText(l.hWnd, value); err != nil {
		return err
	}

	return l.updateParentLayout()
}

func (l *Label) wndProc(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
	switch msg {
	case WM_SIZE, WM_SIZING:
		l.Invalidate()
	}

	return l.WidgetBase.wndProc(hwnd, msg, wParam, lParam)
}
<|endoftext|>


<commit_before>// Package webface provides web interface to view collected data.
package webface

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/fcgi"
	"strconv"

	"github.com/bradfitz/gomemcache/memcache"
	"github.com/gorilla/mux"
	"github.com/steamhistory/core/analysis"
	"github.com/steamhistory/core/apps"
	"github.com/steamhistory/core/usage"
)

// Start starts FastCGI server at 127.0.0.1:9000
func Start() {
	log.Println("Starting server...")
	log.Println("Listening on 127.0.0.1:9000...")
	l, err := net.Listen("tcp", "127.0.0.1:9000")
	if err != nil {
		log.Fatal("Failed to start server!", err)
	}
	fcgi.Serve(l, makeRouter())
}

// StartDev starts development server at localhost:8080
func StartDev() {
	log.Println("Starting development server (localhost:8080)...")
	http.ListenAndServe(":8080", makeRouter())
}

func makeRouter() *mux.Router {
	r := mux.NewRouter().StrictSlash(true)
	r.HandleFunc("/", indexHandler)
	r.HandleFunc("/apps", appsHandler)
	r.HandleFunc("/apps/popular", dailyPopularHandler)
	r.HandleFunc("/history/{appid:[0-9]+}", historyHandler)
	return r
}

var mc *memcache.Client = memcache.New("localhost:11211")

/*
 * Handlers
 */

func indexHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("See API documentation.\n"))
}

func historyHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	appId, err := strconv.Atoi(vars["appid"])
	if err != nil {
		http.Error(w, "Internal error.", http.StatusInternalServerError)
		log.Println(err)
		return
	}

	key := "history_" + strconv.Itoa(appId)
	it, err := mc.Get(key)
	var b []byte
	if err == nil {
		b = it.Value
	} else {
		name, err := apps.GetName(appId)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		history, err := usage.AllUsageHistory(appId)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		type jason struct {
			Name    string     `json:"name"`
			History [][2]int64 `json:"history"`
		}
		result := jason{
			Name:    name,
			History: history,
		}
		b, err = json.Marshal(result)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		err = mc.Set(&memcache.Item{Key: key, Value: b, Expiration: 1800}) // 1800 sec = 30 min
		if err != nil {
			log.Println(err)
		}
	}

	queries := r.URL.Query()
	callback, ok := queries["callback"]
	if ok {
		w.Header().Set("Content-Type", "application/javascript")
		fmt.Fprintf(w, "%s(%s)", callback[0], b)
	} else {
		w.Header().Set("Content-Type", "application/json")
		w.Write(b)
	}
}

func dailyPopularHandler(w http.ResponseWriter, r *http.Request) {
	rows, err := analysis.MostPopularAppsToday()
	if err != nil {
		http.Error(w, "Internal error.", http.StatusInternalServerError)
		log.Println(err)
		return
	}

	key := "top"
	it, err := mc.Get(key)
	var b []byte
	if err == nil {
		b = it.Value
	} else {
		b, err = json.Marshal(rows)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		err = mc.Set(&memcache.Item{Key: key, Value: b, Expiration: 1800}) // 1800 sec = 30 min
		if err != nil {
			log.Println(err)
		}
	}

	queries := r.URL.Query()
	callback, ok := queries["callback"]
	if ok {
		w.Header().Set("Content-Type", "application/javascript")
		fmt.Fprintf(w, "%s(%s)", callback[0], b)
	} else {
		w.Header().Set("Content-Type", "application/json")
		w.Write(b)
	}
}

func appsHandler(w http.ResponseWriter, r *http.Request) {
	queries := r.URL.Query()
	query, ok := queries["q"]
	if !ok {
		// TODO: Return all apps
		http.Error(w, "No query", http.StatusBadRequest)
		return
	}

	h := md5.New()
	key := fmt.Sprintf("%x", h.Sum([]byte(query[0])))
	it, err := mc.Get(key)
	var b []byte
	if err == nil {
		b = it.Value
	} else {
		results, err := apps.Search(query[0])
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		b, err = json.Marshal(results)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		err = mc.Set(&memcache.Item{Key: key, Value: b, Expiration: 43200}) // 43200 sec = 12 hours
		if err != nil {
			log.Println(err)
		}
	}

	callback, ok := queries["callback"]
	if ok {
		w.Header().Set("Content-Type", "application/javascript")
		fmt.Fprintf(w, "%s(%s)", callback[0], b)
	} else {
		w.Header().Set("Content-Type", "application/json")
		w.Write(b)
	}
}
<commit_msg>Moved previously added print to more appropriate place.<commit_after>// Package webface provides web interface to view collected data.
package webface

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/fcgi"
	"strconv"

	"github.com/bradfitz/gomemcache/memcache"
	"github.com/gorilla/mux"
	"github.com/steamhistory/core/analysis"
	"github.com/steamhistory/core/apps"
	"github.com/steamhistory/core/usage"
)

// Start starts FastCGI server at 127.0.0.1:9000
func Start() {
	log.Println("Starting server...")
	l, err := net.Listen("tcp", "127.0.0.1:9000")
	if err != nil {
		log.Fatal("Failed to start server!", err)
	}
	log.Println("Listening on 127.0.0.1:9000...")
	fcgi.Serve(l, makeRouter())
}

// StartDev starts development server at localhost:8080
func StartDev() {
	log.Println("Starting development server (localhost:8080)...")
	http.ListenAndServe(":8080", makeRouter())
}

func makeRouter() *mux.Router {
	r := mux.NewRouter().StrictSlash(true)
	r.HandleFunc("/", indexHandler)
	r.HandleFunc("/apps", appsHandler)
	r.HandleFunc("/apps/popular", dailyPopularHandler)
	r.HandleFunc("/history/{appid:[0-9]+}", historyHandler)
	return r
}

var mc *memcache.Client = memcache.New("localhost:11211")

/*
 * Handlers
 */

func indexHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte("See API documentation.\n"))
}

func historyHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	appId, err := strconv.Atoi(vars["appid"])
	if err != nil {
		http.Error(w, "Internal error.", http.StatusInternalServerError)
		log.Println(err)
		return
	}

	key := "history_" + strconv.Itoa(appId)
	it, err := mc.Get(key)
	var b []byte
	if err == nil {
		b = it.Value
	} else {
		name, err := apps.GetName(appId)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		history, err := usage.AllUsageHistory(appId)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		type jason struct {
			Name    string     `json:"name"`
			History [][2]int64 `json:"history"`
		}
		result := jason{
			Name:    name,
			History: history,
		}
		b, err = json.Marshal(result)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		err = mc.Set(&memcache.Item{Key: key, Value: b, Expiration: 1800}) // 1800 sec = 30 min
		if err != nil {
			log.Println(err)
		}
	}

	queries := r.URL.Query()
	callback, ok := queries["callback"]
	if ok {
		w.Header().Set("Content-Type", "application/javascript")
		fmt.Fprintf(w, "%s(%s)", callback[0], b)
	} else {
		w.Header().Set("Content-Type", "application/json")
		w.Write(b)
	}
}

func dailyPopularHandler(w http.ResponseWriter, r *http.Request) {
	rows, err := analysis.MostPopularAppsToday()
	if err != nil {
		http.Error(w, "Internal error.", http.StatusInternalServerError)
		log.Println(err)
		return
	}

	key := "top"
	it, err := mc.Get(key)
	var b []byte
	if err == nil {
		b = it.Value
	} else {
		b, err = json.Marshal(rows)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		err = mc.Set(&memcache.Item{Key: key, Value: b, Expiration: 1800}) // 1800 sec = 30 min
		if err != nil {
			log.Println(err)
		}
	}

	queries := r.URL.Query()
	callback, ok := queries["callback"]
	if ok {
		w.Header().Set("Content-Type", "application/javascript")
		fmt.Fprintf(w, "%s(%s)", callback[0], b)
	} else {
		w.Header().Set("Content-Type", "application/json")
		w.Write(b)
	}
}

func appsHandler(w http.ResponseWriter, r *http.Request) {
	queries := r.URL.Query()
	query, ok := queries["q"]
	if !ok {
		// TODO: Return all apps
		http.Error(w, "No query", http.StatusBadRequest)
		return
	}

	h := md5.New()
	key := fmt.Sprintf("%x", h.Sum([]byte(query[0])))
	it, err := mc.Get(key)
	var b []byte
	if err == nil {
		b = it.Value
	} else {
		results, err := apps.Search(query[0])
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		b, err = json.Marshal(results)
		if err != nil {
			http.Error(w, "Internal error.", http.StatusInternalServerError)
			log.Println(err)
			return
		}
		err = mc.Set(&memcache.Item{Key: key, Value: b, Expiration: 43200}) // 43200 sec = 12 hours
		if err != nil {
			log.Println(err)
		}
	}

	callback, ok := queries["callback"]
	if ok {
		w.Header().Set("Content-Type", "application/javascript")
		fmt.Fprintf(w, "%s(%s)", callback[0], b)
	} else {
		w.Header().Set("Content-Type", "application/json")
		w.Write(b)
	}
}
<|endoftext|>