<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package components

import (
	"net/http"
	"sync"

	mesos "github.com/mesos/mesos-go/mesosproto"
	"k8s.io/kubernetes/contrib/mesos/pkg/backoff"
	"k8s.io/kubernetes/contrib/mesos/pkg/offers"
	"k8s.io/kubernetes/contrib/mesos/pkg/queue"
	"k8s.io/kubernetes/contrib/mesos/pkg/runtime"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/algorithm"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/algorithm/podschedulers"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/binder"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/controller"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/deleter"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/errorhandler"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/framework"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/podreconciler"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/config"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podtask"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/queuer"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/cache"
	"k8s.io/kubernetes/pkg/client/record"
	client "k8s.io/kubernetes/pkg/client/unversioned"
)

// sched implements the Scheduler interface.
type sched struct {
	podReconciler podreconciler.PodReconciler
	framework     framework.Framework
	controller    controller.Controller

	// unsafe state, needs to be guarded, especially changes to podtask.T objects
	sync.RWMutex
	taskRegistry  podtask.Registry
}

func New(c *config.Config, fw framework.Framework, ps podschedulers.PodScheduler,
	client *client.Client, recorder record.EventRecorder, terminate <-chan struct{}, mux *http.ServeMux, lw *cache.ListWatch) scheduler.Scheduler {

	core := &sched{
		framework:    fw,
		taskRegistry: podtask.NewInMemoryRegistry(),
	}

	// Watch and queue pods that need scheduling.
	updates := make(chan queue.Entry, c.UpdatesBacklog)
	podUpdates := &podStoreAdapter{queue.NewHistorical(updates)}
	reflector := cache.NewReflector(lw, &api.Pod{}, podUpdates, 0)

	q := queuer.New(podUpdates)

	algorithm := algorithm.New(core, podUpdates, ps)

	podDeleter := deleter.New(core, q)

	core.podReconciler = podreconciler.New(core, client, q, podDeleter)

	bo := backoff.New(c.InitialPodBackoff.Duration, c.MaxPodBackoff.Duration)
	newBC := func(podKey string) queue.BreakChan {
		return queue.BreakChan(core.Offers().Listen(podKey, func(offer *mesos.Offer) bool {
			core.Lock()
			defer core.Unlock()
			switch task, state := core.Tasks().ForPod(podKey); state {
			case podtask.StatePending:
				// Assess fitness of pod with the current offer. The scheduler normally
				// "backs off" when it can't find an offer that matches up with a pod.
				// The backoff period for a pod can terminate sooner if an offer becomes
				// available that matches up.
				return !task.Has(podtask.Launched) && ps.FitPredicate()(task, offer, nil)
			default:
				// no point in continuing to check for matching offers
				return true
			}
		}))
	}
	errorHandler := errorhandler.New(core, bo, q, newBC)

	binder := binder.New(core)

	startLatch := make(chan struct{})

	runtime.On(startLatch, func() {
		reflector.Run() // TODO(jdef) should listen for termination
		podDeleter.Run(updates, terminate)
		q.Run(terminate)

		q.InstallDebugHandlers(mux)
		podtask.InstallDebugHandlers(core.Tasks(), mux)
	})

	core.controller = controller.New(client, algorithm, recorder, q.Yield, errorHandler.Error, binder, startLatch)
	return core
}

func (c *sched) Run(done <-chan struct{}) {
	c.controller.Run(done)
}

func (c *sched) Reconcile(t *podtask.T) {
	c.podReconciler.Reconcile(t)
}

func (c *sched) Tasks() podtask.Registry {
	return c.taskRegistry
}

func (c *sched) Offers() offers.Registry {
	return c.framework.Offers()
}

func (c *sched) KillTask(id string) error {
	return c.framework.KillTask(id)
}

func (c *sched) LaunchTask(t *podtask.T) error {
	return c.framework.LaunchTask(t)
}
<commit_msg>gofmt fixes<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package components

import (
	"net/http"
	"sync"

	mesos "github.com/mesos/mesos-go/mesosproto"
	"k8s.io/kubernetes/contrib/mesos/pkg/backoff"
	"k8s.io/kubernetes/contrib/mesos/pkg/offers"
	"k8s.io/kubernetes/contrib/mesos/pkg/queue"
	"k8s.io/kubernetes/contrib/mesos/pkg/runtime"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/algorithm"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/algorithm/podschedulers"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/binder"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/controller"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/deleter"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/errorhandler"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/framework"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/components/podreconciler"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/config"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/podtask"
	"k8s.io/kubernetes/contrib/mesos/pkg/scheduler/queuer"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/cache"
	"k8s.io/kubernetes/pkg/client/record"
	client "k8s.io/kubernetes/pkg/client/unversioned"
)

// sched implements the Scheduler interface.
type sched struct {
	podReconciler podreconciler.PodReconciler
	framework     framework.Framework
	controller    controller.Controller

	// unsafe state, needs to be guarded, especially changes to podtask.T objects
	sync.RWMutex
	taskRegistry podtask.Registry
}

func New(c *config.Config, fw framework.Framework, ps podschedulers.PodScheduler,
	client *client.Client, recorder record.EventRecorder, terminate <-chan struct{}, mux *http.ServeMux, lw *cache.ListWatch) scheduler.Scheduler {

	core := &sched{
		framework:    fw,
		taskRegistry: podtask.NewInMemoryRegistry(),
	}

	// Watch and queue pods that need scheduling.
	updates := make(chan queue.Entry, c.UpdatesBacklog)
	podUpdates := &podStoreAdapter{queue.NewHistorical(updates)}
	reflector := cache.NewReflector(lw, &api.Pod{}, podUpdates, 0)

	q := queuer.New(podUpdates)

	algorithm := algorithm.New(core, podUpdates, ps)

	podDeleter := deleter.New(core, q)

	core.podReconciler = podreconciler.New(core, client, q, podDeleter)

	bo := backoff.New(c.InitialPodBackoff.Duration, c.MaxPodBackoff.Duration)
	newBC := func(podKey string) queue.BreakChan {
		return queue.BreakChan(core.Offers().Listen(podKey, func(offer *mesos.Offer) bool {
			core.Lock()
			defer core.Unlock()
			switch task, state := core.Tasks().ForPod(podKey); state {
			case podtask.StatePending:
				// Assess fitness of pod with the current offer. The scheduler normally
				// "backs off" when it can't find an offer that matches up with a pod.
				// The backoff period for a pod can terminate sooner if an offer becomes
				// available that matches up.
				return !task.Has(podtask.Launched) && ps.FitPredicate()(task, offer, nil)
			default:
				// no point in continuing to check for matching offers
				return true
			}
		}))
	}
	errorHandler := errorhandler.New(core, bo, q, newBC)

	binder := binder.New(core)

	startLatch := make(chan struct{})

	runtime.On(startLatch, func() {
		reflector.Run() // TODO(jdef) should listen for termination
		podDeleter.Run(updates, terminate)
		q.Run(terminate)

		q.InstallDebugHandlers(mux)
		podtask.InstallDebugHandlers(core.Tasks(), mux)
	})

	core.controller = controller.New(client, algorithm, recorder, q.Yield, errorHandler.Error, binder, startLatch)
	return core
}

func (c *sched) Run(done <-chan struct{}) {
	c.controller.Run(done)
}

func (c *sched) Reconcile(t *podtask.T) {
	c.podReconciler.Reconcile(t)
}

func (c *sched) Tasks() podtask.Registry {
	return c.taskRegistry
}

func (c *sched) Offers() offers.Registry {
	return c.framework.Offers()
}

func (c *sched) KillTask(id string) error {
	return c.framework.KillTask(id)
}

func (c *sched) LaunchTask(t *podtask.T) error {
	return c.framework.LaunchTask(t)
}
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"regexp"
	"sync"
	"time"
)

const replyTimeout = 45 * time.Second

type replyDisposition int

const (
	replied          replyDisposition = iota
	replyInterrupted                  // user started another command or canceled
	retryPrompt                       // another prompt was in progress
)

// a replyWaiter is used when a plugin is waiting for a reply
type replyWaiter struct {
	re           *regexp.Regexp // The regular expression the reply needs to match
	replyChannel chan reply     // The channel to send the reply to when it is received
}

// a reply matcher is used as the key in the replys map
type replyMatcher struct {
	user, channel string // Only one reply at a time can be requested for a given user/channel combination
}

// a reply is sent over the replyWaiter channel when a user replies
type reply struct {
	matched     bool             // true if the regex matched
	disposition replyDisposition // replied, interrupted, retry
	rep         string           // text of the reply
}

var replies = struct {
	m map[replyMatcher][]replyWaiter
	sync.Mutex
}{
	make(map[replyMatcher][]replyWaiter),
	sync.Mutex{},
}

type stockReply struct {
	repTag   string
	repRegex string
}

var stockRepliesRegex = `^[A-Z]`
var stockRepliesRe *regexp.Regexp

var stockReplies = make(map[string]*regexp.Regexp)

var stockReplyList = []stockReply{
	{"Email", `[\w-\.]+@(?:[\w-]+\.)+[\w-]{2,4}`},
	{"Domain", `(?:[\w-]+\.)+[\w-]{2,4}`},
	{"OTP", `\d{6}`},
	//	{ "IPaddr", `[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}` }
	{"IPaddr", `(?:(?:0|1[0-9]{0,2}|2[0-9]?|2[0-4][0-9]|25[0-5]|[3-9][0-9]?)\.){3}(?:0|1[0-9]{0,2}|2[0-9]?|2[0-4][0-9]|25[0-5]|[3-9][0-9]?)`},
	{"SimpleString", `[-\w .,_'"?!]+`},
	{"YesNo", `(?i:yes|no|Y|N)`},
}

func init() {
	stockRepliesRe = regexp.MustCompile(stockRepliesRegex)
	for _, sr := range stockReplyList {
		stockReplies[sr.repTag] = regexp.MustCompile(`^\s*` + sr.repRegex + `\s*$`)
	}
}

// PromptForReply lets a plugin direct a prompt string to a user and temporarily
// register a regex for a reply expected to a multi-step command when the robot
// needs more info. If the regular expression matches, it returns the matched
// text and RetVal = Ok.
// If the regular expression doesn't match, it returns an empty string
// with one of the following RetVals:
//	Interrupted - the user issued a new command that ran or canceled with '-'
//  UseDefaultValue - user supplied a single "=", meaning "use the default value"
//	ReplyNotMatched - didn't successfully match for any reason
//	MatcherNotFound - the regexId didn't correspond to a valid regex
//	TimeoutExpired - the user didn't respond within the timeout window
//
// Plugin authors can define regex's for regexId's in the plugin's JSON config,
// with the restriction that the regexId must start with a lowercase letter.
// A pre-definied regex from the following list can also be used:
// 	Email
//	Domain - an alpha-numeric domain name
//	OTP - a 6-digit one-time password code
//	IPAddr
//	SimpleString - Characters commonly found in most english sentences, doesn't
//    include special characters like @, {, etc.
//	YesNo
func (r *Robot) PromptForReply(regexID string, prompt string) (string, RetVal) {
	var rep string
	var ret RetVal
	for i := 0; i < 3; i++ {
		rep, ret = r.promptInternal(regexID, r.User, r.Channel, prompt)
		if ret == RetryPrompt {
			continue
		}
		return rep, ret
	}
	if ret == RetryPrompt {
		return rep, Interrupted
	}
	return rep, ret
}

// PromptUserForReply is identical to PromptForReply, but prompts a specific
// user with a DM.
func (r *Robot) PromptUserForReply(regexID string, user string, prompt string) (string, RetVal) {
	var rep string
	var ret RetVal
	for i := 0; i < 3; i++ {
		rep, ret = r.promptInternal(regexID, user, "", prompt)
		if ret == RetryPrompt {
			continue
		}
		return rep, ret
	}
	if ret == RetryPrompt {
		return rep, Interrupted
	}
	return rep, ret
}

// PromptUserChannelForReply is identical to PromptForReply, but prompts a
// specific user in a given channel.
func (r *Robot) PromptUserChannelForReply(regexID string, user string, channel string, prompt string) (string, RetVal) {
	var rep string
	var ret RetVal
	for i := 0; i < 3; i++ {
		rep, ret = r.promptInternal(regexID, user, channel, prompt)
		if ret == RetryPrompt {
			continue
		}
		return rep, ret
	}
	if ret == RetryPrompt {
		return rep, Interrupted
	}
	return rep, ret
}

// promptInternal can return 'RetryPrompt'
func (r *Robot) promptInternal(regexID string, user string, channel string, prompt string) (string, RetVal) {
	matcher := replyMatcher{
		user:    user,
		channel: channel,
	}
	var rep replyWaiter
	plugin := currentPlugins.getPluginByID(r.pluginID)
	if stockRepliesRe.MatchString(regexID) {
		rep.re = stockReplies[regexID]
	} else {
		for _, matcher := range plugin.ReplyMatchers {
			if matcher.Label == regexID {
				rep.re = matcher.re
				break
			} else if matcher.Command == regexID {
				rep.re = matcher.re
			}
		}
	}
	if rep.re == nil {
		r.Log(Error, fmt.Sprintf("Unable to resolve a reply matcher for plugin %s, regexID %s", plugin.name, regexID))
		return "", MatcherNotFound
	}
	rep.replyChannel = make(chan reply)

	replies.Lock()
	// See if there's already a continuation in progress for this Robot:user,channel,
	// and if so append to the list of waiters.
	waiters, exists := replies.m[matcher]
	if exists {
		r.Log(Debug, fmt.Sprintf("Delaying prompt \"%s\" and appending to the list of waiters for matcher: %q", prompt, matcher))
		waiters = append(waiters, rep)
		replies.m[matcher] = waiters
		replies.Unlock()
	} else {
		r.Log(Debug, fmt.Sprintf("Prompting for \"%s \" and creating reply waiters list and prompting for matcher: %q", prompt, matcher))
		waiters = make([]replyWaiter, 1, 2)
		waiters[0] = rep
		replies.m[matcher] = waiters
		replies.Unlock()
		if channel == "" {
			robot.SendProtocolUserMessage(user, prompt, r.Format)
		} else {
			robot.SendProtocolUserChannelMessage(user, channel, prompt, r.Format)
		}
	}
	var replied reply
	select {
	case <-time.After(replyTimeout):
		Log(Warn, fmt.Sprintf("Timed out waiting for a reply to regex \"%s\" in channel: %s", regexID, r.Channel))
		replies.Lock()
		waitlist, found := replies.m[matcher]
		if found {
			// reply timed out, free up this matcher for later reply requests
			delete(replies.m, matcher)
			replies.Unlock()
			Log(Debug, fmt.Sprintf("Timeout expired waiting for reply to: %s", prompt))
			// let other waiters know to retry
			for i, rep := range waitlist {
				if i != 0 {
					Log(Debug, "Sending retryPrompt to waiters on primary waiter timeout")
					rep.replyChannel <- reply{false, retryPrompt, ""}
				}
			}
			// matched=false, timedOut=true
			return "", TimeoutExpired
		}
		// race: we got a reply at the timeout deadline, and lost the race
		// to delete the entry, so we read the reply as if the timeout hadn't
		// expired.
		replies.Unlock()
		replied = <-rep.replyChannel
	case replied = <-rep.replyChannel:
	}
	if replied.disposition == replyInterrupted {
		return "", Interrupted
	}
	if replied.disposition == retryPrompt {
		return "", RetryPrompt
	}
	// Note: the replies.m[] entry is deleted in handleMessage
	if !replied.matched {
		if replied.rep == "=" {
			return "", UseDefaultValue
		}
		if replied.rep == "-" {
			return "", Interrupted
		}
		return "", ReplyNotMatched
	}
	return replied.rep, Ok
}
<commit_msg>Check for and return error on message send<commit_after>package bot

import (
	"fmt"
	"regexp"
	"sync"
	"time"
)

const replyTimeout = 45 * time.Second

type replyDisposition int

const (
	replied          replyDisposition = iota
	replyInterrupted                  // user started another command or canceled
	retryPrompt                       // another prompt was in progress
)

// a replyWaiter is used when a plugin is waiting for a reply
type replyWaiter struct {
	re           *regexp.Regexp // The regular expression the reply needs to match
	replyChannel chan reply     // The channel to send the reply to when it is received
}

// a reply matcher is used as the key in the replys map
type replyMatcher struct {
	user, channel string // Only one reply at a time can be requested for a given user/channel combination
}

// a reply is sent over the replyWaiter channel when a user replies
type reply struct {
	matched     bool             // true if the regex matched
	disposition replyDisposition // replied, interrupted, retry
	rep         string           // text of the reply
}

var replies = struct {
	m map[replyMatcher][]replyWaiter
	sync.Mutex
}{
	make(map[replyMatcher][]replyWaiter),
	sync.Mutex{},
}

type stockReply struct {
	repTag   string
	repRegex string
}

var stockRepliesRegex = `^[A-Z]`
var stockRepliesRe *regexp.Regexp

var stockReplies = make(map[string]*regexp.Regexp)

var stockReplyList = []stockReply{
	{"Email", `[\w-\.]+@(?:[\w-]+\.)+[\w-]{2,4}`},
	{"Domain", `(?:[\w-]+\.)+[\w-]{2,4}`},
	{"OTP", `\d{6}`},
	//	{ "IPaddr", `[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}` }
	{"IPaddr", `(?:(?:0|1[0-9]{0,2}|2[0-9]?|2[0-4][0-9]|25[0-5]|[3-9][0-9]?)\.){3}(?:0|1[0-9]{0,2}|2[0-9]?|2[0-4][0-9]|25[0-5]|[3-9][0-9]?)`},
	{"SimpleString", `[-\w .,_'"?!]+`},
	{"YesNo", `(?i:yes|no|Y|N)`},
}

func init() {
	stockRepliesRe = regexp.MustCompile(stockRepliesRegex)
	for _, sr := range stockReplyList {
		stockReplies[sr.repTag] = regexp.MustCompile(`^\s*` + sr.repRegex + `\s*$`)
	}
}

// PromptForReply lets a plugin direct a prompt string to a user and temporarily
// register a regex for a reply expected to a multi-step command when the robot
// needs more info. If the regular expression matches, it returns the matched
// text and RetVal = Ok.
// If there's an error getting the reply, it returns an empty string
// with one of the following RetVals:
//  UserNotFound
//  ChannelNotFound
//	Interrupted - the user issued a new command that ran or canceled with '-'
//  UseDefaultValue - user supplied a single "=", meaning "use the default value"
//	ReplyNotMatched - didn't successfully match for any reason
//	MatcherNotFound - the regexId didn't correspond to a valid regex
//	TimeoutExpired - the user didn't respond within the timeout window
//
// Plugin authors can define regex's for regexId's in the plugin's JSON config,
// with the restriction that the regexId must start with a lowercase letter.
// A pre-definied regex from the following list can also be used:
// 	Email
//	Domain - an alpha-numeric domain name
//	OTP - a 6-digit one-time password code
//	IPAddr
//	SimpleString - Characters commonly found in most english sentences, doesn't
//    include special characters like @, {, etc.
//	YesNo
func (r *Robot) PromptForReply(regexID string, prompt string) (string, RetVal) {
	var rep string
	var ret RetVal
	for i := 0; i < 3; i++ {
		rep, ret = r.promptInternal(regexID, r.User, r.Channel, prompt)
		if ret == RetryPrompt {
			continue
		}
		return rep, ret
	}
	if ret == RetryPrompt {
		return rep, Interrupted
	}
	return rep, ret
}

// PromptUserForReply is identical to PromptForReply, but prompts a specific
// user with a DM.
func (r *Robot) PromptUserForReply(regexID string, user string, prompt string) (string, RetVal) {
	var rep string
	var ret RetVal
	for i := 0; i < 3; i++ {
		rep, ret = r.promptInternal(regexID, user, "", prompt)
		if ret == RetryPrompt {
			continue
		}
		return rep, ret
	}
	if ret == RetryPrompt {
		return rep, Interrupted
	}
	return rep, ret
}

// PromptUserChannelForReply is identical to PromptForReply, but prompts a
// specific user in a given channel.
func (r *Robot) PromptUserChannelForReply(regexID string, user string, channel string, prompt string) (string, RetVal) {
	var rep string
	var ret RetVal
	for i := 0; i < 3; i++ {
		rep, ret = r.promptInternal(regexID, user, channel, prompt)
		if ret == RetryPrompt {
			continue
		}
		return rep, ret
	}
	if ret == RetryPrompt {
		return rep, Interrupted
	}
	return rep, ret
}

// promptInternal can return 'RetryPrompt'
func (r *Robot) promptInternal(regexID string, user string, channel string, prompt string) (string, RetVal) {
	matcher := replyMatcher{
		user:    user,
		channel: channel,
	}
	var rep replyWaiter
	plugin := currentPlugins.getPluginByID(r.pluginID)
	if stockRepliesRe.MatchString(regexID) {
		rep.re = stockReplies[regexID]
	} else {
		for _, matcher := range plugin.ReplyMatchers {
			if matcher.Label == regexID {
				rep.re = matcher.re
				break
			} else if matcher.Command == regexID {
				rep.re = matcher.re
			}
		}
	}
	if rep.re == nil {
		r.Log(Error, fmt.Sprintf("Unable to resolve a reply matcher for plugin %s, regexID %s", plugin.name, regexID))
		return "", MatcherNotFound
	}
	rep.replyChannel = make(chan reply)

	replies.Lock()
	// See if there's already a continuation in progress for this Robot:user,channel,
	// and if so append to the list of waiters.
	waiters, exists := replies.m[matcher]
	if exists {
		r.Log(Debug, fmt.Sprintf("Delaying prompt \"%s\" and appending to the list of waiters for matcher: %q", prompt, matcher))
		waiters = append(waiters, rep)
		replies.m[matcher] = waiters
		replies.Unlock()
	} else {
		r.Log(Debug, fmt.Sprintf("Prompting for \"%s \" and creating reply waiters list and prompting for matcher: %q", prompt, matcher))
		var ret RetVal
		if channel == "" {
			ret = robot.SendProtocolUserMessage(user, prompt, r.Format)
		} else {
			ret = robot.SendProtocolUserChannelMessage(user, channel, prompt, r.Format)
		}
		if ret != Ok {
			replies.Unlock()
			return "", ret
		}
		waiters = make([]replyWaiter, 1, 2)
		waiters[0] = rep
		replies.m[matcher] = waiters
		replies.Unlock()
	}
	var replied reply
	select {
	case <-time.After(replyTimeout):
		Log(Warn, fmt.Sprintf("Timed out waiting for a reply to regex \"%s\" in channel: %s", regexID, r.Channel))
		replies.Lock()
		waitlist, found := replies.m[matcher]
		if found {
			// reply timed out, free up this matcher for later reply requests
			delete(replies.m, matcher)
			replies.Unlock()
			Log(Debug, fmt.Sprintf("Timeout expired waiting for reply to: %s", prompt))
			// let other waiters know to retry
			for i, rep := range waitlist {
				if i != 0 {
					Log(Debug, "Sending retryPrompt to waiters on primary waiter timeout")
					rep.replyChannel <- reply{false, retryPrompt, ""}
				}
			}
			// matched=false, timedOut=true
			return "", TimeoutExpired
		}
		// race: we got a reply at the timeout deadline, and lost the race
		// to delete the entry, so we read the reply as if the timeout hadn't
		// expired.
		replies.Unlock()
		replied = <-rep.replyChannel
	case replied = <-rep.replyChannel:
	}
	if replied.disposition == replyInterrupted {
		return "", Interrupted
	}
	if replied.disposition == retryPrompt {
		return "", RetryPrompt
	}
	// Note: the replies.m[] entry is deleted in handleMessage
	if !replied.matched {
		if replied.rep == "=" {
			return "", UseDefaultValue
		}
		if replied.rep == "-" {
			return "", Interrupted
		}
		return "", ReplyNotMatched
	}
	return replied.rep, Ok
}
<|endoftext|>


<commit_before>/*
   Copyright 2015 Tom Cameron

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

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

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

package main

import (
	"fmt"
	"strings"
)

const input string = "()()(()()()(()()((()((()))((()((((()()((((()))()((((())(((((((()(((((((((()(((())(()()(()((()()(()(())(()((((()((()()()((((())((((((()(()(((()())(()((((()))())(())(()(()()))))))))((((((((((((()())()())())(())))(((()()()((((()(((()(()(()()(()(()()(()(((((((())(())(())())))((()())()((((()()((()))(((()()()())))(())))((((())(((()())(())(()))(()((((()())))())((()(())(((()((((()((()(())())))((()))()()(()(()))))((((((((()())((((()()((((()(()())(((((()(()())()))())(((()))()(()(()(()((((()(())(()))(((((()()(()()()(()(((())())(((()()(()()))(((()()(((())())(()(())())()()(())()()()((()(((()(())((()()((())()))((()()))((()()())((((()(()()(()(((()))()(()))))((()(((()()()))(()(((())()(()((()())(()(()()(()())(())()(((()(()())()((((()((()))))())()))((()()()()(())()())()()()((((()))))(()(((()()(((((((())()))()((((()((())()(()())(())()))(()(()())(((((((())))(((()))())))))()))())((())(()()((())()())()))))()((()()())(())((())((((()())())()()()(((()))())))()()))())(()()()(()((((((()()))())()))()(((()(((())((((()()()(()))())()()))))())()))())((())()())(((((())())((())())))(((())(((())(((((()(((((())(()(()())())(()(())(()))(()((((()))())()))))())))((()(()))))())))(((((())()))())()))))()))))(((()))()))))((()))((()((()(()(())()())))(()()()(())()))()((((())))))))(())(()((()()))(()))(()))(()((()))))))()()((((()()))()())()))))))()()()))(()((())(()))((()()()())()(((()((((())())))()((((()(()))))))())))()()())()))(()))))(()())()))))))((())))))))())()))()((())())))(()((()))()))(())))))(()))()())()()))((()(()))()()()()))))())()()))())(())()()))()))((()))))()()(()())))))()()()))((((()))()))))(()(())))(()())))((())())(()))()))))()())))()())()())))))))))()()))))())))((())((()))))())))(((()())))))))(()))()()))(()))()))))()())))))())((((()())))))))())))()()))))))))()))()))))()))))))(())))))))))())))))))))))))))())())((())))))))))()))((())))()))))))))())()(()))))))())))))()()()())()(()()()(()())(()))()()()(()())))())())))()))))())))))))()()()()())(())())()())()))))(()()()()()))))()))())())))((()())()())))()))()))))(()())))()))))))))(((()))()()))))))))))))))))))))(()))(()((()))())))())(()))(()(()(())))))()(()))()))()()))))))))))))()((()())(())())()(())))))())()())((()()))))(()()))))())()(())()))))))))))))))))))))()))(()(()())))))))()()((()))()))))))((())))()))))))))((()))())()()))())()()))((()))())))))))))))(()())()))(())((()(()()))(()())(())))()())(()(())()()))))()))()(()))))))(()))))))))))(()))())))))))))())))))())))(())))))()))))(())())))))))))()(()))))()())))())(()))()())))))))))))))())()()))))()))))))())))))()))))(())(()()()()((())()))())(()))((())()))())())(())(()()))))()))(())()()((())(())))(())))()))())))))))))()(((((())())))(())()))))(())))((()))()(((((((()))))()()))(())))))()(()))))(()()))()))())))))))(()())()))))))))())))(()))())()))(())()((())())()())())(()(()))))()))))))((()())(())()()(()())))()()))(())(())(()))())))()))(()))()()))((((()))))()))((()()()))))()))()))())))(()))()))))(())))()))())()(()))()())))())))))))())))())))()()))))))(()))())())))()))()()())())))))))))))))())))()))(()()))))())))())()(())))())))))))))))))))))()()())())))))()()()((()(()))()()(())()())()))()))))()()()))))))((()))))))))()(()(()((((((()()((()())))))))))))()))())))))((())())(()))())))())))))())()()())(())))())))()())())(())))))))()()(())))()))())))())())())()))))))))()))(()()()())())())))(())())))))))()()())()))))())))())()(())())))))))()())()))(()()(())())))()(()((()()((()()(((((())(()())()))(())()))(())))(())))))))()))()))((()))()))()))))))))()))))))))((()()())(()))(((()))(())))()))((())(((())))()())))())))))((())))))(())())((((((())())()(()))()(()((()())))((())()(()(()))))(())(()()())(())))())((()(((())())))(((()())())))())()(())())((((()()))))())((()))()()()()(())(((((((()()()((()))())(()())))(())())((((()()(()))))()((())))((())()))()(((()))())))()))((()(()))(())(()((((())((((()()(()()))(((())(()))))((((()(()))(())))))((()))(()))((()(((()(()))(()(()((()(())(()(()(()(()()((()))())(((())(()(()))))(()))()()))(())))(())()(((())(()))()((((()()))))())(()))))((())()((((()(((()))())())(((()))()())((())(())())(())()(())()(()()((((((()()))))()()(((()()))))()())()(((()(()))(()(()())(()(()))))(((((()(((())())))))(((((()((()()((())())((((((()(())(()()((()()()()()()()(()()))()(((()))()))(((((((())(((()((()())()((((())(((()(())))()((()(()()()((())((()())()))()))())))())((((((()))(()(()()()))(()((()(()(()))()((()(((()()()((())(((((())()(()))())())((()(())))(()(()())(())((())())())(((()()()(())))))())(()))))))()))))))())((()()()))((()((((((()))(((()((((()()()(((()))())()(()()(((()((()()()()())()()))()()()(()(())((()))))(()))())))))))()(()()(((((())()(()(((((()((()(()()())(()((((((((()((((((())()((((()()()((()((()((((((()))((())))))))())()))((()(()))()(()()(()((())((()()((((((((((((()())(()()()))((((()((((((())(()))())(()()((()()))()(((((((()((()()((((((()(((())))((())))((((((((()()(((((((())(((((()())(((())((())()((((()(((((((()(()(((()((((((()(((()(((((((((((()()((()()(()))((()()(((()(((())))((((())()(()(((())()(()(((())(((((((((((()))())))((((((())((()()((((()())())((((()()))((())(((((()(()()(()()()((())(()((()()((((()(((((()((()(()((((()())((((((()(((((()()(()(()((((())))(())(())(())((((()(()()((((()((((()()((()((((((())))(((((()))))()))(()((((((((()(((())())(((())))(()(()((())(((()((()()(((((()((()()(((())()(()))(((((((())(()(((((()))((()((()((()))(())())((((()((((())()(()))(((()(((((((((((((((())(((((((((()))(((()(()()()()((((((()((())()((((((((()(())(((((((((((()(()((())()((()()(()(()()((((()()((())(()((()()(()()((((()(((((((())))((((())(())()(((()()((()()((((()((()(((()((())(((()()()((((()((((()()(()(()((((((((())(()(((((())(()())(((((((()())()(()((((()((())(()()())((((()()(((()((((())(())(()()(((((((((()()))()(((())(()(()((((((())(()()())(()))()()(((()(((()((())(()(((((((()(()(()((()(((((()(()((()(()((((((()((((()()((((()(((()((())(()(()((()()((((()()(())()(())(((())(()((((((((()())(((((((((()(())()((((())))()))()()(((((()()((((((())(()()(((()(()(((((((()(()(((((((())(())((((()((()(())))((((()()())(()))((()())((((()(((((()(()(())(()(()()())(((((()(((((()((((()()((((((((()()))(()((((((())((((())()(()(((()()()(((()(()(())(())(((((()(())())((((())(())(()(((()(((((())((((())())((()(((((((()(((())(()(()))(((((((((()((()((()()(()((((())(((()((())((((())(()(((()(((()(()((((()(((())(()(((()(()()(()(()((()()(()())(())())((()(()(((()(((()(((()()(((((((((()(((((((((()()(((()(((()())((((()(()(((()()()((())((((((((((())(()(((()((((()())((((()((()))(((()()()(((((()(((((((())((()())(()((((())((((((((())(()((()((((((((((()()((()((()()))(((()())()())()(((()())()()(()(()(((((((())()))(())()))())()()((())()((()((((()((()((())(((((()((((((()(())))(()))())(((()))((()()(()(((()))((((())()(((()))))()(()(())()(((((())(()(()(())(())()((()()()((((()(())((()())(()(()))(()(()(()()(())()()(()((())()((()))))()))((()(()()()()((()())(()))())()(()(((((((((())())((()((()((((((())()((((())(((())((()(()()()((())(()((())(((()((((()()((()(()(((((())()))()((((((()))((())(((()()))(((())(())()))(((((((())(())())()(())(((((()))()((()))()(()()((()()()()()())((((((("

func main() {
	var floor int64 = 0

	for _, c := range input {
		switch {
		case strings.ContainsRune("(", c):
			floor++
		case strings.ContainsRune(")", c):
			floor--
		}
	}
	fmt.Printf("Santa is on floor %d\n", floor)
}
<commit_msg>Determine when Santa is in the basement<commit_after>/*
   Copyright 2015 Tom Cameron

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

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

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

package main

import (
	"fmt"
	"strings"
)

const input string = "()()(()()()(()()((()((()))((()((((()()((((()))()((((())(((((((()(((((((((()(((())(()()(()((()()(()(())(()((((()((()()()((((())((((((()(()(((()())(()((((()))())(())(()(()()))))))))((((((((((((()())()())())(())))(((()()()((((()(((()(()(()()(()(()()(()(((((((())(())(())())))((()())()((((()()((()))(((()()()())))(())))((((())(((()())(())(()))(()((((()())))())((()(())(((()((((()((()(())())))((()))()()(()(()))))((((((((()())((((()()((((()(()())(((((()(()())()))())(((()))()(()(()(()((((()(())(()))(((((()()(()()()(()(((())())(((()()(()()))(((()()(((())())(()(())())()()(())()()()((()(((()(())((()()((())()))((()()))((()()())((((()(()()(()(((()))()(()))))((()(((()()()))(()(((())()(()((()())(()(()()(()())(())()(((()(()())()((((()((()))))())()))((()()()()(())()())()()()((((()))))(()(((()()(((((((())()))()((((()((())()(()())(())()))(()(()())(((((((())))(((()))())))))()))())((())(()()((())()())()))))()((()()())(())((())((((()())())()()()(((()))())))()()))())(()()()(()((((((()()))())()))()(((()(((())((((()()()(()))())()()))))())()))())((())()())(((((())())((())())))(((())(((())(((((()(((((())(()(()())())(()(())(()))(()((((()))())()))))())))((()(()))))())))(((((())()))())()))))()))))(((()))()))))((()))((()((()(()(())()())))(()()()(())()))()((((())))))))(())(()((()()))(()))(()))(()((()))))))()()((((()()))()())()))))))()()()))(()((())(()))((()()()())()(((()((((())())))()((((()(()))))))())))()()())()))(()))))(()())()))))))((())))))))())()))()((())())))(()((()))()))(())))))(()))()())()()))((()(()))()()()()))))())()()))())(())()()))()))((()))))()()(()())))))()()()))((((()))()))))(()(())))(()())))((())())(()))()))))()())))()())()())))))))))()()))))())))((())((()))))())))(((()())))))))(()))()()))(()))()))))()())))))())((((()())))))))())))()()))))))))()))()))))()))))))(())))))))))())))))))))))))))())())((())))))))))()))((())))()))))))))())()(()))))))())))))()()()())()(()()()(()())(()))()()()(()())))())())))()))))())))))))()()()()())(())())()())()))))(()()()()()))))()))())())))((()())()())))()))()))))(()())))()))))))))(((()))()()))))))))))))))))))))(()))(()((()))())))())(()))(()(()(())))))()(()))()))()()))))))))))))()((()())(())())()(())))))())()())((()()))))(()()))))())()(())()))))))))))))))))))))()))(()(()())))))))()()((()))()))))))((())))()))))))))((()))())()()))())()()))((()))())))))))))))(()())()))(())((()(()()))(()())(())))()())(()(())()()))))()))()(()))))))(()))))))))))(()))())))))))))())))))())))(())))))()))))(())())))))))))()(()))))()())))())(()))()())))))))))))))())()()))))()))))))())))))()))))(())(()()()()((())()))())(()))((())()))())())(())(()()))))()))(())()()((())(())))(())))()))())))))))))()(((((())())))(())()))))(())))((()))()(((((((()))))()()))(())))))()(()))))(()()))()))())))))))(()())()))))))))())))(()))())()))(())()((())())()())())(()(()))))()))))))((()())(())()()(()())))()()))(())(())(()))())))()))(()))()()))((((()))))()))((()()()))))()))()))())))(()))()))))(())))()))())()(()))()())))())))))))())))())))()()))))))(()))())())))()))()()())())))))))))))))())))()))(()()))))())))())()(())))())))))))))))))))))()()())())))))()()()((()(()))()()(())()())()))()))))()()()))))))((()))))))))()(()(()((((((()()((()())))))))))))()))())))))((())())(()))())))())))))())()()())(())))())))()())())(())))))))()()(())))()))())))())())())()))))))))()))(()()()())())())))(())())))))))()()())()))))())))())()(())())))))))()())()))(()()(())())))()(()((()()((()()(((((())(()())()))(())()))(())))(())))))))()))()))((()))()))()))))))))()))))))))((()()())(()))(((()))(())))()))((())(((())))()())))())))))((())))))(())())((((((())())()(()))()(()((()())))((())()(()(()))))(())(()()())(())))())((()(((())())))(((()())())))())()(())())((((()()))))())((()))()()()()(())(((((((()()()((()))())(()())))(())())((((()()(()))))()((())))((())()))()(((()))())))()))((()(()))(())(()((((())((((()()(()()))(((())(()))))((((()(()))(())))))((()))(()))((()(((()(()))(()(()((()(())(()(()(()(()()((()))())(((())(()(()))))(()))()()))(())))(())()(((())(()))()((((()()))))())(()))))((())()((((()(((()))())())(((()))()())((())(())())(())()(())()(()()((((((()()))))()()(((()()))))()())()(((()(()))(()(()())(()(()))))(((((()(((())())))))(((((()((()()((())())((((((()(())(()()((()()()()()()()(()()))()(((()))()))(((((((())(((()((()())()((((())(((()(())))()((()(()()()((())((()())()))()))())))())((((((()))(()(()()()))(()((()(()(()))()((()(((()()()((())(((((())()(()))())())((()(())))(()(()())(())((())())())(((()()()(())))))())(()))))))()))))))())((()()()))((()((((((()))(((()((((()()()(((()))())()(()()(((()((()()()()())()()))()()()(()(())((()))))(()))())))))))()(()()(((((())()(()(((((()((()(()()())(()((((((((()((((((())()((((()()()((()((()((((((()))((())))))))())()))((()(()))()(()()(()((())((()()((((((((((((()())(()()()))((((()((((((())(()))())(()()((()()))()(((((((()((()()((((((()(((())))((())))((((((((()()(((((((())(((((()())(((())((())()((((()(((((((()(()(((()((((((()(((()(((((((((((()()((()()(()))((()()(((()(((())))((((())()(()(((())()(()(((())(((((((((((()))())))((((((())((()()((((()())())((((()()))((())(((((()(()()(()()()((())(()((()()((((()(((((()((()(()((((()())((((((()(((((()()(()(()((((())))(())(())(())((((()(()()((((()((((()()((()((((((())))(((((()))))()))(()((((((((()(((())())(((())))(()(()((())(((()((()()(((((()((()()(((())()(()))(((((((())(()(((((()))((()((()((()))(())())((((()((((())()(()))(((()(((((((((((((((())(((((((((()))(((()(()()()()((((((()((())()((((((((()(())(((((((((((()(()((())()((()()(()(()()((((()()((())(()((()()(()()((((()(((((((())))((((())(())()(((()()((()()((((()((()(((()((())(((()()()((((()((((()()(()(()((((((((())(()(((((())(()())(((((((()())()(()((((()((())(()()())((((()()(((()((((())(())(()()(((((((((()()))()(((())(()(()((((((())(()()())(()))()()(((()(((()((())(()(((((((()(()(()((()(((((()(()((()(()((((((()((((()()((((()(((()((())(()(()((()()((((()()(())()(())(((())(()((((((((()())(((((((((()(())()((((())))()))()()(((((()()((((((())(()()(((()(()(((((((()(()(((((((())(())((((()((()(())))((((()()())(()))((()())((((()(((((()(()(())(()(()()())(((((()(((((()((((()()((((((((()()))(()((((((())((((())()(()(((()()()(((()(()(())(())(((((()(())())((((())(())(()(((()(((((())((((())())((()(((((((()(((())(()(()))(((((((((()((()((()()(()((((())(((()((())((((())(()(((()(((()(()((((()(((())(()(((()(()()(()(()((()()(()())(())())((()(()(((()(((()(((()()(((((((((()(((((((((()()(((()(((()())((((()(()(((()()()((())((((((((((())(()(((()((((()())((((()((()))(((()()()(((((()(((((((())((()())(()((((())((((((((())(()((()((((((((((()()((()((()()))(((()())()())()(((()())()()(()(()(((((((())()))(())()))())()()((())()((()((((()((()((())(((((()((((((()(())))(()))())(((()))((()()(()(((()))((((())()(((()))))()(()(())()(((((())(()(()(())(())()((()()()((((()(())((()())(()(()))(()(()(()()(())()()(()((())()((()))))()))((()(()()()()((()())(()))())()(()(((((((((())())((()((()((((((())()((((())(((())((()(()()()((())(()((())(((()((((()()((()(()(((((())()))()((((((()))((())(((()()))(((())(())()))(((((((())(())())()(())(((((()))()((()))()(()()((()()()()()())((((((("

func main() {
	var floor int64 = 0
	var basement bool

	for i, c := range input {
		switch {
		case strings.ContainsRune("(", c):
			floor++
		case strings.ContainsRune(")", c):
			floor--
		}
		if floor == -1 && !basement {
			fmt.Printf("Santa is in the basement at instruction %d\n", i+1)
			basement = true
		}
	}
	fmt.Printf("Santa is on floor %d\n", floor)
}
<|endoftext|>


<commit_before>package water

import (
	"encoding/xml"
	"errors"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/meilihao/logx"
)

type H map[string]interface{}

func (ctx *Context) GetHeader(key string) string {
	return ctx.Request.Header.Get(key)
}

func (ctx *Context) SetHeader(key, value string) {
	ctx.Header().Set(key, value)
}

// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
func (ctx *Context) Protocol() string {
	switch s := ctx.GetHeader(HeaderXForwardedProto); s {
	case "http", "https":
		return s
	}

	if ctx.Request.TLS != nil {
		return "https"
	}

	return "http"
}

// 301
func (ctx *Context) MovedPermanently(uri string) {
	http.Redirect(ctx, ctx.Request, uri, http.StatusMovedPermanently)
}

// 302
func (ctx *Context) Found(uri string) {
	http.Redirect(ctx, ctx.Request, uri, http.StatusFound)
}

// 304
func (ctx *Context) NotModified() {
	ctx.Abort(http.StatusNotModified)
}

// 400
func (ctx *Context) BadRequest() {
	ctx.Abort(http.StatusBadRequest)
}

// 401
func (ctx *Context) Unauthorized() {
	ctx.Abort(http.StatusUnauthorized)
}

// 403
func (ctx *Context) Forbidden() {
	ctx.Abort(http.StatusForbidden)
}

// 404
func (ctx *Context) NotFound() {
	ctx.Abort(http.StatusNotFound)
}

// 500
func (ctx *Context) InternalServerError() {
	ctx.Abort(http.StatusInternalServerError)
}

func (ctx *Context) Abort(code int) {
	ctx.WriteHeader(code)
}

// http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers
func (ctx *Context) NoCache() {
	ctx.Header().Set(HeaderCacheControl, "no-cache, max-age=0, s-max-age=0, must-revalidate") // HTTP 1.1
	ctx.Header().Set("Expires", "0")                                                          // Proxies.
}

func (ctx *Context) UserAgent() string {
	return ctx.Request.Header.Get(HeaderUserAgent)
}

// IsAjax returns boolean of this request is generated by ajax.
func (ctx *Context) IsAjax() bool {
	return ctx.Request.Header.Get(HeaderXRequestedWith) == MIMEXMLHttpRequest
}

func (ctx *Context) IsWebsocket() bool {
	if strings.Contains(strings.ToLower(ctx.Request.Header.Get("Connection")), "upgrade") &&
		strings.ToLower(ctx.Request.Header.Get("Upgrade")) == "websocket" {
		return true
	}

	return false
}

// IP returns request client ip.
// if using proxy, return first proxy ip.
func (ctx *Context) RealIp() string {
	return requestRealIp(ctx.Request)
}

// Proxy returns slice of proxy client ips.
func (ctx *Context) Proxy() []string {
	return requestProxy(ctx.Request)
}

// ContentType returns the Content-Type header of the request.
func (ctx *Context) ContentType() string {
	return filterFlags(ctx.Request.Header.Get("Content-Type"))
}

// BodyString returns content of request body in string.
func (ctx *Context) BodyString() (string, error) {
	data, err := ctx.BodyBytes()
	return string(data), err
}

// BodyBytes returns content of request body in bytes.
func (ctx *Context) BodyBytes() ([]byte, error) {
	data, err := ioutil.ReadAll(ctx.Request.Body)
	if err != nil {
		return nil, err
	}
	ctx.Request.Body.Close()
	return data, err
}

func (ctx *Context) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
	return ctx.Request.FormFile(key)
}

func (ctx *Context) SaveToFile(fileName, savePath string) error {
	file, _, err := ctx.Request.FormFile(fileName)
	if err != nil {
		return err
	}
	defer file.Close()

	f, err := os.OpenFile(savePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = io.Copy(f, file)
	return err
}

func (ctx *Context) ServeFile(filePath string) {
	http.ServeFile(ctx, ctx.Request, filePath)
}

func (ctx *Context) Download(fpath string, inline ...bool) error {
	f, err := os.Open(fpath)
	if err != nil {
		return err
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return err
	}

	if fi.IsDir() {
		return errors.New("This is Dir.")
	}

	dispositionType := "attachment"
	if len(inline) > 0 && inline[0] {
		dispositionType = "inline"
	}

	ctx.Header().Set(HeaderContentDisposition, contentDisposition(fi.Name(), dispositionType))
	http.ServeContent(ctx, ctx.Request, fi.Name(), fi.ModTime(), f)

	return nil
}

func (ctx *Context) Attachment(name string, modtime time.Time, content io.ReadSeeker, inline ...bool) {
	dispositionType := "attachment"
	if len(inline) > 0 && inline[0] {
		dispositionType = "inline"
	}

	ctx.Header().Set(HeaderContentDisposition, contentDisposition(name, dispositionType))
	http.ServeContent(ctx, ctx.Request, name, modtime, content)
}

func (ctx *Context) Stream(contentType string, r io.Reader) error {
	ctx.Header().Set(HeaderContentType, contentType)

	_, err := io.Copy(ctx, r)

	return err
}

func (ctx *Context) String(code int, str string) {
	ctx.WriteHeader(code)
	ctx.Header().Set(HeaderContentType, MIMETextPlainCharsetUTF8)
	ctx.Write([]byte(str))
}

func (ctx *Context) HTML(code int, str string) {
	ctx.WriteHeader(code)
	ctx.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	ctx.Write([]byte(str))
}

func (ctx *Context) JSON(code int, v interface{}) error {
	ctx.WriteHeader(code)
	ctx.Header().Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8)
	err := json.NewEncoder(ctx).Encode(v)
	if err != nil {
		logx.Warn(err)
	}
	return err
}

func (ctx *Context) XML(code int, v interface{}) error {
	ctx.WriteHeader(code)
	ctx.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
	err := xml.NewEncoder(ctx).Encode(v)
	if err != nil {
		logx.Warn(err)
	}
	return err
}

func (ctx *Context) DecodeJson(v interface{}) error {
	defer ctx.Request.Body.Close()

	return json.NewDecoder(ctx.Request.Body).Decode(v)
}

func (ctx *Context) DecodeXml(v interface{}) error {
	defer ctx.Request.Body.Close()

	return xml.NewDecoder(ctx.Request.Body).Decode(v)
}

// HandlerName returns the last handler's name.
// For example if the handler is "_Users()", this function will return "main._Users".
func (ctx *Context) HandlerName() string {
	return nameOfFunction(ctx.handlers[ctx.handlersLength-1])
}

// `DefaultNotFoundHandler.FilterPath=func(c){return "/index.html"}`用于spa时可能会无限重定向, 原因是http.FileServer对路径"/index.html"有特别处理
type DefaultNotFoundHandler struct {
	FileServer http.Handler
	FilterPath func(string) string
}

func NewDefaultNotFoundHandler(root string) *DefaultNotFoundHandler {
	return &DefaultNotFoundHandler{
		FileServer: http.FileServer(http.Dir(root)),
	}
}

func (h *DefaultNotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h.FilterPath != nil {
		r.URL.Path = h.FilterPath(r.URL.Path)
	}
	fmt.Println(r.URL.Path)
	h.FileServer.ServeHTTP(w, r)
}

type SPANotFoundHandler struct {
	Index string
}

func NewSPANotFoundHandler(index string) *SPANotFoundHandler {
	return &SPANotFoundHandler{
		Index: index,
	}
}

func (h *SPANotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, h.Index)
}
<commit_msg>+ ctx.File<commit_after>package water

import (
	"encoding/xml"
	"errors"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/meilihao/logx"
)

type H map[string]interface{}

func (ctx *Context) GetHeader(key string) string {
	return ctx.Request.Header.Get(key)
}

func (ctx *Context) SetHeader(key, value string) {
	ctx.Header().Set(key, value)
}

// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
func (ctx *Context) Protocol() string {
	switch s := ctx.GetHeader(HeaderXForwardedProto); s {
	case "http", "https":
		return s
	}

	if ctx.Request.TLS != nil {
		return "https"
	}

	return "http"
}

// 301
func (ctx *Context) MovedPermanently(uri string) {
	http.Redirect(ctx, ctx.Request, uri, http.StatusMovedPermanently)
}

// 302
func (ctx *Context) Found(uri string) {
	http.Redirect(ctx, ctx.Request, uri, http.StatusFound)
}

// 304
func (ctx *Context) NotModified() {
	ctx.Abort(http.StatusNotModified)
}

// 400
func (ctx *Context) BadRequest() {
	ctx.Abort(http.StatusBadRequest)
}

// 401
func (ctx *Context) Unauthorized() {
	ctx.Abort(http.StatusUnauthorized)
}

// 403
func (ctx *Context) Forbidden() {
	ctx.Abort(http.StatusForbidden)
}

// 404
func (ctx *Context) NotFound() {
	ctx.Abort(http.StatusNotFound)
}

// 500
func (ctx *Context) InternalServerError() {
	ctx.Abort(http.StatusInternalServerError)
}

func (ctx *Context) Abort(code int) {
	ctx.WriteHeader(code)
}

// http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers
func (ctx *Context) NoCache() {
	ctx.Header().Set(HeaderCacheControl, "no-cache, max-age=0, s-max-age=0, must-revalidate") // HTTP 1.1
	ctx.Header().Set("Expires", "0")                                                          // Proxies.
}

func (ctx *Context) UserAgent() string {
	return ctx.Request.Header.Get(HeaderUserAgent)
}

// IsAjax returns boolean of this request is generated by ajax.
func (ctx *Context) IsAjax() bool {
	return ctx.Request.Header.Get(HeaderXRequestedWith) == MIMEXMLHttpRequest
}

func (ctx *Context) IsWebsocket() bool {
	if strings.Contains(strings.ToLower(ctx.Request.Header.Get("Connection")), "upgrade") &&
		strings.ToLower(ctx.Request.Header.Get("Upgrade")) == "websocket" {
		return true
	}

	return false
}

// IP returns request client ip.
// if using proxy, return first proxy ip.
func (ctx *Context) RealIp() string {
	return requestRealIp(ctx.Request)
}

// Proxy returns slice of proxy client ips.
func (ctx *Context) Proxy() []string {
	return requestProxy(ctx.Request)
}

// ContentType returns the Content-Type header of the request.
func (ctx *Context) ContentType() string {
	return filterFlags(ctx.Request.Header.Get("Content-Type"))
}

// BodyString returns content of request body in string.
func (ctx *Context) BodyString() (string, error) {
	data, err := ctx.BodyBytes()
	return string(data), err
}

// BodyBytes returns content of request body in bytes.
func (ctx *Context) BodyBytes() ([]byte, error) {
	data, err := ioutil.ReadAll(ctx.Request.Body)
	if err != nil {
		return nil, err
	}
	ctx.Request.Body.Close()
	return data, err
}

// File writes the specified file into the body stream.
func (ctx *Context) File(filepath string) {
	http.ServeFile(ctx.ResponseWriter, ctx.Request, filepath)
}

func (ctx *Context) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
	return ctx.Request.FormFile(key)
}

func (ctx *Context) SaveToFile(fileName, savePath string) error {
	file, _, err := ctx.Request.FormFile(fileName)
	if err != nil {
		return err
	}
	defer file.Close()

	f, err := os.OpenFile(savePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer f.Close()

	_, err = io.Copy(f, file)
	return err
}

func (ctx *Context) ServeFile(filePath string) {
	http.ServeFile(ctx, ctx.Request, filePath)
}

func (ctx *Context) Download(fpath string, inline ...bool) error {
	f, err := os.Open(fpath)
	if err != nil {
		return err
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return err
	}

	if fi.IsDir() {
		return errors.New("This is Dir.")
	}

	dispositionType := "attachment"
	if len(inline) > 0 && inline[0] {
		dispositionType = "inline"
	}

	ctx.Header().Set(HeaderContentDisposition, contentDisposition(fi.Name(), dispositionType))
	http.ServeContent(ctx, ctx.Request, fi.Name(), fi.ModTime(), f)

	return nil
}

func (ctx *Context) Attachment(name string, modtime time.Time, content io.ReadSeeker, inline ...bool) {
	dispositionType := "attachment"
	if len(inline) > 0 && inline[0] {
		dispositionType = "inline"
	}

	ctx.Header().Set(HeaderContentDisposition, contentDisposition(name, dispositionType))
	http.ServeContent(ctx, ctx.Request, name, modtime, content)
}

func (ctx *Context) Stream(contentType string, r io.Reader) error {
	ctx.Header().Set(HeaderContentType, contentType)

	_, err := io.Copy(ctx, r)

	return err
}

func (ctx *Context) String(code int, str string) {
	ctx.WriteHeader(code)
	ctx.Header().Set(HeaderContentType, MIMETextPlainCharsetUTF8)
	ctx.Write([]byte(str))
}

func (ctx *Context) HTML(code int, str string) {
	ctx.WriteHeader(code)
	ctx.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	ctx.Write([]byte(str))
}

func (ctx *Context) JSON(code int, v interface{}) error {
	ctx.WriteHeader(code)
	ctx.Header().Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8)
	err := json.NewEncoder(ctx).Encode(v)
	if err != nil {
		logx.Warn(err)
	}
	return err
}

func (ctx *Context) XML(code int, v interface{}) error {
	ctx.WriteHeader(code)
	ctx.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
	err := xml.NewEncoder(ctx).Encode(v)
	if err != nil {
		logx.Warn(err)
	}
	return err
}

func (ctx *Context) DecodeJson(v interface{}) error {
	defer ctx.Request.Body.Close()

	return json.NewDecoder(ctx.Request.Body).Decode(v)
}

func (ctx *Context) DecodeXml(v interface{}) error {
	defer ctx.Request.Body.Close()

	return xml.NewDecoder(ctx.Request.Body).Decode(v)
}

// HandlerName returns the last handler's name.
// For example if the handler is "_Users()", this function will return "main._Users".
func (ctx *Context) HandlerName() string {
	return nameOfFunction(ctx.handlers[ctx.handlersLength-1])
}

// `DefaultNotFoundHandler.FilterPath=func(c){return "/index.html"}`用于spa时可能会无限重定向, 原因是http.FileServer对路径"/index.html"有特别处理
type DefaultNotFoundHandler struct {
	FileServer http.Handler
	FilterPath func(string) string
}

func NewDefaultNotFoundHandler(root string) *DefaultNotFoundHandler {
	return &DefaultNotFoundHandler{
		FileServer: http.FileServer(http.Dir(root)),
	}
}

func (h *DefaultNotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h.FilterPath != nil {
		r.URL.Path = h.FilterPath(r.URL.Path)
	}
	fmt.Println(r.URL.Path)
	h.FileServer.ServeHTTP(w, r)
}

type SPANotFoundHandler struct {
	Index string
}

func NewSPANotFoundHandler(index string) *SPANotFoundHandler {
	return &SPANotFoundHandler{
		Index: index,
	}
}

func (h *SPANotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, h.Index)
}
<|endoftext|>


<commit_before>package main

const(
INDEX_PAGE_CONTENT = `

	<title>RequestHub</title>

RequestHub

<form method="POST">
	<input type="text" name="hub_name" />
	<input type="submit" value="Create Hub"/>
</form>

My Hubs:

`

HUB_PAGE_CONTENT = `

	<title>RequestHub - {{.Id}}</title>

RequestHub

{{.Id}}

Clear

`
)
<commit_msg>Tweaks to page content<commit_after>package main

const(
INDEX_PAGE_CONTENT = `

	<title>RequestHub</title>

RequestHub

<form method="POST">
	<input type="text" name="hub_name" />
	<input type="submit" value="Create Hub"/>
</form>

My Hubs:

`

HUB_PAGE_CONTENT = `

	<title>RequestHub - {{.Id}}</title>

RequestHub

{{.Id}}

Clear

`
)
<|endoftext|>


<commit_before>package gokeepasslib

import (
	"bytes"
	"encoding/binary"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
)

const (
	InnerHeaderTerminator byte = 0x00 // InnerHeader terminator byte
	InnerHeaderIRSID           = 0x01 // InnerHeader InnerRandomStreamID byte
	InnerHeaderIRSKey          = 0x02 // InnerHeader InnerRandomStreamKey byte
	InnerHeaderBinary          = 0x03 // InnerHeader binary byte
)

// DBContent is a container for all elements of a keepass database
type DBContent struct {
	RawData     []byte       `xml:"-"` // Encrypted data
	InnerHeader *InnerHeader `xml:"-"`
	XMLName     xml.Name     `xml:"KeePassFile"`
	Meta        *MetaData    `xml:"Meta"`
	Root        *RootData    `xml:"Root"`
}

// InnerHeader is the container of crypt options and binaries, only for Kdbx v4
type InnerHeader struct {
	InnerRandomStreamID  uint32
	InnerRandomStreamKey []byte
	Binaries             Binaries
}

// NewContent creates a new database content with some good defaults
func NewContent() *DBContent {
	// Not necessary create InnerHeader because this will be a KDBX v3.1
	return &DBContent{
		Meta: NewMetaData(),
		Root: NewRootData(),
	}
}

// readFrom reads the InnerHeader from an io.Reader
func (ih *InnerHeader) readFrom(r io.Reader) error {
	binaryCount := 0 // Var used to count and index every binary
	for {
		var typ byte
		var length int32
		var data []byte

		if err := binary.Read(r, binary.LittleEndian, &typ); err != nil {
			return err
		}
		if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
			return err
		}
		data = make([]byte, length)
		if err := binary.Read(r, binary.LittleEndian, &data); err != nil {
			return err
		}

		if typ == InnerHeaderTerminator {
			// End of inner header
			break
		} else if typ == InnerHeaderIRSID {
			// Found InnerRandomStream ID
			ih.InnerRandomStreamID = binary.LittleEndian.Uint32(data)
		} else if typ == InnerHeaderIRSKey {
			// Found InnerRandomStream Key
			ih.InnerRandomStreamKey = data
		} else if typ == InnerHeaderBinary {
			// Found a binary
			var protection byte
			reader := bytes.NewReader(data)

			binary.Read(reader, binary.LittleEndian, &protection) // Read memory protection flag
			content, _ := ioutil.ReadAll(reader)                  // Read content

			ih.Binaries = append(ih.Binaries, Binary{
				ID:               binaryCount,
				MemoryProtection: protection,
				Content:          content,
			})

			binaryCount = binaryCount + 1
		} else {
			return ErrUnknownInnerHeaderID(typ)
		}
	}
	return nil
}

// writeTo the InnerHeader to the given io.Writer
func (ih *InnerHeader) writeTo(w io.Writer) error {
	// InnerRandomStreamID
	if ih.InnerRandomStreamID != 0 {
		if err := binary.Write(w, binary.LittleEndian, uint8(InnerHeaderIRSID)); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, uint32(4)); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, ih.InnerRandomStreamID); err != nil {
			return err
		}
	}
	// InnerRandomStreamKey
	if len(ih.InnerRandomStreamKey) > 0 {
		if err := binary.Write(w, binary.LittleEndian, uint8(InnerHeaderIRSKey)); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, uint32(len(ih.InnerRandomStreamKey))); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, ih.InnerRandomStreamKey); err != nil {
			return err
		}
	}
	// Binaries
	for _, item := range ih.Binaries {
		if err := binary.Write(w, binary.LittleEndian, uint8(InnerHeaderBinary)); err != nil {
			return err
		}
		// +1 byte for protection flag
		if err := binary.Write(w, binary.LittleEndian, uint32(len(item.Content)+1)); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, item.MemoryProtection); err != nil {

		}
		if err := binary.Write(w, binary.LittleEndian, item.Content); err != nil {
			return err
		}
	}
	// End inner header
	if err := binary.Write(w, binary.LittleEndian, uint8(InnerHeaderTerminator)); err != nil {
		return err
	}
	if err := binary.Write(w, binary.LittleEndian, uint32(0)); err != nil {
		return err
	}
	return nil
}

func (ih InnerHeader) String() string {
	return fmt.Sprintf(
		"1) InnerRandomStreamID: %d\n"+
			"2) InnerRandomStreamKey: %x\n"+
			"3) Binaries: %s\n",
		ih.InnerRandomStreamID,
		ih.InnerRandomStreamKey,
		ih.Binaries,
	)
}

// Error for end of inner header
var ErrEndOfInnerHeaders = errors.New("gokeepasslib: inner header id was 0, end of inner headers")

// Error for unknown inner header id
type ErrUnknownInnerHeaderID byte

func (i ErrUnknownInnerHeaderID) Error() string {
	return fmt.Sprintf("gokeepasslib: unknown inner header ID of %x", i)
}
<commit_msg>Improved inner header write<commit_after>package gokeepasslib

import (
	"bytes"
	"encoding/binary"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
)

const (
	InnerHeaderTerminator byte = 0x00 // InnerHeader terminator byte
	InnerHeaderIRSID           = 0x01 // InnerHeader InnerRandomStreamID byte
	InnerHeaderIRSKey          = 0x02 // InnerHeader InnerRandomStreamKey byte
	InnerHeaderBinary          = 0x03 // InnerHeader binary byte
)

// DBContent is a container for all elements of a keepass database
type DBContent struct {
	RawData     []byte       `xml:"-"` // Encrypted data
	InnerHeader *InnerHeader `xml:"-"`
	XMLName     xml.Name     `xml:"KeePassFile"`
	Meta        *MetaData    `xml:"Meta"`
	Root        *RootData    `xml:"Root"`
}

// InnerHeader is the container of crypt options and binaries, only for Kdbx v4
type InnerHeader struct {
	InnerRandomStreamID  uint32
	InnerRandomStreamKey []byte
	Binaries             Binaries
}

// NewContent creates a new database content with some good defaults
func NewContent() *DBContent {
	// Not necessary create InnerHeader because this will be a KDBX v3.1
	return &DBContent{
		Meta: NewMetaData(),
		Root: NewRootData(),
	}
}

// readFrom reads the InnerHeader from an io.Reader
func (ih *InnerHeader) readFrom(r io.Reader) error {
	binaryCount := 0 // Var used to count and index every binary
	for {
		var typ byte
		var length int32
		var data []byte

		if err := binary.Read(r, binary.LittleEndian, &typ); err != nil {
			return err
		}
		if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
			return err
		}
		data = make([]byte, length)
		if err := binary.Read(r, binary.LittleEndian, &data); err != nil {
			return err
		}

		if typ == InnerHeaderTerminator {
			// End of inner header
			break
		} else if typ == InnerHeaderIRSID {
			// Found InnerRandomStream ID
			ih.InnerRandomStreamID = binary.LittleEndian.Uint32(data)
		} else if typ == InnerHeaderIRSKey {
			// Found InnerRandomStream Key
			ih.InnerRandomStreamKey = data
		} else if typ == InnerHeaderBinary {
			// Found a binary
			var protection byte
			reader := bytes.NewReader(data)

			binary.Read(reader, binary.LittleEndian, &protection) // Read memory protection flag
			content, _ := ioutil.ReadAll(reader)                  // Read content

			ih.Binaries = append(ih.Binaries, Binary{
				ID:               binaryCount,
				MemoryProtection: protection,
				Content:          content,
			})

			binaryCount = binaryCount + 1
		} else {
			return ErrUnknownInnerHeaderID(typ)
		}
	}
	return nil
}

// writeTo the InnerHeader to the given io.Writer
func (ih *InnerHeader) writeTo(w io.Writer) error {
	irsID := make([]byte, 4)
	binary.LittleEndian.PutUint32(irsID, ih.InnerRandomStreamID)

	if err := writeToInnerHeader(w, InnerHeaderIRSID, irsID); err != nil {
		return err
	}
	if err := writeToInnerHeader(w, InnerHeaderIRSKey, ih.InnerRandomStreamKey); err != nil {
		return err
	}

	for _, item := range ih.Binaries {
		buf := []byte{item.MemoryProtection}
		buf = append(buf, item.Content...)
		if err := writeToInnerHeader(w, InnerHeaderBinary, buf); err != nil {
			return err
		}
	}
	// End inner header
	if err := binary.Write(w, binary.LittleEndian, uint8(InnerHeaderTerminator)); err != nil {
		return err
	}
	if err := binary.Write(w, binary.LittleEndian, uint32(0)); err != nil {
		return err
	}
	return nil
}

// writeToInnerHeader is an helper to write an inner header item to the given io.Writer
func writeToInnerHeader(w io.Writer, id uint8, data []byte) error {
	if len(data) > 0 {
		if err := binary.Write(w, binary.LittleEndian, id); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, uint32(len(data))); err != nil {
			return err
		}
		if err := binary.Write(w, binary.LittleEndian, data); err != nil {
			return err
		}
	}
	return nil
}

func (ih InnerHeader) String() string {
	return fmt.Sprintf(
		"1) InnerRandomStreamID: %d\n"+
			"2) InnerRandomStreamKey: %x\n"+
			"3) Binaries: %s\n",
		ih.InnerRandomStreamID,
		ih.InnerRandomStreamKey,
		ih.Binaries,
	)
}

// Error for end of inner header
var ErrEndOfInnerHeaders = errors.New("gokeepasslib: inner header id was 0, end of inner headers")

// Error for unknown inner header id
type ErrUnknownInnerHeaderID byte

func (i ErrUnknownInnerHeaderID) Error() string {
	return fmt.Sprintf("gokeepasslib: unknown inner header ID of %x", i)
}
<|endoftext|>


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

package macaron

import (
	"crypto/md5"
	"encoding/hex"
	"html/template"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"path"
	"path/filepath"
	"reflect"
	"strings"
	"time"

	"github.com/Unknwon/com"

	"github.com/Unknwon/macaron/inject"
)

// Locale reprents a localization interface.
type Locale interface {
	Language() string
	Tr(string, ...interface{}) string
}

// RequestBody represents a request body.
type RequestBody struct {
	reader io.ReadCloser
}

// Bytes reads and returns content of request body in bytes.
func (rb *RequestBody) Bytes() ([]byte, error) {
	return ioutil.ReadAll(rb.reader)
}

// String reads and returns content of request body in string.
func (rb *RequestBody) String() (string, error) {
	data, err := rb.Bytes()
	return string(data), err
}

// ReadCloser returns a ReadCloser for request body.
func (rb *RequestBody) ReadCloser() io.ReadCloser {
	return rb.reader
}

// Request represents an HTTP request received by a server or to be sent by a client.
type Request struct {
	*http.Request
}

func (r *Request) Body() *RequestBody {
	return &RequestBody{r.Request.Body}
}

// Context represents the runtime context of current request of Macaron instance.
// It is the integration of most frequently used middlewares and helper methods.
type Context struct {
	inject.Injector
	handlers []Handler
	action   Handler
	index    int

	*Router
	Req    Request
	Resp   ResponseWriter
	params Params
	Render // Not nil only if you use macaran.Render middleware.
	Locale
	Data map[string]interface{}
}

func (c *Context) handler() Handler {
	if c.index < len(c.handlers) {
		return c.handlers[c.index]
	}
	if c.index == len(c.handlers) {
		return c.action
	}
	panic("invalid index for context handler")
}

func (c *Context) Next() {
	c.index += 1
	c.run()
}

func (c *Context) Written() bool {
	return c.Resp.Written()
}

func (c *Context) run() {
	for c.index <= len(c.handlers) {
		vals, err := c.Invoke(c.handler())
		if err != nil {
			panic(err)
		}
		c.index += 1

		// if the handler returned something, write it to the http response
		if len(vals) > 0 {
			ev := c.GetVal(reflect.TypeOf(ReturnHandler(nil)))
			handleReturn := ev.Interface().(ReturnHandler)
			handleReturn(c, vals)
		}

		if c.Written() {
			return
		}
	}
}

// RemoteAddr returns more real IP address.
func (ctx *Context) RemoteAddr() string {
	addr := ctx.Req.Header.Get("X-Real-IP")
	if len(addr) == 0 {
		addr = ctx.Req.Header.Get("X-Forwarded-For")
		if addr == "" {
			addr = ctx.Req.RemoteAddr
			if i := strings.LastIndex(addr, ":"); i > -1 {
				addr = addr[:i]
			}
		}
	}
	return addr
}

func (ctx *Context) renderHTML(status int, setName, tplName string, data ...interface{}) {
	if ctx.Render == nil {
		panic("renderer middleware hasn't been registered")
	}
	if len(data) == 0 {
		ctx.Render.HTMLSet(status, setName, tplName, ctx.Data)
	} else {
		ctx.Render.HTMLSet(status, setName, tplName, data[0])
		if len(data) > 1 {
			ctx.Render.HTMLSet(status, setName, tplName, data[0], data[1].(HTMLOptions))
		}
	}
}

// HTML calls Render.HTML but allows less arguments.
func (ctx *Context) HTML(status int, name string, data ...interface{}) {
	ctx.renderHTML(status, _DEFAULT_TPL_SET_NAME, name, data...)
}

// HTML calls Render.HTMLSet but allows less arguments.
func (ctx *Context) HTMLSet(status int, setName, tplName string, data ...interface{}) {
	ctx.renderHTML(status, setName, tplName, data...)
}

func (ctx *Context) Redirect(location string, status ...int) {
	code := http.StatusFound
	if len(status) == 1 {
		code = status[0]
	}

	http.Redirect(ctx.Resp, ctx.Req.Request, location, code)
}

// Query querys form parameter.
func (ctx *Context) Query(name string) string {
	if ctx.Req.Form == nil {
		ctx.Req.ParseForm()
	}
	return ctx.Req.Form.Get(name)
}

// QueryStrings returns a list of results by given query name.
func (ctx *Context) QueryStrings(name string) []string {
	if ctx.Req.Form == nil {
		ctx.Req.ParseForm()
	}

	vals, ok := ctx.Req.Form[name]
	if !ok {
		return []string{}
	}
	return vals
}

// QueryEscape returns escapred query result.
func (ctx *Context) QueryEscape(name string) string {
	return template.HTMLEscapeString(ctx.Query(name))
}

// QueryInt returns query result in int type.
func (ctx *Context) QueryInt(name string) int {
	return com.StrTo(ctx.Query(name)).MustInt()
}

// QueryInt64 returns query result in int64 type.
func (ctx *Context) QueryInt64(name string) int64 {
	return com.StrTo(ctx.Query(name)).MustInt64()
}

// Params returns value of given param name.
// e.g. ctx.Params(":uid")
func (ctx *Context) Params(name string) string {
	return ctx.params[name]
}

// SetParams sets value of param with given name.
func (ctx *Context) SetParams(name, val string) {
	ctx.params[name] = val
}

// ParamsEscape returns escapred params result.
// e.g. ctx.ParamsEscape(":uname")
func (ctx *Context) ParamsEscape(name string) string {
	return template.HTMLEscapeString(ctx.Params(name))
}

// ParamsInt returns params result in int type.
// e.g. ctx.ParamsInt(":uid")
func (ctx *Context) ParamsInt(name string) int {
	return com.StrTo(ctx.Params(name)).MustInt()
}

// ParamsInt64 returns params result in int64 type.
// e.g. ctx.ParamsInt64(":uid")
func (ctx *Context) ParamsInt64(name string) int64 {
	return com.StrTo(ctx.Params(name)).MustInt64()
}

// GetFile returns information about user upload file by given form field name.
func (ctx *Context) GetFile(name string) (multipart.File, *multipart.FileHeader, error) {
	return ctx.Req.FormFile(name)
}

// SetCookie sets given cookie value to response header.
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
	cookie := http.Cookie{}
	cookie.Name = name
	cookie.Value = url.QueryEscape(value)

	if len(others) > 0 {
		switch v := others[0].(type) {
		case int:
			cookie.MaxAge = v
		case int64:
			cookie.MaxAge = int(v)
		case int32:
			cookie.MaxAge = int(v)
		}
	}

	// default "/"
	if len(others) > 1 {
		if v, ok := others[1].(string); ok && len(v) > 0 {
			cookie.Path = v
		}
	} else {
		cookie.Path = "/"
	}

	// default empty
	if len(others) > 2 {
		if v, ok := others[2].(string); ok && len(v) > 0 {
			cookie.Domain = v
		}
	}

	// default empty
	if len(others) > 3 {
		switch v := others[3].(type) {
		case bool:
			cookie.Secure = v
		default:
			if others[3] != nil {
				cookie.Secure = true
			}
		}
	}

	// default false. for session cookie default true
	if len(others) > 4 {
		if v, ok := others[4].(bool); ok && v {
			cookie.HttpOnly = true
		}
	}

	ctx.Resp.Header().Add("Set-Cookie", cookie.String())
}

// GetCookie returns given cookie value from request header.
func (ctx *Context) GetCookie(name string) string {
	cookie, err := ctx.Req.Cookie(name)
	if err != nil {
		return ""
	}
	val, _ := url.QueryUnescape(cookie.Value)
	return val
}

// GetCookieInt returns cookie result in int type.
func (ctx *Context) GetCookieInt(name string) int {
	return com.StrTo(ctx.GetCookie(name)).MustInt()
}

// GetCookieInt64 returns cookie result in int64 type.
func (ctx *Context) GetCookieInt64(name string) int64 {
	return com.StrTo(ctx.GetCookie(name)).MustInt64()
}

var defaultCookieSecret string

// SetDefaultCookieSecret sets global default secure cookie secret.
func (m *Macaron) SetDefaultCookieSecret(secret string) {
	defaultCookieSecret = secret
}

// SetSecureCookie sets given cookie value to response header with default secret string.
func (ctx *Context) SetSecureCookie(name, value string, others ...interface{}) {
	ctx.SetSuperSecureCookie(defaultCookieSecret, name, value, others...)
}

// GetSecureCookie returns given cookie value from request header with default secret string.
func (ctx *Context) GetSecureCookie(key string) (string, bool) {
	return ctx.GetSuperSecureCookie(defaultCookieSecret, key)
}

// SetSuperSecureCookie sets given cookie value to response header with secret string.
func (ctx *Context) SetSuperSecureCookie(secret, name, value string, others ...interface{}) {
	m := md5.Sum([]byte(secret))
	secret = hex.EncodeToString(m[:])
	text, err := com.AESEncrypt([]byte(secret), []byte(value))
	if err != nil {
		panic("error encrypting cookie: " + err.Error())
	}
	ctx.SetCookie(name, hex.EncodeToString(text), others...)
}

// GetSuperSecureCookie returns given cookie value from request header with secret string.
func (ctx *Context) GetSuperSecureCookie(secret, key string) (string, bool) {
	val := ctx.GetCookie(key)
	if val == "" {
		return "", false
	}

	data, err := hex.DecodeString(val)
	if err != nil {
		return "", false
	}

	m := md5.Sum([]byte(secret))
	secret = hex.EncodeToString(m[:])
	text, err := com.AESDecrypt([]byte(secret), data)
	return string(text), err == nil
}

// ServeContent serves given content to response.
func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
	modtime := time.Now()
	for _, p := range params {
		switch v := p.(type) {
		case time.Time:
			modtime = v
		}
	}
	ctx.Resp.Header().Set("Content-Description", "Raw content")
	ctx.Resp.Header().Set("Content-Type", "text/plain")
	ctx.Resp.Header().Set("Expires", "0")
	ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
	ctx.Resp.Header().Set("Pragma", "public")
	http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r)
}

// ServeFile serves given file to response.
func (ctx *Context) ServeFile(file string, names ...string) {
	var name string
	if len(names) > 0 {
		name = names[0]
	} else {
		name = path.Base(file)
	}
	ctx.Resp.Header().Set("Content-Description", "File Transfer")
	ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
	ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
	ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
	ctx.Resp.Header().Set("Expires", "0")
	ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
	ctx.Resp.Header().Set("Pragma", "public")
	http.ServeFile(ctx.Resp, ctx.Req.Request, file)
}

// ChangeStaticPath changes static path from old to new one.
func (ctx *Context) ChangeStaticPath(oldPath, newPath string) {
	if !filepath.IsAbs(oldPath) {
		oldPath = filepath.Join(Root, oldPath)
	}
	dir := statics.Get(oldPath)
	if dir != nil {
		statics.Delete(oldPath)

		if !filepath.IsAbs(newPath) {
			newPath = filepath.Join(Root, newPath)
		}
		*dir = http.Dir(newPath)
		statics.Set(dir)
	}
}
<commit_msg>Fix duplicate rendering<commit_after>// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
	"crypto/md5"
	"encoding/hex"
	"html/template"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"path"
	"path/filepath"
	"reflect"
	"strings"
	"time"

	"github.com/Unknwon/com"

	"github.com/Unknwon/macaron/inject"
)

// Locale reprents a localization interface.
type Locale interface {
	Language() string
	Tr(string, ...interface{}) string
}

// RequestBody represents a request body.
type RequestBody struct {
	reader io.ReadCloser
}

// Bytes reads and returns content of request body in bytes.
func (rb *RequestBody) Bytes() ([]byte, error) {
	return ioutil.ReadAll(rb.reader)
}

// String reads and returns content of request body in string.
func (rb *RequestBody) String() (string, error) {
	data, err := rb.Bytes()
	return string(data), err
}

// ReadCloser returns a ReadCloser for request body.
func (rb *RequestBody) ReadCloser() io.ReadCloser {
	return rb.reader
}

// Request represents an HTTP request received by a server or to be sent by a client.
type Request struct {
	*http.Request
}

func (r *Request) Body() *RequestBody {
	return &RequestBody{r.Request.Body}
}

// Context represents the runtime context of current request of Macaron instance.
// It is the integration of most frequently used middlewares and helper methods.
type Context struct {
	inject.Injector
	handlers []Handler
	action   Handler
	index    int

	*Router
	Req    Request
	Resp   ResponseWriter
	params Params
	Render // Not nil only if you use macaran.Render middleware.
	Locale
	Data map[string]interface{}
}

func (c *Context) handler() Handler {
	if c.index < len(c.handlers) {
		return c.handlers[c.index]
	}
	if c.index == len(c.handlers) {
		return c.action
	}
	panic("invalid index for context handler")
}

func (c *Context) Next() {
	c.index += 1
	c.run()
}

func (c *Context) Written() bool {
	return c.Resp.Written()
}

func (c *Context) run() {
	for c.index <= len(c.handlers) {
		vals, err := c.Invoke(c.handler())
		if err != nil {
			panic(err)
		}
		c.index += 1

		// if the handler returned something, write it to the http response
		if len(vals) > 0 {
			ev := c.GetVal(reflect.TypeOf(ReturnHandler(nil)))
			handleReturn := ev.Interface().(ReturnHandler)
			handleReturn(c, vals)
		}

		if c.Written() {
			return
		}
	}
}

// RemoteAddr returns more real IP address.
func (ctx *Context) RemoteAddr() string {
	addr := ctx.Req.Header.Get("X-Real-IP")
	if len(addr) == 0 {
		addr = ctx.Req.Header.Get("X-Forwarded-For")
		if addr == "" {
			addr = ctx.Req.RemoteAddr
			if i := strings.LastIndex(addr, ":"); i > -1 {
				addr = addr[:i]
			}
		}
	}
	return addr
}

func (ctx *Context) renderHTML(status int, setName, tplName string, data ...interface{}) {
	if ctx.Render == nil {
		panic("renderer middleware hasn't been registered")
	}
	if len(data) == 0 {
		ctx.Render.HTMLSet(status, setName, tplName, ctx.Data)
	} else {
		if len(data) == 1 {
			ctx.Render.HTMLSet(status, setName, tplName, data[0])
		}
		if len(data) > 1 {
			ctx.Render.HTMLSet(status, setName, tplName, data[0], data[1].(HTMLOptions))
		}
	}
}

// HTML calls Render.HTML but allows less arguments.
func (ctx *Context) HTML(status int, name string, data ...interface{}) {
	ctx.renderHTML(status, _DEFAULT_TPL_SET_NAME, name, data...)
}

// HTML calls Render.HTMLSet but allows less arguments.
func (ctx *Context) HTMLSet(status int, setName, tplName string, data ...interface{}) {
	ctx.renderHTML(status, setName, tplName, data...)
}

func (ctx *Context) Redirect(location string, status ...int) {
	code := http.StatusFound
	if len(status) == 1 {
		code = status[0]
	}

	http.Redirect(ctx.Resp, ctx.Req.Request, location, code)
}

// Query querys form parameter.
func (ctx *Context) Query(name string) string {
	if ctx.Req.Form == nil {
		ctx.Req.ParseForm()
	}
	return ctx.Req.Form.Get(name)
}

// QueryStrings returns a list of results by given query name.
func (ctx *Context) QueryStrings(name string) []string {
	if ctx.Req.Form == nil {
		ctx.Req.ParseForm()
	}

	vals, ok := ctx.Req.Form[name]
	if !ok {
		return []string{}
	}
	return vals
}

// QueryEscape returns escapred query result.
func (ctx *Context) QueryEscape(name string) string {
	return template.HTMLEscapeString(ctx.Query(name))
}

// QueryInt returns query result in int type.
func (ctx *Context) QueryInt(name string) int {
	return com.StrTo(ctx.Query(name)).MustInt()
}

// QueryInt64 returns query result in int64 type.
func (ctx *Context) QueryInt64(name string) int64 {
	return com.StrTo(ctx.Query(name)).MustInt64()
}

// Params returns value of given param name.
// e.g. ctx.Params(":uid")
func (ctx *Context) Params(name string) string {
	return ctx.params[name]
}

// SetParams sets value of param with given name.
func (ctx *Context) SetParams(name, val string) {
	ctx.params[name] = val
}

// ParamsEscape returns escapred params result.
// e.g. ctx.ParamsEscape(":uname")
func (ctx *Context) ParamsEscape(name string) string {
	return template.HTMLEscapeString(ctx.Params(name))
}

// ParamsInt returns params result in int type.
// e.g. ctx.ParamsInt(":uid")
func (ctx *Context) ParamsInt(name string) int {
	return com.StrTo(ctx.Params(name)).MustInt()
}

// ParamsInt64 returns params result in int64 type.
// e.g. ctx.ParamsInt64(":uid")
func (ctx *Context) ParamsInt64(name string) int64 {
	return com.StrTo(ctx.Params(name)).MustInt64()
}

// GetFile returns information about user upload file by given form field name.
func (ctx *Context) GetFile(name string) (multipart.File, *multipart.FileHeader, error) {
	return ctx.Req.FormFile(name)
}

// SetCookie sets given cookie value to response header.
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
	cookie := http.Cookie{}
	cookie.Name = name
	cookie.Value = url.QueryEscape(value)

	if len(others) > 0 {
		switch v := others[0].(type) {
		case int:
			cookie.MaxAge = v
		case int64:
			cookie.MaxAge = int(v)
		case int32:
			cookie.MaxAge = int(v)
		}
	}

	// default "/"
	if len(others) > 1 {
		if v, ok := others[1].(string); ok && len(v) > 0 {
			cookie.Path = v
		}
	} else {
		cookie.Path = "/"
	}

	// default empty
	if len(others) > 2 {
		if v, ok := others[2].(string); ok && len(v) > 0 {
			cookie.Domain = v
		}
	}

	// default empty
	if len(others) > 3 {
		switch v := others[3].(type) {
		case bool:
			cookie.Secure = v
		default:
			if others[3] != nil {
				cookie.Secure = true
			}
		}
	}

	// default false. for session cookie default true
	if len(others) > 4 {
		if v, ok := others[4].(bool); ok && v {
			cookie.HttpOnly = true
		}
	}

	ctx.Resp.Header().Add("Set-Cookie", cookie.String())
}

// GetCookie returns given cookie value from request header.
func (ctx *Context) GetCookie(name string) string {
	cookie, err := ctx.Req.Cookie(name)
	if err != nil {
		return ""
	}
	val, _ := url.QueryUnescape(cookie.Value)
	return val
}

// GetCookieInt returns cookie result in int type.
func (ctx *Context) GetCookieInt(name string) int {
	return com.StrTo(ctx.GetCookie(name)).MustInt()
}

// GetCookieInt64 returns cookie result in int64 type.
func (ctx *Context) GetCookieInt64(name string) int64 {
	return com.StrTo(ctx.GetCookie(name)).MustInt64()
}

var defaultCookieSecret string

// SetDefaultCookieSecret sets global default secure cookie secret.
func (m *Macaron) SetDefaultCookieSecret(secret string) {
	defaultCookieSecret = secret
}

// SetSecureCookie sets given cookie value to response header with default secret string.
func (ctx *Context) SetSecureCookie(name, value string, others ...interface{}) {
	ctx.SetSuperSecureCookie(defaultCookieSecret, name, value, others...)
}

// GetSecureCookie returns given cookie value from request header with default secret string.
func (ctx *Context) GetSecureCookie(key string) (string, bool) {
	return ctx.GetSuperSecureCookie(defaultCookieSecret, key)
}

// SetSuperSecureCookie sets given cookie value to response header with secret string.
func (ctx *Context) SetSuperSecureCookie(secret, name, value string, others ...interface{}) {
	m := md5.Sum([]byte(secret))
	secret = hex.EncodeToString(m[:])
	text, err := com.AESEncrypt([]byte(secret), []byte(value))
	if err != nil {
		panic("error encrypting cookie: " + err.Error())
	}
	ctx.SetCookie(name, hex.EncodeToString(text), others...)
}

// GetSuperSecureCookie returns given cookie value from request header with secret string.
func (ctx *Context) GetSuperSecureCookie(secret, key string) (string, bool) {
	val := ctx.GetCookie(key)
	if val == "" {
		return "", false
	}

	data, err := hex.DecodeString(val)
	if err != nil {
		return "", false
	}

	m := md5.Sum([]byte(secret))
	secret = hex.EncodeToString(m[:])
	text, err := com.AESDecrypt([]byte(secret), data)
	return string(text), err == nil
}

// ServeContent serves given content to response.
func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
	modtime := time.Now()
	for _, p := range params {
		switch v := p.(type) {
		case time.Time:
			modtime = v
		}
	}
	ctx.Resp.Header().Set("Content-Description", "Raw content")
	ctx.Resp.Header().Set("Content-Type", "text/plain")
	ctx.Resp.Header().Set("Expires", "0")
	ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
	ctx.Resp.Header().Set("Pragma", "public")
	http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r)
}

// ServeFile serves given file to response.
func (ctx *Context) ServeFile(file string, names ...string) {
	var name string
	if len(names) > 0 {
		name = names[0]
	} else {
		name = path.Base(file)
	}
	ctx.Resp.Header().Set("Content-Description", "File Transfer")
	ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
	ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
	ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
	ctx.Resp.Header().Set("Expires", "0")
	ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
	ctx.Resp.Header().Set("Pragma", "public")
	http.ServeFile(ctx.Resp, ctx.Req.Request, file)
}

// ChangeStaticPath changes static path from old to new one.
func (ctx *Context) ChangeStaticPath(oldPath, newPath string) {
	if !filepath.IsAbs(oldPath) {
		oldPath = filepath.Join(Root, oldPath)
	}
	dir := statics.Get(oldPath)
	if dir != nil {
		statics.Delete(oldPath)

		if !filepath.IsAbs(newPath) {
			newPath = filepath.Join(Root, newPath)
		}
		*dir = http.Dir(newPath)
		statics.Set(dir)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// go test *.go -bench=".*" -benchmem

package gqueue_test

import (
	"github.com/gogf/gf/g/container/gqueue"
	"github.com/gogf/gf/g/test/gtest"
	"testing"
)

func TestQueue_Len(t *testing.T) {

	max := 100
	for n := 10; n < max; n++ {
		q1 := gqueue.New(max)
		for i := 0; i < max; i++ {
			q1.Push(i)
		}
		gtest.Assert(q1.Len(), max)
		gtest.Assert(q1.Size(), max)
	}
}

func TestQueue_Basic(t *testing.T) {
	q := gqueue.New()
	for i := 0; i < 100; i++ {
		q.Push(i)
	}
	gtest.Assert(q.Pop(), 0)
	gtest.Assert(q.Pop(), 1)
}

func TestQueue_Pop(t *testing.T) {
	q1 := gqueue.New()
	q1.Push(1)
	q1.Push(2)
	q1.Push(3)
	q1.Push(4)
	i1 := q1.Pop()
	gtest.Assert(i1, 1)

}

func TestQueue_Close(t *testing.T) {
	q1 := gqueue.New()
	q1.Push(1)
	q1.Push(2)
	gtest.Assert(q1.Len(), 2)
	q1.Close()
}
<commit_msg>Update gqueue_unit_test.go<commit_after>// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

// go test *.go -bench=".*" -benchmem

package gqueue_test

import (
	"github.com/gogf/gf/g/container/gqueue"
	"github.com/gogf/gf/g/test/gtest"
	"testing"
)

func TestQueue_Len(t *testing.T) {
	max := 100
	for n := 10; n < max; n++ {
		q1 := gqueue.New(max)
		for i := 0; i < max; i++ {
			q1.Push(i)
		}
		gtest.Assert(q1.Len(), max)
		gtest.Assert(q1.Size(), max)
	}
}

func TestQueue_Basic(t *testing.T) {
	q := gqueue.New()
	for i := 0; i < 100; i++ {
		q.Push(i)
	}
	gtest.Assert(q.Pop(), 0)
	gtest.Assert(q.Pop(), 1)
}

func TestQueue_Pop(t *testing.T) {
	q1 := gqueue.New()
	q1.Push(1)
	q1.Push(2)
	q1.Push(3)
	q1.Push(4)
	i1 := q1.Pop()
	gtest.Assert(i1, 1)
}

func TestQueue_Close(t *testing.T) {
	q1 := gqueue.New()
	q1.Push(1)
	q1.Push(2)
	gtest.Assert(q1.Len(), 2)
	q1.Close()
}
<|endoftext|>


<commit_before>package web

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
)

// Context is type of an web.Context
type Context struct {
	ResponseWriter http.ResponseWriter
	Request        *http.Request
	params         *Params
	urlValues      *url.Values
}

// Param get value from Params
func (ctx *Context) Param(name string) string {
	return ctx.params.Val(name)
}

// Query get value from QueryString
func (ctx *Context) Query(name string) string {
	if ctx.urlValues == nil {
		urlValues := ctx.Request.URL.Query()
		ctx.urlValues = &urlValues
	}

	return ctx.urlValues.Get(name)
}

// Form get value from Form
func (ctx *Context) Form(name string) string {
	if ctx.Request.Form == nil {
		ctx.Request.ParseForm()
	}
	return ctx.Request.Form.Get(name)
}

// Unmarshal parse val to v
func (ctx *Context) Unmarshal(val string, v interface{}) error {
	rv := reflect.ValueOf(v)

	if rv.IsNil() {
		return errors.New("Unmarshal(nil)")
	}

	if rv.Kind() != reflect.Ptr {
		return errors.New("Unmarshal(non-pointer " + reflect.TypeOf(v).String() + ")")
	}

	for rv.Kind() == reflect.Ptr && !rv.IsNil() {
		rv = rv.Elem()
	}

	switch rv.Interface().(type) {
	case string:
		rv.SetString(val)
		return nil
	case int, int64:
		d, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			return err
		}
		rv.SetInt(d)
		return nil
	case int32:
		d, err := strconv.ParseInt(val, 10, 32)
		if err != nil {
			return err
		}
		rv.SetInt(d)
		return nil
	default:
		return json.Unmarshal([]byte(val), v)
	}
}

// TryParse decode val from Request.Body
func (ctx *Context) TryParse(val interface{}) error {
	if err := json.NewDecoder(ctx.Request.Body).Decode(val); err != nil {
		return err
	}
	defer ctx.Request.Body.Close()
	return nil
}

// Parse decode val from Request.Body, if error != nil abort
func (ctx *Context) Parse(val interface{}) {
	ctx.AbortIf(ctx.TryParse(val))
}

// TryParseParam decode val from Query
func (ctx *Context) TryParseParam(name string, val interface{}) error {
	return ctx.Unmarshal(ctx.Param(name), val)
}

// ParseParam decode val from Param, if error != nil abort
func (ctx *Context) ParseParam(name string, val interface{}) {
	ctx.AbortIf(ctx.TryParseParam(name, val))
}

// TryParseQuery decode val from Query
func (ctx *Context) TryParseQuery(name string, val interface{}) error {
	return ctx.Unmarshal(ctx.Query(name), val)
}

// ParseQuery decode val from Query, if error != nil abort
func (ctx *Context) ParseQuery(name string, val interface{}) {
	ctx.AbortIf(ctx.TryParseQuery(name, val))
}

// TryParseForm decode val from Form
func (ctx *Context) TryParseForm(name string, val interface{}) error {
	return ctx.Unmarshal(ctx.Form(name), val)
}

// ParseForm decode val from Form, if error != nil abort
func (ctx *Context) ParseForm(name string, val interface{}) {
	ctx.AbortIf(ctx.TryParseForm(name, val))
}

// Abort WriteHeader 400 then abort
func (ctx *Context) Abort() {
	ctx.ResponseWriter.WriteHeader(defaultHTTPError)
	panic(errors.New("Abort by user"))
}

// AbortIf if error != nill, WriteHeader 400 then abort
func (ctx *Context) AbortIf(err error) {
	if err != nil {
		ctx.ResponseWriter.WriteHeader(defaultHTTPError)
		panic(err)
	}
}

// AbortFn if error != nill, call fn then abort
func (ctx *Context) AbortFn(code int, err error, fn func(code int, err error) error) {
	if err != nil {
		if fn != nil {
			fn(code, err)
		}
		panic(err)
	}
}

// Header get value by key from header
func (ctx *Context) Header(key string) string {
	return ctx.Request.Header.Get(key)
}

// Write bytes
func (ctx *Context) Write(val []byte) (int, error) {
	return ctx.ResponseWriter.Write(val)
}

// WriteString Write String
func (ctx *Context) WriteString(val string) (int, error) {
	return ctx.ResponseWriter.Write([]byte(val))
}

// WriteJSON Write JSON
func (ctx *Context) WriteJSON(val interface{}) error {
	return json.NewEncoder(ctx.ResponseWriter).Encode(val)
}

// WriteXML Write XML
func (ctx *Context) WriteXML(val interface{}) error {
	return xml.NewEncoder(ctx.ResponseWriter).Encode(val)
}

// WriteSuccess with status
func (ctx *Context) WriteSuccess(code int, result interface{}) error {
	data := &responseData{
		Success: true,
		Code:    code,
		Result:  result,
	}
	ctx.ResponseWriter.WriteHeader(defaultHTTPSuccess)
	return ctx.WriteJSON(data)
}

// WriteError with http 400 and code
func (ctx *Context) WriteError(code int, err error) error {
	data := &responseData{
		Success: false,
		Code:    code,
		Error:   err,
	}
	ctx.ResponseWriter.WriteHeader(defaultHTTPError)
	return ctx.WriteJSON(data)
}

// WriteHeader Write Header
func (ctx *Context) WriteHeader(statusCode int) {
	ctx.ResponseWriter.WriteHeader(statusCode)
}

// SetHeader Set Header
func (ctx *Context) SetHeader(key string, value string) {
	ctx.ResponseWriter.Header().Set(key, value)
}

// AddHeader Add Header
func (ctx *Context) AddHeader(key string, value string) {
	ctx.ResponseWriter.Header().Add(key, value)
}

// SetContentType Set Content-Type
func (ctx *Context) SetContentType(val string) {
	ctx.ResponseWriter.Header().Set("Content-Type", contentType(val))
}

// Redirect to url with status
func (ctx *Context) Redirect(status int, url string) {
	ctx.SetHeader("Location", url)
	ctx.WriteHeader(status)
	ctx.WriteString("Redirecting to: " + url)
}
<commit_msg>added token to ctx<commit_after>package web

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
)

// Context is type of an web.Context
type Context struct {
	ResponseWriter http.ResponseWriter
	Request        *http.Request
	params         *Params
	urlValues      *url.Values
	token          *string
}

// GetToken return token
func (ctx *Context) GetToken() *string {
	return ctx.token
}

// SetToken set token
func (ctx *Context) SetToken(token *string) {
	ctx.token = token
}

// Param get value from Params
func (ctx *Context) Param(name string) string {
	return ctx.params.Val(name)
}

// Query get value from QueryString
func (ctx *Context) Query(name string) string {
	if ctx.urlValues == nil {
		urlValues := ctx.Request.URL.Query()
		ctx.urlValues = &urlValues
	}

	return ctx.urlValues.Get(name)
}

// Form get value from Form
func (ctx *Context) Form(name string) string {
	if ctx.Request.Form == nil {
		ctx.Request.ParseForm()
	}
	return ctx.Request.Form.Get(name)
}

// Unmarshal parse val to v
func (ctx *Context) Unmarshal(val string, v interface{}) error {
	rv := reflect.ValueOf(v)

	if rv.IsNil() {
		return errors.New("Unmarshal(nil)")
	}

	if rv.Kind() != reflect.Ptr {
		return errors.New("Unmarshal(non-pointer " + reflect.TypeOf(v).String() + ")")
	}

	for rv.Kind() == reflect.Ptr && !rv.IsNil() {
		rv = rv.Elem()
	}

	switch rv.Interface().(type) {
	case string:
		rv.SetString(val)
		return nil
	case int, int64:
		d, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			return err
		}
		rv.SetInt(d)
		return nil
	case int32:
		d, err := strconv.ParseInt(val, 10, 32)
		if err != nil {
			return err
		}
		rv.SetInt(d)
		return nil
	default:
		return json.Unmarshal([]byte(val), v)
	}
}

// TryParse decode val from Request.Body
func (ctx *Context) TryParse(val interface{}) error {
	if err := json.NewDecoder(ctx.Request.Body).Decode(val); err != nil {
		return err
	}
	defer ctx.Request.Body.Close()
	return nil
}

// Parse decode val from Request.Body, if error != nil abort
func (ctx *Context) Parse(val interface{}) {
	ctx.AbortIf(ctx.TryParse(val))
}

// TryParseParam decode val from Query
func (ctx *Context) TryParseParam(name string, val interface{}) error {
	return ctx.Unmarshal(ctx.Param(name), val)
}

// ParseParam decode val from Param, if error != nil abort
func (ctx *Context) ParseParam(name string, val interface{}) {
	ctx.AbortIf(ctx.TryParseParam(name, val))
}

// TryParseQuery decode val from Query
func (ctx *Context) TryParseQuery(name string, val interface{}) error {
	return ctx.Unmarshal(ctx.Query(name), val)
}

// ParseQuery decode val from Query, if error != nil abort
func (ctx *Context) ParseQuery(name string, val interface{}) {
	ctx.AbortIf(ctx.TryParseQuery(name, val))
}

// TryParseForm decode val from Form
func (ctx *Context) TryParseForm(name string, val interface{}) error {
	return ctx.Unmarshal(ctx.Form(name), val)
}

// ParseForm decode val from Form, if error != nil abort
func (ctx *Context) ParseForm(name string, val interface{}) {
	ctx.AbortIf(ctx.TryParseForm(name, val))
}

// Abort WriteHeader 400 then abort
func (ctx *Context) Abort() {
	ctx.ResponseWriter.WriteHeader(defaultHTTPError)
	panic(errors.New("Abort by user"))
}

// AbortIf if error != nill, WriteHeader 400 then abort
func (ctx *Context) AbortIf(err error) {
	if err != nil {
		ctx.ResponseWriter.WriteHeader(defaultHTTPError)
		panic(err)
	}
}

// AbortFn if error != nill, call fn then abort
func (ctx *Context) AbortFn(code int, err error, fn func(code int, err error) error) {
	if err != nil {
		if fn != nil {
			fn(code, err)
		}
		panic(err)
	}
}

// Header get value by key from header
func (ctx *Context) Header(key string) string {
	return ctx.Request.Header.Get(key)
}

// Write bytes
func (ctx *Context) Write(val []byte) (int, error) {
	return ctx.ResponseWriter.Write(val)
}

// WriteString Write String
func (ctx *Context) WriteString(val string) (int, error) {
	return ctx.ResponseWriter.Write([]byte(val))
}

// WriteJSON Write JSON
func (ctx *Context) WriteJSON(val interface{}) error {
	return json.NewEncoder(ctx.ResponseWriter).Encode(val)
}

// WriteXML Write XML
func (ctx *Context) WriteXML(val interface{}) error {
	return xml.NewEncoder(ctx.ResponseWriter).Encode(val)
}

// WriteSuccess with status
func (ctx *Context) WriteSuccess(code int, result interface{}) error {
	data := &responseData{
		Success: true,
		Code:    code,
		Result:  result,
	}
	ctx.ResponseWriter.WriteHeader(defaultHTTPSuccess)
	return ctx.WriteJSON(data)
}

// WriteError with http 400 and code
func (ctx *Context) WriteError(code int, err error) error {
	data := &responseData{
		Success: false,
		Code:    code,
		Error:   err,
	}
	ctx.ResponseWriter.WriteHeader(defaultHTTPError)
	return ctx.WriteJSON(data)
}

// WriteHeader Write Header
func (ctx *Context) WriteHeader(statusCode int) {
	ctx.ResponseWriter.WriteHeader(statusCode)
}

// SetHeader Set Header
func (ctx *Context) SetHeader(key string, value string) {
	ctx.ResponseWriter.Header().Set(key, value)
}

// AddHeader Add Header
func (ctx *Context) AddHeader(key string, value string) {
	ctx.ResponseWriter.Header().Add(key, value)
}

// SetContentType Set Content-Type
func (ctx *Context) SetContentType(val string) {
	ctx.ResponseWriter.Header().Set("Content-Type", contentType(val))
}

// Redirect to url with status
func (ctx *Context) Redirect(status int, url string) {
	ctx.SetHeader("Location", url)
	ctx.WriteHeader(status)
	ctx.WriteString("Redirecting to: " + url)
}
<|endoftext|>