<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
)

type SlackAttachment struct {
	Title    string `json:"title,omitempty"`
	Text     string `json:"text,omitempty"`
	ImageURL string `json:"image_url,omitempty"`
}

type SlackResponse struct {
	ResponseType string             `json:"response_type,omitempty"`
	Text         string             `json:"text"`
	Attachments  *[]SlackAttachment `json:"attachments,omitempty"`
}

type UntappdBeer struct {
	ID          int     `json:"bid"`
	Name        string  `json:"beer_name"`
	Label       string  `json:"beer_label"`
	Ibu         int     `json:"beer_ibu"`
	Abv         float64 `json:"beer_abv"`
	Style       string  `json:"beer_style"`
	Description string  `json:"beer_description"`
}

type UntappdBeerResponse struct {
	Beers struct {
		Items []struct {
			Beer *UntappdBeer `json:"beer"`
		}
	}
}

type UntappdResponse struct {
	Meta struct {
		StatusCode int `json:"code"`
	}
	Beer *UntappdBeerResponse `json:"response"`
}

func untappdRequest(searchString string) (untappdData *UntappdResponse, err error) {

	untappdResponse := &UntappdResponse{}

	untappdClientID := os.Getenv("UNTAPPD_CLIENT_ID")
	if untappdClientID == "" {
		return untappdResponse, errors.New("unable to read environment variable UNTAPPD_CLIENT_ID")
	}
	untappdClientSecret := os.Getenv("UNTAPPD_CLIENT_SECRET")
	if untappdClientSecret == "" {
		return untappdResponse, errors.New("unable to read environment variable UNTAPPD_CLIENT_SECRET")
	}

	requestURL := url.URL{
		Scheme: "https",
		Host:   "api.untappd.com",
		Path:   "/v4/search/beer",
	}
	q := requestURL.Query()
	q.Set("client_id", untappdClientID)
	q.Set("client_secret", untappdClientSecret)
	q.Set("q", searchString)
	requestURL.RawQuery = q.Encode()

	res, err := http.Get(requestURL.String())
	if err != nil {
		return untappdResponse, err
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return untappdResponse, err
	}
	if err := json.Unmarshal(body, &untappdResponse); err != nil {
		return untappdResponse, err
	}

	return untappdResponse, nil

}

func slug(s string) string {
	var re = regexp.MustCompile("[^a-z0-9]+")
	return strings.Trim(re.ReplaceAllString(strings.ToLower(s), "-"), "-")
}

func handler(w http.ResponseWriter, r *http.Request) {

	slackToken := os.Getenv("SLACK_TOKEN")
	if slackToken == "" {
		log.Println("unable to read environment variable SLACK_TOKEN")
		http.Error(w, "UNABLE_TO_READ_SLACK_TOKEN", http.StatusInternalServerError)
		return
	}

	reqSlackToken := r.FormValue("token")
	if reqSlackToken == "" {
		http.Error(w, "MISSING_ARG_TOKEN", http.StatusBadRequest)
		return
	}

	slackTokens := strings.Split(slackToken, ",")
	for _, token := range slackTokens {
		if token != reqSlackToken {
			http.Error(w, "INVALID_TOKEN", http.StatusUnauthorized)
			return
		}
	}

	reqUserName := r.FormValue("user_name")
	if reqUserName == "" {
		http.Error(w, "MISSING_ARG_USER_NAME", http.StatusBadRequest)
		return
	}
	if reqUserName == "slackbot" {
		return // this is a bot response that we simply want to ignore
	}

	searchString := r.FormValue("text")
	if searchString == "" {
		http.Error(w, "MISSING_ARG_TEXT", http.StatusBadRequest)
		return
	}

	untappdData, err := untappdRequest(searchString)
	if err != nil {
		log.Println(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	response := &SlackResponse{
		ResponseType: "in_channel",
		Text:         "Your Untappd Response",
	}

	if len(untappdData.Beer.Beers.Items) == 0 {
		response.ResponseType = "ephemeral"
		response.Text = "No Results Found"
	} else {
		beer := untappdData.Beer.Beers.Items[0].Beer

		untappdURL := fmt.Sprintf("https://untappd.com/b/%s/%d", slug(beer.Name), beer.ID)

		newAttachment := SlackAttachment{
			Title:    fmt.Sprintf("<%s|%s>", untappdURL, beer.Name),
			Text:     fmt.Sprintf("%s | %d IBU | %0.0f%% ABV \n%s", beer.Style, beer.Ibu, beer.Abv, beer.Description),
			ImageURL: beer.Label,
		}
		attachments := append([]SlackAttachment{}, newAttachment)
		response.Attachments = &attachments
	}

	responseJSON, err := json.Marshal(response)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(responseJSON)
}

func main() {
	var port string
	port = os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	http.HandleFunc("/", handler)
	http.ListenAndServe(":"+port, nil)
}
<commit_msg>Correctly handle multiple slack tokens<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
)

type SlackAttachment struct {
	Title    string `json:"title,omitempty"`
	Text     string `json:"text,omitempty"`
	ImageURL string `json:"image_url,omitempty"`
}

type SlackResponse struct {
	ResponseType string             `json:"response_type,omitempty"`
	Text         string             `json:"text"`
	Attachments  *[]SlackAttachment `json:"attachments,omitempty"`
}

type UntappdBeer struct {
	ID          int     `json:"bid"`
	Name        string  `json:"beer_name"`
	Label       string  `json:"beer_label"`
	Ibu         int     `json:"beer_ibu"`
	Abv         float64 `json:"beer_abv"`
	Style       string  `json:"beer_style"`
	Description string  `json:"beer_description"`
}

type UntappdBeerResponse struct {
	Beers struct {
		Items []struct {
			Beer *UntappdBeer `json:"beer"`
		}
	}
}

type UntappdResponse struct {
	Meta struct {
		StatusCode int `json:"code"`
	}
	Beer *UntappdBeerResponse `json:"response"`
}

func untappdRequest(searchString string) (untappdData *UntappdResponse, err error) {

	untappdResponse := &UntappdResponse{}

	untappdClientID := os.Getenv("UNTAPPD_CLIENT_ID")
	if untappdClientID == "" {
		return untappdResponse, errors.New("unable to read environment variable UNTAPPD_CLIENT_ID")
	}
	untappdClientSecret := os.Getenv("UNTAPPD_CLIENT_SECRET")
	if untappdClientSecret == "" {
		return untappdResponse, errors.New("unable to read environment variable UNTAPPD_CLIENT_SECRET")
	}

	requestURL := url.URL{
		Scheme: "https",
		Host:   "api.untappd.com",
		Path:   "/v4/search/beer",
	}
	q := requestURL.Query()
	q.Set("client_id", untappdClientID)
	q.Set("client_secret", untappdClientSecret)
	q.Set("q", searchString)
	requestURL.RawQuery = q.Encode()

	res, err := http.Get(requestURL.String())
	if err != nil {
		return untappdResponse, err
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return untappdResponse, err
	}
	if err := json.Unmarshal(body, &untappdResponse); err != nil {
		return untappdResponse, err
	}

	return untappdResponse, nil

}

func slug(s string) string {
	var re = regexp.MustCompile("[^a-z0-9]+")
	return strings.Trim(re.ReplaceAllString(strings.ToLower(s), "-"), "-")
}

func handler(w http.ResponseWriter, r *http.Request) {

	slackToken := os.Getenv("SLACK_TOKEN")
	if slackToken == "" {
		log.Println("unable to read environment variable SLACK_TOKEN")
		http.Error(w, "UNABLE_TO_READ_SLACK_TOKEN", http.StatusInternalServerError)
		return
	}

	reqSlackToken := r.FormValue("token")
	if reqSlackToken == "" {
		http.Error(w, "MISSING_ARG_TOKEN", http.StatusBadRequest)
		return
	}

	validToken := false
	slackTokens := strings.Split(slackToken, ",")
	for _, token := range slackTokens {
		if token == reqSlackToken {
			validToken = true
			break
		}
	}

	if !validToken {
		http.Error(w, "INVALID_TOKEN", http.StatusUnauthorized)
		return
	}

	reqUserName := r.FormValue("user_name")
	if reqUserName == "" {
		http.Error(w, "MISSING_ARG_USER_NAME", http.StatusBadRequest)
		return
	}
	if reqUserName == "slackbot" {
		return // this is a bot response that we simply want to ignore
	}

	searchString := r.FormValue("text")
	if searchString == "" {
		http.Error(w, "MISSING_ARG_TEXT", http.StatusBadRequest)
		return
	}

	untappdData, err := untappdRequest(searchString)
	if err != nil {
		log.Println(err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	response := &SlackResponse{
		ResponseType: "in_channel",
		Text:         "Your Untappd Response",
	}

	if len(untappdData.Beer.Beers.Items) == 0 {
		response.ResponseType = "ephemeral"
		response.Text = "No Results Found"
	} else {
		beer := untappdData.Beer.Beers.Items[0].Beer

		untappdURL := fmt.Sprintf("https://untappd.com/b/%s/%d", slug(beer.Name), beer.ID)

		newAttachment := SlackAttachment{
			Title:    fmt.Sprintf("<%s|%s>", untappdURL, beer.Name),
			Text:     fmt.Sprintf("%s | %d IBU | %0.0f%% ABV \n%s", beer.Style, beer.Ibu, beer.Abv, beer.Description),
			ImageURL: beer.Label,
		}
		attachments := append([]SlackAttachment{}, newAttachment)
		response.Attachments = &attachments
	}

	responseJSON, err := json.Marshal(response)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.Write(responseJSON)
}

func main() {
	var port string
	port = os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	http.HandleFunc("/", handler)
	http.ListenAndServe(":"+port, nil)
}
<|endoftext|>


<commit_before>package location

import (
	"fmt"
	"github.com/jasdel/explore/util/command"
	"strings"
)

const (
	DirectionalExitMsgFmt  = `%[1]s leaves to the %[2]s`
	DirectionalEnterMsgFmt = `%[1]s enters from the %[2]s`
)

// Directional exit that is tied to an location
type Exit struct {
	Name      string
	Aliases   []string
	ExitMsg   string
	EnterMsg  string
	Loc       Interface
	LookAhead string
}

// Processes the command determining if this exit is where the thing is going through
// Expects to be called in the same context as a location
//
// TODO need to refactor how locatables are moved between locations. This method
// 'works', but may not be safe.
//
func (e *Exit) Process(cmd *command.Command) bool {
	for _, alias := range e.Aliases {
		if cmd.Verb == alias {
			locatable, ok := cmd.Issuer.(Locatable)
			if !ok {
				return false
			}

			fmt.Println("Exit.Process: DEBUG:", e.Name, "exit by", cmd.Issuer.Name(), cmd.Issuer.UniqueId())

			origLoc := locatable.Relocate(e.Loc)
			if origLoc != nil {
				origLoc.Broadcast(cmd.Issuer.SelfOmit(), e.ExitMsg, cmd.Issuer.Name(), e.Name)
				origLoc.Remove(cmd.Issuer)
			}
			fmt.Println("Exit.Process: DEBUG:", e.Name, "relocated", cmd.Issuer.Name(), cmd.Issuer.UniqueId(), origLoc.Name(), origLoc.UniqueId())

			e.Loc.MoveIn(cmd.Issuer, origLoc, fmt.Sprintf(e.EnterMsg, cmd.Issuer.Name(), e.Name))
			return true
		}
	}
	return false
}

type Exits []Exit

// Prints the known exits to strings
func (e Exits) String() string {
	buf := make([]string, 0, len(e))

	for _, exit := range e {
		buf = append(buf, exit.Name)
	}
	output := strings.Join(buf, ", ")

	if output == "" {
		output = "none"
	}

	return output
}
<commit_msg>Cleaned up exit process to also use name of item in addition to aliases<commit_after>package location

import (
	"fmt"
	"github.com/jasdel/explore/entity/thing"
	"github.com/jasdel/explore/util/command"
	"strings"
)

const (
	DirectionalExitMsgFmt  = `%[1]s leaves to the %[2]s`
	DirectionalEnterMsgFmt = `%[1]s enters from the %[2]s`
)

// Directional exit that is tied to an location
type Exit struct {
	Name      string
	Aliases   []string
	ExitMsg   string
	EnterMsg  string
	Loc       Interface
	LookAhead string
}

// Processes the command determining if this exit is where the thing is going through
// Expects to be called in the same context as a location
//
// TODO need to refactor how locatables are moved between locations. This method
// 'works', but may not be safe.
//
func (e *Exit) Process(cmd *command.Command) bool {

	if e.Name == cmd.Verb {
		e.exit(cmd.Issuer)
		return true
	}

	for _, alias := range e.Aliases {
		if cmd.Verb == alias {
			e.exit(cmd.Issuer)
			return true
		}
	}

	return false
}

// Moves the thing out of its current location and into a new location.
func (e *Exit) exit(t thing.Interface) {
	locatable, ok := t.(Locatable)
	if !ok {
		fmt.Printf("Exit.exit: DEBUG: %s is not a locatable. %#v\n", e.Name, t)
		return
	}

	origLoc := locatable.Relocate(e.Loc)
	if origLoc != nil {
		origLoc.Broadcast(t.SelfOmit(), e.ExitMsg, t.Name(), e.Name)
		origLoc.Remove(t)
	}
	fmt.Println("Exit.Process: DEBUG:", e.Name, "relocated", t.Name(), t.UniqueId(), origLoc.Name(), origLoc.UniqueId())

	e.Loc.MoveIn(t, origLoc, fmt.Sprintf(e.EnterMsg, t.Name(), e.Name))
}

type Exits []Exit

// Prints the known exits to strings
func (e Exits) String() string {
	buf := make([]string, 0, len(e))

	for _, exit := range e {
		buf = append(buf, exit.Name)
	}
	output := strings.Join(buf, ", ")

	if output == "" {
		output = "none"
	}

	return output
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "bufio"
    "fmt"
    "strings"
    "time"
    "regexp"
    "flag"
    "os"
)

func main() {

    fName := flag.String("in", "", "Input file to parse")
    flag.Parse()

    if len(*fName) <= 0 {
        flag.Usage()
        os.Exit(6)
    }

    f, err := os.Open(*fName)
    if err != nil {
        log.Fatalln(err)
    }
    defer f.Close()

    started := time.Now()
    fmt.Fprintf(os.Stderr, "Starting output at: %s\n", started.String())

    scanner := bufio.NewScanner(f)
    isBlock := false
    str := ""
    spaces, _ := regexp.Compile(" +")

    // Add inet6num if you need IPv6 too.
    hasInetnum, _ := regexp.Compile("^inetnum:")
    isInet := false

    for scanner.Scan() {
        text := scanner.Text()

        if hasInetnum.MatchString(text) {
            isBlock = true
            isInet = true
        } else {
            isInet = false
        }

        isCountry := strings.Contains(text, "country:")

        if isBlock && (isInet || isCountry) {
            simple := spaces.ReplaceAllString(text, "")
            parts := strings.Split(simple, ":")

            if isInet {
                fromTo := strings.Split(parts[1], "-")
                str += fromTo[0] + ";" + fromTo[1] + ";"
            } else {
                str += parts[1]
            }
        }

        if text == "" {
            isBlock = false

            if str != "" {
                fmt.Println(str)
                str = ""
            }
        }

    }

    fmt.Fprintf(os.Stderr, "Ending output at: %s, took: %s\n", time.Now().String(), time.Now().Sub(started).String())
}

<commit_msg>doc: added licence<commit_after>/*
MIT License

Copyright (c) 2017 Tomaž Marhat

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
 */

package main

import (
    "log"
    "bufio"
    "fmt"
    "strings"
    "time"
    "regexp"
    "flag"
    "os"
)

// Parse(fh *os.File)
// Parses the input ripe database for IPv4 ranges and corresponding countries.
// Status messages are written to stderr, and data to stdout
func Parse(fh *os.File) {
    started := time.Now()
    fmt.Fprintf(os.Stderr, "Starting output at: %s\n", started.String())

    scanner := bufio.NewScanner(fh)
    isBlock := false
    str := ""
    spaces, _ := regexp.Compile(" +")

    // Add inet6num if you need IPv6 too.
    hasInetnum, _ := regexp.Compile("^inetnum:")
    isInet := false

    for scanner.Scan() {
        text := scanner.Text()

        if hasInetnum.MatchString(text) {
            isBlock = true
            isInet = true
        } else {
            isInet = false
        }

        isCountry := strings.Contains(text, "country:")

        if isBlock && (isInet || isCountry) {
            simple := spaces.ReplaceAllString(text, "")
            parts := strings.Split(simple, ":")

            if isInet {
                fromTo := strings.Split(parts[1], "-")
                str += fromTo[0] + ";" + fromTo[1] + ";"
            } else {
                str += parts[1]
            }
        }

        if text == "" {
            isBlock = false

            if str != "" {
                fmt.Println(str)
                str = ""
            }
        }

    }

    fmt.Fprintf(os.Stderr, "Ending output at: %s, took: %s\n", time.Now().String(), time.Now().Sub(started).String())
}

func main() {
    fName := flag.String("in", "ripe.db", "Input file to parse, defauls to ripe.db")
    flag.Parse()

    if len(*fName) <= 0 {
        flag.Usage()
        os.Exit(6)
    }

    f, err := os.Open(*fName)
    if err != nil {
        log.Fatalln(err)
    }
    defer f.Close()
    Parse(f)
}
<|endoftext|>


<commit_before>package goparse

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"reflect"
	"strconv"
	"strings"
)

// StructDesc contains description of parsed struct
type StructDesc struct {
	Name  string
	Field []StructField
}

// StructField describes field itself
type StructField struct {
	Name      string
	Type      string
	Tags      []string
	TagParams map[string]string
	TagGt     map[string]int
	TagLt     map[string]int
}

func getTypeName(t ast.Expr) string {
	switch e := t.(type) {
	case *ast.Ident:
		return e.Name
	case *ast.ArrayType:
		return "[]" + getTypeName(e.Elt)
	case *ast.StarExpr:
		return "*" + getTypeName(e.X)
	case *ast.MapType:
		return fmt.Sprintf("map[%s]%s", getTypeName(e.Key), getTypeName(e.Value))
	case *ast.SelectorExpr:
		return fmt.Sprintf("%s.%s", e.X.(*ast.Ident).Name, e.Sel.Name)
	}
	return "unknown"
}

// GetFileStructs returns structs descriptions from parsed go file
func GetFileStructs(filename string, prefix string, tag string) ([]StructDesc, error) {
	result := make([]StructDesc, 0, 5)

	fset := token.NewFileSet()

	f, err := parser.ParseFile(fset, filename, nil, 0)
	if nil != err {
		return result, err
	}

	for i := range f.Decls {
		if g, ok := f.Decls[i].(*ast.GenDecl); ok {
			for _, s := range g.Specs {
				if ts, ok := s.(*ast.TypeSpec); ok {
					if "" == prefix || strings.HasPrefix(ts.Name.String(), prefix) {
						if tt, ok := ts.Type.(*ast.StructType); ok {
							newStruct := StructDesc{Name: ts.Name.String(), Field: make([]StructField, 0, len(tt.Fields.List))}
							for _, field := range tt.Fields.List {
								newField := StructField{}
								if len(field.Names) < 1 {
									continue
								}

								newField.Name = field.Names[0].Name
								newField.Type = getTypeName(field.Type)
								newField.Tags = []string{}
								newField.TagParams = map[string]string{}
								newField.TagGt = map[string]int{}
								newField.TagLt = map[string]int{}

								if nil != field.Tag {
									tags := strings.Split(reflect.StructTag(strings.Trim(field.Tag.Value, "`")).Get(tag), ",")

									for _, tag := range tags {
										ts := strings.SplitN(tag, "=", 2)
										if len(ts) == 2 {
											newField.TagParams[ts[0]] = ts[1]
										}
										if len(ts) == 1 {
											ts = strings.SplitN(tag, ">", 2)
											if len(ts) == 2 {
												newField.TagGt[ts[0]], _ = strconv.Atoi(ts[1])
											}
										}
										if len(ts) == 1 {
											ts = strings.SplitN(tag, "<", 2)
											if len(ts) == 2 {
												newField.TagLt[ts[0]], _ = strconv.Atoi(ts[1])
											}
										}
										if len(ts) == 1 {
											newField.Tags = append(newField.Tags, ts[0])
										}

									}
								}
								newStruct.Field = append(newStruct.Field, newField)
							}
							result = append(result, newStruct)
						}
					}
				}
			}
		}
	}

	return result, nil
}
<commit_msg>Ignore fields with no specified tag<commit_after>package goparse

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"reflect"
	"strconv"
	"strings"
)

// StructDesc contains description of parsed struct
type StructDesc struct {
	Name  string
	Field []StructField
}

// StructField describes field itself
type StructField struct {
	Name      string
	Type      string
	Tags      []string
	TagParams map[string]string
	TagGt     map[string]int
	TagLt     map[string]int
}

func getTypeName(t ast.Expr) string {
	switch e := t.(type) {
	case *ast.Ident:
		return e.Name
	case *ast.ArrayType:
		return "[]" + getTypeName(e.Elt)
	case *ast.StarExpr:
		return "*" + getTypeName(e.X)
	case *ast.MapType:
		return fmt.Sprintf("map[%s]%s", getTypeName(e.Key), getTypeName(e.Value))
	case *ast.SelectorExpr:
		return fmt.Sprintf("%s.%s", e.X.(*ast.Ident).Name, e.Sel.Name)
	}
	return "unknown"
}

// GetFileStructs returns structs descriptions from parsed go file
func GetFileStructs(filename string, prefix string, tag string) ([]StructDesc, error) {
	result := make([]StructDesc, 0, 5)

	fset := token.NewFileSet()

	f, err := parser.ParseFile(fset, filename, nil, 0)
	if nil != err {
		return result, err
	}

	for i := range f.Decls {
		if g, ok := f.Decls[i].(*ast.GenDecl); ok {
			for _, s := range g.Specs {
				if ts, ok := s.(*ast.TypeSpec); ok {
					if "" == prefix || strings.HasPrefix(ts.Name.String(), prefix) {
						if tt, ok := ts.Type.(*ast.StructType); ok {
							newStruct := StructDesc{Name: ts.Name.String(), Field: make([]StructField, 0, len(tt.Fields.List))}
							for _, field := range tt.Fields.List {
								newField := StructField{}
								if len(field.Names) < 1 {
									continue
								}

								newField.Name = field.Names[0].Name
								newField.Type = getTypeName(field.Type)
								newField.Tags = []string{}
								newField.TagParams = map[string]string{}
								newField.TagGt = map[string]int{}
								newField.TagLt = map[string]int{}

								if nil != field.Tag {
									tags := strings.Split(reflect.StructTag(strings.Trim(field.Tag.Value, "`")).Get(tag), ",")
									if len(tags) == 1 && tags[0] == "" {
										continue
									}

									for _, tag := range tags {
										ts := strings.SplitN(tag, "=", 2)
										if len(ts) == 2 {
											newField.TagParams[ts[0]] = ts[1]
										}
										if len(ts) == 1 {
											ts = strings.SplitN(tag, ">", 2)
											if len(ts) == 2 {
												newField.TagGt[ts[0]], _ = strconv.Atoi(ts[1])
											}
										}
										if len(ts) == 1 {
											ts = strings.SplitN(tag, "<", 2)
											if len(ts) == 2 {
												newField.TagLt[ts[0]], _ = strconv.Atoi(ts[1])
											}
										}
										if len(ts) == 1 {
											newField.Tags = append(newField.Tags, ts[0])
										}

									}
								}
								newStruct.Field = append(newStruct.Field, newField)
							}
							result = append(result, newStruct)
						}
					}
				}
			}
		}
	}

	return result, nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"fmt"
	"github.com/codegangsta/cli"
	"io"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "psv"
	app.Usage = "parse csv"

	app.Action = func(c *cli.Context) {
		var fp *os.File
		la := len(c.Args())

		switch {
		case la == 0:
			fp = os.Stdin
		case la == 1:
			var err error
			fp, err = os.Open(c.Args()[0])
			if err != nil {
				panic(err)
			}
			defer fp.Close()
		case la >= 2:
			println("psv: too many arguments")
		}

		reader := csv.NewReader(fp)
		reader.Comma = ','
		reader.LazyQuotes = true
		for {
			record, err := reader.Read()
			if err == io.EOF {
				break
			} else if err != nil {
				panic(err)
			}
			fmt.Println(record)
		}
	}

	app.Run(os.Args)
}
<commit_msg>Update option for separator<commit_after>package main

import (
	"encoding/csv"
	"fmt"
	"github.com/codegangsta/cli"
	"io"
	"os"
	"strings"
)

func main() {
	app := cli.NewApp()
	app.Name = "psv"
	app.Usage = "parse csv"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "separator, s",
			Value: ",",
			Usage: "separater for fields",
		},
	}

	app.Action = func(c *cli.Context) {
		var fp *os.File
		la := len(c.Args())
		sep := c.String("separator")

		switch {
		case la == 0:
			fp = os.Stdin
		case la == 1:
			var err error
			fp, err = os.Open(c.Args()[0])
			if err != nil {
				panic(err)
			}
			defer fp.Close()
		case la >= 2:
			println("psv: too many arguments")
		}

		reader := csv.NewReader(fp)
		reader.Comma = ','
		reader.LazyQuotes = true
		for {
			record, err := reader.Read()
			if err == io.EOF {
				break
			} else if err != nil {
				panic(err)
			}
			fmt.Println(strings.Join(record, sep))
		}
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"
	"log"
	"strings"
	"sync"

	"github.com/hashicorp/terraform/dag"
)

// RootModuleName is the name given to the root module implicitly.
const RootModuleName = "root"

// RootModulePath is the path for the root module.
var RootModulePath = []string{RootModuleName}

// Graph represents the graph that Terraform uses to represent resources
// and their dependencies. Each graph represents only one module, but it
// can contain further modules, which themselves have their own graph.
type Graph struct {
	// Graph is the actual DAG. This is embedded so you can call the DAG
	// methods directly.
	dag.AcyclicGraph

	// Path is the path in the module tree that this Graph represents.
	// The root is represented by a single element list containing
	// RootModuleName
	Path []string

	// dependableMap is a lookaside table for fast lookups for connecting
	// dependencies by their GraphNodeDependable value to avoid O(n^3)-like
	// situations and turn them into O(1) with respect to the number of new
	// edges.
	dependableMap map[string]dag.Vertex

	once sync.Once
}

// Add is the same as dag.Graph.Add.
func (g *Graph) Add(v dag.Vertex) dag.Vertex {
	g.once.Do(g.init)

	// Call upwards to add it to the actual graph
	g.Graph.Add(v)

	// If this is a depend-able node, then store the lookaside info
	if dv, ok := v.(GraphNodeDependable); ok {
		for _, n := range dv.DependableName() {
			g.dependableMap[n] = v
		}
	}

	return v
}

// ConnectDependent connects a GraphNodeDependent to all of its
// GraphNodeDependables. It returns the list of dependents it was
// unable to connect to.
func (g *Graph) ConnectDependent(raw dag.Vertex) []string {
	v, ok := raw.(GraphNodeDependent)
	if !ok {
		return nil
	}

	return g.ConnectTo(v, v.DependentOn())
}

// ConnectDependents goes through the graph, connecting all the
// GraphNodeDependents to GraphNodeDependables. This is safe to call
// multiple times.
//
// To get details on whether dependencies could be found/made, the more
// specific ConnectDependent should be used.
func (g *Graph) ConnectDependents() {
	for _, v := range g.Vertices() {
		if dv, ok := v.(GraphNodeDependent); ok {
			g.ConnectDependent(dv)
		}
	}
}

// ConnectFrom creates an edge by finding the source from a DependableName
// and connecting it to the specific vertex.
func (g *Graph) ConnectFrom(source string, target dag.Vertex) {
	g.once.Do(g.init)

	if source := g.dependableMap[source]; source != nil {
		g.Connect(dag.BasicEdge(source, target))
	}
}

// ConnectTo connects a vertex to a raw string of targets that are the
// result of DependableName, and returns the list of targets that are missing.
func (g *Graph) ConnectTo(v dag.Vertex, targets []string) []string {
	g.once.Do(g.init)

	var missing []string
	for _, t := range targets {
		if dest := g.dependableMap[t]; dest != nil {
			g.Connect(dag.BasicEdge(v, dest))
		} else {
			missing = append(missing, t)
		}
	}

	return missing
}

// Dependable finds the vertices in the graph that have the given dependable
// names and returns them.
func (g *Graph) Dependable(n string) dag.Vertex {
	// TODO: do we need this?
	return nil
}

// Walk walks the graph with the given walker for callbacks. The graph
// will be walked with full parallelism, so the walker should expect
// to be called in concurrently.
func (g *Graph) Walk(walker GraphWalker) error {
	return g.walk(walker)
}

func (g *Graph) init() {
	if g.dependableMap == nil {
		g.dependableMap = make(map[string]dag.Vertex)
	}
}

func (g *Graph) walk(walker GraphWalker) error {
	// The callbacks for enter/exiting a graph
	ctx := walker.EnterGraph(g)
	defer walker.ExitGraph(g)

	// Get the path for logs
	path := strings.Join(ctx.Path(), ".")

	// Walk the graph.
	var walkFn dag.WalkFunc
	walkFn = func(v dag.Vertex) (rerr error) {
		log.Printf("[DEBUG] vertex %s.%s: walking", path, dag.VertexName(v))

		walker.EnterVertex(v)
		defer func() { walker.ExitVertex(v, rerr) }()

		// If the node is eval-able, then evaluate it.
		if ev, ok := v.(GraphNodeEvalable); ok {
			tree := ev.EvalTree()
			if tree == nil {
				panic(fmt.Sprintf(
					"%s.%s (%T): nil eval tree", path, dag.VertexName(v), v))
			}

			// Allow the walker to change our tree if needed. Eval,
			// then callback with the output.
			log.Printf("[DEBUG] vertex %s.%s: evaluating", path, dag.VertexName(v))
			tree = walker.EnterEvalTree(v, tree)
			output, err := Eval(tree, ctx)
			if rerr = walker.ExitEvalTree(v, output, err); rerr != nil {
				return
			}
		}

		// If the node is dynamically expanded, then expand it
		if ev, ok := v.(GraphNodeDynamicExpandable); ok {
			log.Printf(
				"[DEBUG] vertex %s.%s: expanding/walking dynamic subgraph",
				path,
				dag.VertexName(v))
			g, err := ev.DynamicExpand(ctx)
			if err != nil {
				rerr = err
				return
			}

			// Walk the subgraph
			if rerr = g.walk(walker); rerr != nil {
				return
			}
		}

		// If the node has a subgraph, then walk the subgraph
		if sn, ok := v.(GraphNodeSubgraph); ok {
			log.Printf(
				"[DEBUG] vertex %s.%s: walking subgraph",
				path,
				dag.VertexName(v))

			if rerr = sn.Subgraph().walk(walker); rerr != nil {
				return
			}
		}

		return nil
	}

	return g.AcyclicGraph.Walk(walkFn)
}

// GraphNodeDependable is an interface which says that a node can be
// depended on (an edge can be placed between this node and another) according
// to the well-known name returned by DependableName.
//
// DependableName can return multiple names it is known by.
type GraphNodeDependable interface {
	DependableName() []string
}

// GraphNodeDependent is an interface which says that a node depends
// on another GraphNodeDependable by some name. By implementing this
// interface, Graph.ConnectDependents() can be called multiple times
// safely and efficiently.
type GraphNodeDependent interface {
	DependentOn() []string
}
<commit_msg>terraform: Graph should overrride Remove to clear lookaside<commit_after>package terraform

import (
	"fmt"
	"log"
	"strings"
	"sync"

	"github.com/hashicorp/terraform/dag"
)

// RootModuleName is the name given to the root module implicitly.
const RootModuleName = "root"

// RootModulePath is the path for the root module.
var RootModulePath = []string{RootModuleName}

// Graph represents the graph that Terraform uses to represent resources
// and their dependencies. Each graph represents only one module, but it
// can contain further modules, which themselves have their own graph.
type Graph struct {
	// Graph is the actual DAG. This is embedded so you can call the DAG
	// methods directly.
	dag.AcyclicGraph

	// Path is the path in the module tree that this Graph represents.
	// The root is represented by a single element list containing
	// RootModuleName
	Path []string

	// dependableMap is a lookaside table for fast lookups for connecting
	// dependencies by their GraphNodeDependable value to avoid O(n^3)-like
	// situations and turn them into O(1) with respect to the number of new
	// edges.
	dependableMap map[string]dag.Vertex

	once sync.Once
}

// Add is the same as dag.Graph.Add.
func (g *Graph) Add(v dag.Vertex) dag.Vertex {
	g.once.Do(g.init)

	// Call upwards to add it to the actual graph
	g.Graph.Add(v)

	// If this is a depend-able node, then store the lookaside info
	if dv, ok := v.(GraphNodeDependable); ok {
		for _, n := range dv.DependableName() {
			g.dependableMap[n] = v
		}
	}

	return v
}

// Remove is the same as dag.Graph.Remove
func (g *Graph) Remove(v dag.Vertex) dag.Vertex {
	g.once.Do(g.init)

	// If this is a depend-able node, then remove the lookaside info
	if dv, ok := v.(GraphNodeDependable); ok {
		for _, n := range dv.DependableName() {
			delete(g.dependableMap, n)
		}
	}

	// Call upwards to remove it from the actual graph
	return g.Graph.Remove(v)
}

// ConnectDependent connects a GraphNodeDependent to all of its
// GraphNodeDependables. It returns the list of dependents it was
// unable to connect to.
func (g *Graph) ConnectDependent(raw dag.Vertex) []string {
	v, ok := raw.(GraphNodeDependent)
	if !ok {
		return nil
	}

	return g.ConnectTo(v, v.DependentOn())
}

// ConnectDependents goes through the graph, connecting all the
// GraphNodeDependents to GraphNodeDependables. This is safe to call
// multiple times.
//
// To get details on whether dependencies could be found/made, the more
// specific ConnectDependent should be used.
func (g *Graph) ConnectDependents() {
	for _, v := range g.Vertices() {
		if dv, ok := v.(GraphNodeDependent); ok {
			g.ConnectDependent(dv)
		}
	}
}

// ConnectFrom creates an edge by finding the source from a DependableName
// and connecting it to the specific vertex.
func (g *Graph) ConnectFrom(source string, target dag.Vertex) {
	g.once.Do(g.init)

	if source := g.dependableMap[source]; source != nil {
		g.Connect(dag.BasicEdge(source, target))
	}
}

// ConnectTo connects a vertex to a raw string of targets that are the
// result of DependableName, and returns the list of targets that are missing.
func (g *Graph) ConnectTo(v dag.Vertex, targets []string) []string {
	g.once.Do(g.init)

	var missing []string
	for _, t := range targets {
		if dest := g.dependableMap[t]; dest != nil {
			g.Connect(dag.BasicEdge(v, dest))
		} else {
			missing = append(missing, t)
		}
	}

	return missing
}

// Dependable finds the vertices in the graph that have the given dependable
// names and returns them.
func (g *Graph) Dependable(n string) dag.Vertex {
	// TODO: do we need this?
	return nil
}

// Walk walks the graph with the given walker for callbacks. The graph
// will be walked with full parallelism, so the walker should expect
// to be called in concurrently.
func (g *Graph) Walk(walker GraphWalker) error {
	return g.walk(walker)
}

func (g *Graph) init() {
	if g.dependableMap == nil {
		g.dependableMap = make(map[string]dag.Vertex)
	}
}

func (g *Graph) walk(walker GraphWalker) error {
	// The callbacks for enter/exiting a graph
	ctx := walker.EnterGraph(g)
	defer walker.ExitGraph(g)

	// Get the path for logs
	path := strings.Join(ctx.Path(), ".")

	// Walk the graph.
	var walkFn dag.WalkFunc
	walkFn = func(v dag.Vertex) (rerr error) {
		log.Printf("[DEBUG] vertex %s.%s: walking", path, dag.VertexName(v))

		walker.EnterVertex(v)
		defer func() { walker.ExitVertex(v, rerr) }()

		// If the node is eval-able, then evaluate it.
		if ev, ok := v.(GraphNodeEvalable); ok {
			tree := ev.EvalTree()
			if tree == nil {
				panic(fmt.Sprintf(
					"%s.%s (%T): nil eval tree", path, dag.VertexName(v), v))
			}

			// Allow the walker to change our tree if needed. Eval,
			// then callback with the output.
			log.Printf("[DEBUG] vertex %s.%s: evaluating", path, dag.VertexName(v))
			tree = walker.EnterEvalTree(v, tree)
			output, err := Eval(tree, ctx)
			if rerr = walker.ExitEvalTree(v, output, err); rerr != nil {
				return
			}
		}

		// If the node is dynamically expanded, then expand it
		if ev, ok := v.(GraphNodeDynamicExpandable); ok {
			log.Printf(
				"[DEBUG] vertex %s.%s: expanding/walking dynamic subgraph",
				path,
				dag.VertexName(v))
			g, err := ev.DynamicExpand(ctx)
			if err != nil {
				rerr = err
				return
			}

			// Walk the subgraph
			if rerr = g.walk(walker); rerr != nil {
				return
			}
		}

		// If the node has a subgraph, then walk the subgraph
		if sn, ok := v.(GraphNodeSubgraph); ok {
			log.Printf(
				"[DEBUG] vertex %s.%s: walking subgraph",
				path,
				dag.VertexName(v))

			if rerr = sn.Subgraph().walk(walker); rerr != nil {
				return
			}
		}

		return nil
	}

	return g.AcyclicGraph.Walk(walkFn)
}

// GraphNodeDependable is an interface which says that a node can be
// depended on (an edge can be placed between this node and another) according
// to the well-known name returned by DependableName.
//
// DependableName can return multiple names it is known by.
type GraphNodeDependable interface {
	DependableName() []string
}

// GraphNodeDependent is an interface which says that a node depends
// on another GraphNodeDependable by some name. By implementing this
// interface, Graph.ConnectDependents() can be called multiple times
// safely and efficiently.
type GraphNodeDependent interface {
	DependentOn() []string
}
<|endoftext|>


<commit_before>package terrain

import (
	"errors"
	"math"
)

type Terrain struct {
	layout    [][]uint16
	Max       uint16
	MaxHeight uint16
}

func New(scale uint16, max_height uint16) *Terrain {
	max := uint16(math.Exp2(float64(scale)) + 1)
	t := Terrain{Max: max, layout: make([][]uint16, max), MaxHeight: max_height}
	for i := range t.layout {
		t.layout[i] = make([]uint16, max)
	}

	return &t
}

func (t *Terrain) GetHeight(x uint16, y uint16) (num uint16, err error) {
	// Below-zero is unrepresentable by unsigned ints
	if x > t.Max-1 || y > t.Max-1 {
		return 0, errors.New("Index out of range")
	}

	return t.layout[x][y], nil
}

func (t *Terrain) SetHeight(x uint16, y uint16, height uint16) (err error) {
	if x > t.Max-1 || y > t.Max-1 {
		return errors.New("Index out of range")
	}

	t.layout[x][y] = height

	return nil
}
<commit_msg>Making the layout of the terrain a singly-indexed array<commit_after>package terrain

import (
	"errors"
	"fmt"
	"math"
)

type Terrain struct {
	layout    []uint16
	Max       uint16
	MaxHeight uint16
}

func New(scale uint16, max_height uint16) *Terrain {
	max := uint16(math.Exp2(float64(scale)) + 1)
	t := Terrain{Max: max, layout: make([]uint16, int64(max)*int64(max)), MaxHeight: max_height}
	return &t
}

func (t *Terrain) GetHeight(x uint16, y uint16) (num uint16, err error) {
	// Below-zero is unrepresentable by unsigned ints
	if x > t.Max-1 || y > t.Max-1 {
		return 0, errors.New("Index out of range")
	}
	index := x*(t.Max-1) + y

	return t.layout[index], nil
}

func (t *Terrain) SetHeight(x uint16, y uint16, height uint16) (err error) {
	if x > t.Max-1 || y > t.Max-1 {
		return errors.New(fmt.Sprintf("%d,%d is out of range (max %d)", x, y, t.Max))
	}
	index := x*(t.Max-1) + y

	t.layout[index] = height

	return nil
}
<|endoftext|>


<commit_before>package jsonpatch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

const (
	eRaw = iota
	eDoc = iota
	eAry = iota
)

type lazyNode struct {
	raw   *json.RawMessage
	doc   partialDoc
	ary   partialArray
	which int
}

type operation map[string]*json.RawMessage
type Patch []operation

type partialDoc map[string]*lazyNode
type partialArray []*lazyNode

type container interface {
	get(key string) (*lazyNode, error)
	set(key string, val *lazyNode) error
	remove(key string) error
}

func newLazyNode(raw *json.RawMessage) *lazyNode {
	return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
}

func (n *lazyNode) MarshalJSON() ([]byte, error) {
	switch n.which {
	case eRaw:
		return *n.raw, nil
	case eDoc:
		return json.Marshal(n.doc)
	case eAry:
		return json.Marshal(n.ary)
	default:
		return nil, fmt.Errorf("Unknown type")
	}
}

func (n *lazyNode) UnmarshalJSON(data []byte) error {
	dest := make(json.RawMessage, len(data))
	copy(dest, data)
	n.raw = &dest
	n.which = eRaw
	return nil
}

func (n *lazyNode) intoDoc() (*partialDoc, error) {
	if n.which == eDoc {
		return &n.doc, nil
	}

	err := json.Unmarshal(*n.raw, &n.doc)

	if err != nil {
		return nil, err
	}

	n.which = eDoc
	return &n.doc, nil
}

func (n *lazyNode) intoAry() (*partialArray, error) {
	if n.which == eAry {
		return &n.ary, nil
	}

	err := json.Unmarshal(*n.raw, &n.ary)

	if err != nil {
		return nil, err
	}

	n.which = eAry
	return &n.ary, nil
}

func (n *lazyNode) compact() []byte {
	buf := new(bytes.Buffer)

	err := json.Compact(buf, *n.raw)

	if err != nil {
		return *n.raw
	}

	return buf.Bytes()
}

func (n *lazyNode) tryDoc() bool {
	err := json.Unmarshal(*n.raw, &n.doc)

	if err != nil {
		return false
	}

	n.which = eDoc
	return true
}

func (n *lazyNode) tryAry() bool {
	err := json.Unmarshal(*n.raw, &n.ary)

	if err != nil {
		return false
	}

	n.which = eAry
	return true
}

func (n *lazyNode) equal(o *lazyNode) bool {
	if n.which == eRaw {
		if !n.tryDoc() && !n.tryAry() {
			if o.which != eRaw {
				return false
			}

			return bytes.Equal(n.compact(), o.compact())
		}
	}

	if n.which == eDoc {
		if o.which == eRaw {
			if !o.tryDoc() {
				return false
			}
		}

		if o.which != eDoc {
			return false
		}

		for k, v := range n.doc {
			ov, ok := o.doc[k]

			if !ok {
				return false
			}

			if !v.equal(ov) {
				return false
			}
		}

		return true
	}

	if o.which != eAry && !o.tryAry() {
		return false
	}

	if len(n.ary) != len(o.ary) {
		return false
	}

	for idx, val := range n.ary {
		if !val.equal(o.ary[idx]) {
			return false
		}
	}

	return true
}

func (o operation) kind() string {
	if obj, ok := o["op"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) path() string {
	if obj, ok := o["path"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) from() string {
	if obj, ok := o["from"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) value() *lazyNode {
	if obj, ok := o["value"]; ok {
		return newLazyNode(obj)
	}

	return nil
}

func isArray(buf []byte) bool {
	for _, c := range buf {
		switch c {
		case ' ':
		case '\n':
		case '\t':
			continue
		case '[':
			return true
		default:
			break
		}
	}

	return false
}

func findObject(doc *partialDoc, path string) (container, string) {
	split := strings.Split(path, "/")

	parts := split[1 : len(split)-1]

	key := split[len(split)-1]

	var err error

	for idx, part := range parts {
		next, ok := (*doc)[part]
		if !ok {
			return nil, ""
		}

		if isArray(*next.raw) {
			if idx == len(parts)-1 {
				ary, err := next.intoAry()

				if err != nil {
					return nil, ""
				}

				return ary, key
			} else {
				return nil, ""
			}
		} else {
			doc, err = next.intoDoc()

			if err != nil {
				return nil, ""
			}
		}
	}

	return doc, key
}

func (d *partialDoc) set(key string, val *lazyNode) error {
	(*d)[key] = val
	return nil
}

func (d *partialDoc) get(key string) (*lazyNode, error) {
	return (*d)[key], nil
}

func (d *partialDoc) remove(key string) error {
	delete(*d, key)
	return nil
}

func (d *partialArray) set(key string, val *lazyNode) error {
	if key == "-" {
		*d = append(*d, val)
		return nil
	}

	idx, err := strconv.Atoi(key)

	if err != nil {
		return err
	}

	ary := make([]*lazyNode, len(*d)+1)

	cur := *d

	copy(ary[0:idx], cur[0:idx])
	ary[idx] = val
	copy(ary[idx+1:], cur[idx:])

	*d = ary
	return nil
}

func (d *partialArray) get(key string) (*lazyNode, error) {
	idx, err := strconv.Atoi(key)

	if err != nil {
		return nil, err
	}

	return (*d)[idx], nil
}

func (d *partialArray) remove(key string) error {
	idx, err := strconv.Atoi(key)

	if err != nil {
		return err
	}

	cur := *d

	ary := make([]*lazyNode, len(cur)-1)

	copy(ary[0:idx], cur[0:idx])
	copy(ary[idx:], cur[idx+1:])

	*d = ary
	return nil

}

func (p Patch) add(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	if con == nil {
		return fmt.Errorf("Missing container: %s", path)
	}

	con.set(key, op.value())

	return nil
}

func (p Patch) remove(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	return con.remove(key)
}

func (p Patch) replace(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	con.set(key, op.value())

	return nil
}

func (p Patch) move(doc *partialDoc, op operation) error {
	from := op.from()

	con, key := findObject(doc, from)

	val, err := con.get(key)

	if err != nil {
		return err
	}

	con.remove(key)

	path := op.path()

	con, key = findObject(doc, path)

	con.set(key, val)

	return nil
}

var eTestFailed = fmt.Errorf("Testing value failed")

func (p Patch) test(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	val, err := con.get(key)

	if err != nil {
		return err
	}

	if val.equal(op.value()) {
		return nil
	}

	return eTestFailed
}

// Indicate if 2 JSON documents have the same structural equality
func Equal(a, b []byte) bool {
	ra := make(json.RawMessage, len(a))
	copy(ra, a)
	la := newLazyNode(&ra)

	rb := make(json.RawMessage, len(b))
	copy(rb, b)
	lb := newLazyNode(&rb)

	return la.equal(lb)
}

// Given a JSON document `doc`, treat it like a document
// conforming to RFC6902 and decode it.
func DecodePatch(buf []byte) (Patch, error) {
	var p Patch

	err := json.Unmarshal(buf, &p)

	if err != nil {
		return nil, err
	}

	return p, nil
}

// Mutate a JSON document according to the patch and return
// the new document
func (p Patch) Apply(doc []byte) ([]byte, error) {
	pd := new(partialDoc)

	err := json.Unmarshal(doc, pd)

	if err != nil {
		return nil, err
	}

	err = nil

	for _, op := range p {
		switch op.kind() {
		case "add":
			err = p.add(pd, op)
		case "remove":
			err = p.remove(pd, op)
		case "replace":
			err = p.replace(pd, op)
		case "move":
			err = p.move(pd, op)
		case "test":
			err = p.test(pd, op)
		default:
			err = fmt.Errorf("Unexpected kind: %s", op.kind())
		}

		if err != nil {
			return nil, err
		}
	}

	return json.Marshal(pd)
}
<commit_msg>Handle null's properly in equality test<commit_after>package jsonpatch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

const (
	eRaw = iota
	eDoc = iota
	eAry = iota
)

type lazyNode struct {
	raw   *json.RawMessage
	doc   partialDoc
	ary   partialArray
	which int
}

type operation map[string]*json.RawMessage
type Patch []operation

type partialDoc map[string]*lazyNode
type partialArray []*lazyNode

type container interface {
	get(key string) (*lazyNode, error)
	set(key string, val *lazyNode) error
	remove(key string) error
}

func newLazyNode(raw *json.RawMessage) *lazyNode {
	return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
}

func (n *lazyNode) MarshalJSON() ([]byte, error) {
	switch n.which {
	case eRaw:
		return *n.raw, nil
	case eDoc:
		return json.Marshal(n.doc)
	case eAry:
		return json.Marshal(n.ary)
	default:
		return nil, fmt.Errorf("Unknown type")
	}
}

func (n *lazyNode) UnmarshalJSON(data []byte) error {
	dest := make(json.RawMessage, len(data))
	copy(dest, data)
	n.raw = &dest
	n.which = eRaw
	return nil
}

func (n *lazyNode) intoDoc() (*partialDoc, error) {
	if n.which == eDoc {
		return &n.doc, nil
	}

	err := json.Unmarshal(*n.raw, &n.doc)

	if err != nil {
		return nil, err
	}

	n.which = eDoc
	return &n.doc, nil
}

func (n *lazyNode) intoAry() (*partialArray, error) {
	if n.which == eAry {
		return &n.ary, nil
	}

	err := json.Unmarshal(*n.raw, &n.ary)

	if err != nil {
		return nil, err
	}

	n.which = eAry
	return &n.ary, nil
}

func (n *lazyNode) compact() []byte {
	buf := new(bytes.Buffer)

	err := json.Compact(buf, *n.raw)

	if err != nil {
		return *n.raw
	}

	return buf.Bytes()
}

func (n *lazyNode) tryDoc() bool {
	err := json.Unmarshal(*n.raw, &n.doc)

	if err != nil {
		return false
	}

	n.which = eDoc
	return true
}

func (n *lazyNode) tryAry() bool {
	err := json.Unmarshal(*n.raw, &n.ary)

	if err != nil {
		return false
	}

	n.which = eAry
	return true
}

func (n *lazyNode) equal(o *lazyNode) bool {
	if n.which == eRaw {
		if !n.tryDoc() && !n.tryAry() {
			if o.which != eRaw {
				return false
			}

			return bytes.Equal(n.compact(), o.compact())
		}
	}

	if n.which == eDoc {
		if o.which == eRaw {
			if !o.tryDoc() {
				return false
			}
		}

		if o.which != eDoc {
			return false
		}

		for k, v := range n.doc {
			ov, ok := o.doc[k]

			if !ok {
				return false
			}

			if v == nil && ov == nil {
				continue
			}

			if !v.equal(ov) {
				return false
			}
		}

		return true
	}

	if o.which != eAry && !o.tryAry() {
		return false
	}

	if len(n.ary) != len(o.ary) {
		return false
	}

	for idx, val := range n.ary {
		if !val.equal(o.ary[idx]) {
			return false
		}
	}

	return true
}

func (o operation) kind() string {
	if obj, ok := o["op"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) path() string {
	if obj, ok := o["path"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) from() string {
	if obj, ok := o["from"]; ok {
		var op string

		err := json.Unmarshal(*obj, &op)

		if err != nil {
			return "unknown"
		}

		return op
	}

	return "unknown"
}

func (o operation) value() *lazyNode {
	if obj, ok := o["value"]; ok {
		return newLazyNode(obj)
	}

	return nil
}

func isArray(buf []byte) bool {
	for _, c := range buf {
		switch c {
		case ' ':
		case '\n':
		case '\t':
			continue
		case '[':
			return true
		default:
			break
		}
	}

	return false
}

func findObject(doc *partialDoc, path string) (container, string) {
	split := strings.Split(path, "/")

	parts := split[1 : len(split)-1]

	key := split[len(split)-1]

	var err error

	for idx, part := range parts {
		next, ok := (*doc)[part]
		if !ok {
			return nil, ""
		}

		if isArray(*next.raw) {
			if idx == len(parts)-1 {
				ary, err := next.intoAry()

				if err != nil {
					return nil, ""
				}

				return ary, key
			} else {
				return nil, ""
			}
		} else {
			doc, err = next.intoDoc()

			if err != nil {
				return nil, ""
			}
		}
	}

	return doc, key
}

func (d *partialDoc) set(key string, val *lazyNode) error {
	(*d)[key] = val
	return nil
}

func (d *partialDoc) get(key string) (*lazyNode, error) {
	return (*d)[key], nil
}

func (d *partialDoc) remove(key string) error {
	delete(*d, key)
	return nil
}

func (d *partialArray) set(key string, val *lazyNode) error {
	if key == "-" {
		*d = append(*d, val)
		return nil
	}

	idx, err := strconv.Atoi(key)

	if err != nil {
		return err
	}

	ary := make([]*lazyNode, len(*d)+1)

	cur := *d

	copy(ary[0:idx], cur[0:idx])
	ary[idx] = val
	copy(ary[idx+1:], cur[idx:])

	*d = ary
	return nil
}

func (d *partialArray) get(key string) (*lazyNode, error) {
	idx, err := strconv.Atoi(key)

	if err != nil {
		return nil, err
	}

	return (*d)[idx], nil
}

func (d *partialArray) remove(key string) error {
	idx, err := strconv.Atoi(key)

	if err != nil {
		return err
	}

	cur := *d

	ary := make([]*lazyNode, len(cur)-1)

	copy(ary[0:idx], cur[0:idx])
	copy(ary[idx:], cur[idx+1:])

	*d = ary
	return nil

}

func (p Patch) add(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	if con == nil {
		return fmt.Errorf("Missing container: %s", path)
	}

	con.set(key, op.value())

	return nil
}

func (p Patch) remove(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	return con.remove(key)
}

func (p Patch) replace(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	con.set(key, op.value())

	return nil
}

func (p Patch) move(doc *partialDoc, op operation) error {
	from := op.from()

	con, key := findObject(doc, from)

	val, err := con.get(key)

	if err != nil {
		return err
	}

	con.remove(key)

	path := op.path()

	con, key = findObject(doc, path)

	con.set(key, val)

	return nil
}

var eTestFailed = fmt.Errorf("Testing value failed")

func (p Patch) test(doc *partialDoc, op operation) error {
	path := op.path()

	con, key := findObject(doc, path)

	val, err := con.get(key)

	if err != nil {
		return err
	}

	if val.equal(op.value()) {
		return nil
	}

	return eTestFailed
}

// Indicate if 2 JSON documents have the same structural equality
func Equal(a, b []byte) bool {
	ra := make(json.RawMessage, len(a))
	copy(ra, a)
	la := newLazyNode(&ra)

	rb := make(json.RawMessage, len(b))
	copy(rb, b)
	lb := newLazyNode(&rb)

	return la.equal(lb)
}

// Given a JSON document `doc`, treat it like a document
// conforming to RFC6902 and decode it.
func DecodePatch(buf []byte) (Patch, error) {
	var p Patch

	err := json.Unmarshal(buf, &p)

	if err != nil {
		return nil, err
	}

	return p, nil
}

// Mutate a JSON document according to the patch and return
// the new document
func (p Patch) Apply(doc []byte) ([]byte, error) {
	pd := new(partialDoc)

	err := json.Unmarshal(doc, pd)

	if err != nil {
		return nil, err
	}

	err = nil

	for _, op := range p {
		switch op.kind() {
		case "add":
			err = p.add(pd, op)
		case "remove":
			err = p.remove(pd, op)
		case "replace":
			err = p.replace(pd, op)
		case "move":
			err = p.move(pd, op)
		case "test":
			err = p.test(pd, op)
		default:
			err = fmt.Errorf("Unexpected kind: %s", op.kind())
		}

		if err != nil {
			return nil, err
		}
	}

	return json.Marshal(pd)
}
<|endoftext|>


<commit_before>package dockerclient

import (
	"fmt"
	"github.com/dynport/dgtk/dockerclient/docker"
	"io"
	"net/url"
)

// Get a list of all ontainers available on the host.
func (dh *DockerHost) Containers() (containers []*docker.Container, e error) {
	e = dh.getJSON(dh.url()+"/containers/json", &containers)
	return containers, e
}

// Get the information for the container with the given id.
func (dh *DockerHost) Container(containerId string) (containerInfo *docker.ContainerInfo, e error) {
	containerInfo = &docker.ContainerInfo{}
	e = dh.getJSON(dh.url()+"/containers/"+containerId+"/json", containerInfo)
	return containerInfo, e
}

// For the given image name and the given container configuration, create a container. If the image name deosn't contain
// a tag "latest" is used by default.
func (dh *DockerHost) CreateContainer(imageName string, options *docker.ContainerConfig, name string) (containerId string, e error) {
	// Verify image available on host.
	_, e = dh.ImageHistory(imageName)
	if e != nil && e.Error() == "resource not found" {
		if e = dh.PullImage(imageName); e != nil {
			return "", e
		}
	}

	if options == nil {
		options = &docker.ContainerConfig{}
	}
	options.Image = imageName

	container := &docker.Container{}
	u := dh.url() + "/containers/create"
	if name != "" {
		u += "?" + (url.Values{"name": []string{name}}).Encode()
	}
	content, _, e := dh.postJSON(u, options, container)
	if e != nil {
		return "", fmt.Errorf("failed creating container (%s): %s", e.Error(), content)
	}
	return container.Id, e
}

// Start the container with the given identifier. The hostConfig can safely be set to nil to use the defaults.
func (dh *DockerHost) StartContainer(containerId string, hostConfig *docker.HostConfig) (e error) {
	if hostConfig == nil {
		hostConfig = &docker.HostConfig{}
	}
	body, rsp, e := dh.postJSON(dh.url()+"/containers/"+containerId+"/start", hostConfig, nil)
	if e != nil {
		return e
	}
	if rsp.StatusCode < 200 || rsp.StatusCode >= 300 {
		return fmt.Errorf("error starting container %s: status=%s, response=%s", containerId, rsp.StatusCode, string(body))
	}
	return nil
}

// Kill the container with the given identifier.
func (dh *DockerHost) StopContainer(containerId string) (e error) {
	rsp, e := dh.post(dh.url() + "/containers/" + containerId + "/kill")
	defer rsp.Body.Close()
	return e
}

type AttachOptions struct {
	Logs   bool
	Stream bool
	Stdout io.Writer
	Stderr io.Writer
}

func (opts *AttachOptions) Encode() string {
	v := url.Values{}
	if opts.Logs {
		v.Add("logs", "1")
	}
	if opts.Stream {
		v.Add("stream", "1")
	}
	if opts.Stdout != nil {
		v.Add("stdout", "1")
	}
	if opts.Stderr != nil {
		v.Add("stderr", "1")
	}
	if len(v) > 0 {
		return "?" + v.Encode()
	}
	return ""
}

func messageLength(header []byte) int {
	msgLength := int(header[7]) << 0
	msgLength += int(header[6]) << 8
	msgLength += int(header[5]) << 16
	msgLength += int(header[4]) << 24
	return msgLength
}

// See http://docs.docker.io/en/latest/api/docker_remote_api_v1.8/#attach-to-a-container for the stream protocol.
func handleMessages(r io.Reader, stdout io.Writer, stderr io.Writer) error {
	headerBuf := make([]byte, 8)
	for {
		n, e := r.Read(headerBuf)
		if e != nil {
			if e == io.EOF {
				return nil
			}
			return e
		}
		if n != 8 {
			return fmt.Errorf("failed reading; header to short")
		}

		msgLength := messageLength(headerBuf)
		msgBuf := make([]byte, msgLength) // buffer size taken from io.Copy
		n = 0
		for n < msgLength {
			i, e := r.Read(msgBuf[n:])
			if e != nil {
				return e
			}
			n += i
		}

		switch headerBuf[0] {
		case 0: // stdin
			if stdout != nil {
				_, _ = stdout.Write([]byte{'+'})
			}
			fallthrough
		case 1: // stdout
			if stdout != nil {
				_, e := stdout.Write(msgBuf[:msgLength])
				if e != nil {
					return e
				}
			}
		case 2: // stderr
			if stderr != nil {
				_, e := stderr.Write(msgBuf[:msgLength])
				if e != nil {
					return e
				}
			}
		default:
			return fmt.Errorf("unknown stream source received")
		}
	}
	return nil
}

// Attach to the given container with the given writer.
func (dh *DockerHost) AttachContainer(containerId string, opts *AttachOptions) (e error) {
	if opts == nil {
		opts = &AttachOptions{}
	}
	rsp, e := dh.post(dh.url() + "/containers/" + containerId + "/attach" + opts.Encode())
	if e != nil {
		return e
	}
	defer rsp.Body.Close()

	return handleMessages(rsp.Body, opts.Stdout, opts.Stderr)
}
<commit_msg>add ListContainers method (with options)<commit_after>package dockerclient

import (
	"fmt"
	"github.com/dynport/dgtk/dockerclient/docker"
	"io"
	"net/http"
	"net/url"
	"strconv"
)

type ListContainersOptions struct {
	All    bool
	Limit  int
	Since  string
	Before string
	Size   bool
}

func (opts *ListContainersOptions) Encode() string {
	values := url.Values{}
	if opts.All {
		values.Add("all", "true")
	}
	if opts.Limit > 0 {
		values.Add("limit", strconv.Itoa(opts.Limit))
	}
	if opts.Since != "" {
		values.Add("since", opts.Since)
	}
	if opts.Before != "" {
		values.Add("before", opts.Before)
	}
	if opts.Size {
		values.Add("size", "true")
	}

	if len(values) > 0 {
		return values.Encode()
	}
	return ""
}

// Get a list of all ontainers available on the host.
func (dh *DockerHost) Containers() (containers []*docker.Container, e error) {
	return dh.ListContainers(nil)
}

func (dh *DockerHost) ListContainers(opts *ListContainersOptions) (containers []*docker.Container, e error) {
	u := dh.url() + "/containers/json"
	if opts != nil {
		if params := opts.Encode(); params != "" {
			u += "?" + params
		}
	}
	e = dh.getJSON(u, &containers)
	return containers, e
}

// Get the information for the container with the given id.
func (dh *DockerHost) Container(containerId string) (containerInfo *docker.ContainerInfo, e error) {
	containerInfo = &docker.ContainerInfo{}
	e = dh.getJSON(dh.url()+"/containers/"+containerId+"/json", containerInfo)
	return containerInfo, e
}

// For the given image name and the given container configuration, create a container. If the image name deosn't contain
// a tag "latest" is used by default.
func (dh *DockerHost) CreateContainer(imageName string, options *docker.ContainerConfig, name string) (containerId string, e error) {
	// Verify image available on host.
	_, e = dh.ImageHistory(imageName)
	if e != nil && e.Error() == "resource not found" {
		if e = dh.PullImage(imageName); e != nil {
			return "", e
		}
	}

	if options == nil {
		options = &docker.ContainerConfig{}
	}
	options.Image = imageName

	container := &docker.Container{}
	u := dh.url() + "/containers/create"
	if name != "" {
		u += "?" + (url.Values{"name": []string{name}}).Encode()
	}
	content, _, e := dh.postJSON(u, options, container)
	if e != nil {
		return "", fmt.Errorf("failed creating container (%s): %s", e.Error(), content)
	}
	return container.Id, e
}

// Start the container with the given identifier. The hostConfig can safely be set to nil to use the defaults.
func (dh *DockerHost) StartContainer(containerId string, hostConfig *docker.HostConfig) (e error) {
	if hostConfig == nil {
		hostConfig = &docker.HostConfig{}
	}
	body, rsp, e := dh.postJSON(dh.url()+"/containers/"+containerId+"/start", hostConfig, nil)
	if e != nil {
		return e
	}
	if rsp.StatusCode < 200 || rsp.StatusCode >= 300 {
		return fmt.Errorf("error starting container %s: status=%s, response=%s", containerId, rsp.StatusCode, string(body))
	}
	return nil
}

// Kill the container with the given identifier.
func (dh *DockerHost) StopContainer(containerId string) (e error) {
	rsp, e := dh.post(dh.url() + "/containers/" + containerId + "/kill")
	defer rsp.Body.Close()
	return e
}

type AttachOptions struct {
	Logs   bool
	Stream bool
	Stdout io.Writer
	Stderr io.Writer
}

func (opts *AttachOptions) Encode() string {
	v := url.Values{}
	if opts.Logs {
		v.Add("logs", "1")
	}
	if opts.Stream {
		v.Add("stream", "1")
	}
	if opts.Stdout != nil {
		v.Add("stdout", "1")
	}
	if opts.Stderr != nil {
		v.Add("stderr", "1")
	}
	if len(v) > 0 {
		return "?" + v.Encode()
	}
	return ""
}

func messageLength(header []byte) int {
	msgLength := int(header[7]) << 0
	msgLength += int(header[6]) << 8
	msgLength += int(header[5]) << 16
	msgLength += int(header[4]) << 24
	return msgLength
}

// See http://docs.docker.io/en/latest/api/docker_remote_api_v1.8/#attach-to-a-container for the stream protocol.
func handleMessages(r io.Reader, stdout io.Writer, stderr io.Writer) error {
	headerBuf := make([]byte, 8)
	for {
		n, e := r.Read(headerBuf)
		if e != nil {
			if e == io.EOF {
				return nil
			}
			return e
		}
		if n != 8 {
			return fmt.Errorf("failed reading; header to short")
		}

		msgLength := messageLength(headerBuf)
		msgBuf := make([]byte, msgLength) // buffer size taken from io.Copy
		n = 0
		for n < msgLength {
			i, e := r.Read(msgBuf[n:])
			if e != nil {
				return e
			}
			n += i
		}

		switch headerBuf[0] {
		case 0: // stdin
			if stdout != nil {
				_, _ = stdout.Write([]byte{'+'})
			}
			fallthrough
		case 1: // stdout
			if stdout != nil {
				_, e := stdout.Write(msgBuf[:msgLength])
				if e != nil {
					return e
				}
			}
		case 2: // stderr
			if stderr != nil {
				_, e := stderr.Write(msgBuf[:msgLength])
				if e != nil {
					return e
				}
			}
		default:
			return fmt.Errorf("unknown stream source received")
		}
	}
	return nil
}

// Attach to the given container with the given writer.
func (dh *DockerHost) AttachContainer(containerId string, opts *AttachOptions) (e error) {
	if opts == nil {
		opts = &AttachOptions{}
	}
	rsp, e := dh.post(dh.url() + "/containers/" + containerId + "/attach" + opts.Encode())
	if e != nil {
		return e
	}
	defer rsp.Body.Close()

	return handleMessages(rsp.Body, opts.Stdout, opts.Stderr)
}
<|endoftext|>


<commit_before>package dockerclient

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"

	"github.com/dynport/dgtk/dockerclient/docker"
)

type ListContainersOptions struct {
	All    bool
	Limit  int
	Since  string
	Before string
	Size   bool
}

func (opts *ListContainersOptions) Encode() string {
	values := url.Values{}
	if opts.All {
		values.Add("all", "true")
	}
	if opts.Limit > 0 {
		values.Add("limit", strconv.Itoa(opts.Limit))
	}
	if opts.Since != "" {
		values.Add("since", opts.Since)
	}
	if opts.Before != "" {
		values.Add("before", opts.Before)
	}
	if opts.Size {
		values.Add("size", "true")
	}

	if len(values) > 0 {
		return values.Encode()
	}
	return ""
}

// Get a list of all ontainers available on the host.
func (dh *DockerHost) Containers() (containers []*docker.Container, e error) {
	return dh.ListContainers(nil)
}

func (dh *DockerHost) ListContainers(opts *ListContainersOptions) (containers []*docker.Container, e error) {
	u := dh.url() + "/containers/json"
	if opts != nil {
		if params := opts.Encode(); params != "" {
			u += "?" + params
		}
	}
	e = dh.getJSON(u, &containers)
	return containers, e
}

// Get the information for the container with the given id.
func (dh *DockerHost) Container(containerId string) (containerInfo *docker.ContainerInfo, e error) {
	containerInfo = &docker.ContainerInfo{}
	e = dh.getJSON(dh.url()+"/containers/"+containerId+"/json", containerInfo)
	return containerInfo, e
}

// For the given image name and the given container configuration, create a container. If the image name deosn't contain
// a tag "latest" is used by default.
func (dh *DockerHost) CreateContainer(options *docker.ContainerConfig, name string) (containerId string, e error) {
	imageId := options.Image

	// Verify image available on host.
	_, e = dh.ImageHistory(imageId)
	if e != nil && e.Error() == "resource not found" {
		if e = dh.PullImage(imageId); e != nil {
			return "", e
		}
	}

	container := &docker.Container{}
	u := dh.url() + "/containers/create"

	if name != "" {
		u += "?name=" + name
	}

	if _, e = dh.postJSON(u, options, container); e != nil {
		return "", fmt.Errorf("failed creating container: %s", e.Error())
	}
	return container.Id, e
}

// Start the container with the given identifier. The hostConfig can safely be set to nil to use the defaults.
func (dh *DockerHost) StartContainer(containerId string, hostConfig *docker.HostConfig) (e error) {
	if hostConfig == nil {
		hostConfig = &docker.HostConfig{}
	}
	_, e = dh.postJSON(dh.url()+"/containers/"+containerId+"/start", hostConfig, nil)
	return e
}

func (dh *DockerHost) RemoveContainer(containerId string) error {
	req, e := http.NewRequest("DELETE", dh.url()+"/containers/"+containerId, nil)
	if e != nil {
		return e
	}
	rsp, e := dh.httpClient.Do(req)
	if e != nil {
		return e
	}
	if rsp.Status[0] != '2' {
		return fmt.Errorf("expected status 2xx but got %s", rsp.Status)
	}
	return nil
}

// Kill the container with the given identifier.
func (dh *DockerHost) StopContainer(containerId string) (e error) {
	rsp, e := dh.post(dh.url() + "/containers/" + containerId + "/kill")
	defer rsp.Body.Close()
	return e
}

type AttachOptions struct {
	Logs   bool
	Stream bool
	Stdout io.Writer
	Stderr io.Writer
}

func (opts *AttachOptions) Encode() string {
	v := url.Values{}
	if opts.Logs {
		v.Add("logs", "1")
	}
	if opts.Stream {
		v.Add("stream", "1")
	}
	if opts.Stdout != nil {
		v.Add("stdout", "1")
	}
	if opts.Stderr != nil {
		v.Add("stderr", "1")
	}
	if len(v) > 0 {
		return "?" + v.Encode()
	}
	return ""
}

func messageLength(header []byte) int {
	msgLength := int(header[7]) << 0
	msgLength += int(header[6]) << 8
	msgLength += int(header[5]) << 16
	msgLength += int(header[4]) << 24
	return msgLength
}

// See http://docs.docker.io/en/latest/api/docker_remote_api_v1.8/#attach-to-a-container for the stream protocol.
func handleMessages(r io.Reader, stdout io.Writer, stderr io.Writer) error {
	headerBuf := make([]byte, 8)
	for {
		n, e := r.Read(headerBuf)
		if e != nil {
			if e == io.EOF {
				return nil
			}
			return e
		}
		if n != 8 {
			return fmt.Errorf("failed reading; header to short")
		}

		msgLength := messageLength(headerBuf)
		msgBuf := make([]byte, msgLength) // buffer size taken from io.Copy
		n = 0
		for n < msgLength {
			i, e := r.Read(msgBuf[n:])
			if e != nil {
				return e
			}
			n += i
		}

		switch headerBuf[0] {
		case 0: // stdin
			if stdout != nil {
				_, _ = stdout.Write([]byte{'+'})
			}
		case 1: // stdout
			if stdout != nil {
				_, e := stdout.Write(msgBuf[:msgLength])
				if e != nil {
					return e
				}
			}
		case 2: // stderr
			if stderr != nil {
				_, e := stderr.Write(msgBuf[:msgLength])
				if e != nil {
					return e
				}
			}
		default:
			return fmt.Errorf("unknown stream source received")
		}
	}
}

// Attach to the given container with the given writer.
func (dh *DockerHost) AttachContainer(containerId string, opts *AttachOptions) (e error) {
	if opts == nil {
		opts = &AttachOptions{}
	}
	rsp, e := dh.post(dh.url() + "/containers/" + containerId + "/attach" + opts.Encode())
	if e != nil {
		return e
	}
	defer rsp.Body.Close()

	return handleMessages(rsp.Body, opts.Stdout, opts.Stderr)
}
<commit_msg>added docker image info to container environment<commit_after>package dockerclient

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"

	"github.com/dynport/dgtk/dockerclient/docker"
)

type ListContainersOptions struct {
	All    bool
	Limit  int
	Since  string
	Before string
	Size   bool
}

func (opts *ListContainersOptions) Encode() string {
	values := url.Values{}
	if opts.All {
		values.Add("all", "true")
	}
	if opts.Limit > 0 {
		values.Add("limit", strconv.Itoa(opts.Limit))
	}
	if opts.Since != "" {
		values.Add("since", opts.Since)
	}
	if opts.Before != "" {
		values.Add("before", opts.Before)
	}
	if opts.Size {
		values.Add("size", "true")
	}

	if len(values) > 0 {
		return values.Encode()
	}
	return ""
}

// Get a list of all ontainers available on the host.
func (dh *DockerHost) Containers() (containers []*docker.Container, e error) {
	return dh.ListContainers(nil)
}

func (dh *DockerHost) ListContainers(opts *ListContainersOptions) (containers []*docker.Container, e error) {
	u := dh.url() + "/containers/json"
	if opts != nil {
		if params := opts.Encode(); params != "" {
			u += "?" + params
		}
	}
	e = dh.getJSON(u, &containers)
	return containers, e
}

// Get the information for the container with the given id.
func (dh *DockerHost) Container(containerId string) (containerInfo *docker.ContainerInfo, e error) {
	containerInfo = &docker.ContainerInfo{}
	e = dh.getJSON(dh.url()+"/containers/"+containerId+"/json", containerInfo)
	return containerInfo, e
}

// For the given image name and the given container configuration, create a container. If the image name deosn't contain
// a tag "latest" is used by default.
func (dh *DockerHost) CreateContainer(options *docker.ContainerConfig, name string) (containerId string, e error) {
	imageId := options.Image

	// Verify image available on host.
	_, e = dh.ImageHistory(imageId)
	if e != nil && e.Error() == "resource not found" {
		if e = dh.PullImage(imageId); e != nil {
			return "", e
		}
	}

	imgDetails, err := dh.ImageDetails(imageId)
	if err != nil {
		return "", err
	}
	options.Env = append(options.Env, "DOCKER_IMAGE="+imgDetails.Id)

	container := &docker.Container{}
	u := dh.url() + "/containers/create"

	if name != "" {
		u += "?name=" + name
	}

	if _, e = dh.postJSON(u, options, container); e != nil {
		return "", fmt.Errorf("failed creating container: %s", e.Error())
	}
	return container.Id, e
}

// Start the container with the given identifier. The hostConfig can safely be set to nil to use the defaults.
func (dh *DockerHost) StartContainer(containerId string, hostConfig *docker.HostConfig) (e error) {
	if hostConfig == nil {
		hostConfig = &docker.HostConfig{}
	}
	_, e = dh.postJSON(dh.url()+"/containers/"+containerId+"/start", hostConfig, nil)
	return e
}

func (dh *DockerHost) RemoveContainer(containerId string) error {
	req, e := http.NewRequest("DELETE", dh.url()+"/containers/"+containerId, nil)
	if e != nil {
		return e
	}
	rsp, e := dh.httpClient.Do(req)
	if e != nil {
		return e
	}
	if rsp.Status[0] != '2' {
		return fmt.Errorf("expected status 2xx but got %s", rsp.Status)
	}
	return nil
}

// Kill the container with the given identifier.
func (dh *DockerHost) StopContainer(containerId string) (e error) {
	rsp, e := dh.post(dh.url() + "/containers/" + containerId + "/kill")
	defer rsp.Body.Close()
	return e
}

type AttachOptions struct {
	Logs   bool
	Stream bool
	Stdout io.Writer
	Stderr io.Writer
}

func (opts *AttachOptions) Encode() string {
	v := url.Values{}
	if opts.Logs {
		v.Add("logs", "1")
	}
	if opts.Stream {
		v.Add("stream", "1")
	}
	if opts.Stdout != nil {
		v.Add("stdout", "1")
	}
	if opts.Stderr != nil {
		v.Add("stderr", "1")
	}
	if len(v) > 0 {
		return "?" + v.Encode()
	}
	return ""
}

func messageLength(header []byte) int {
	msgLength := int(header[7]) << 0
	msgLength += int(header[6]) << 8
	msgLength += int(header[5]) << 16
	msgLength += int(header[4]) << 24
	return msgLength
}

// See http://docs.docker.io/en/latest/api/docker_remote_api_v1.8/#attach-to-a-container for the stream protocol.
func handleMessages(r io.Reader, stdout io.Writer, stderr io.Writer) error {
	headerBuf := make([]byte, 8)
	for {
		n, e := r.Read(headerBuf)
		if e != nil {
			if e == io.EOF {
				return nil
			}
			return e
		}
		if n != 8 {
			return fmt.Errorf("failed reading; header to short")
		}

		msgLength := messageLength(headerBuf)
		msgBuf := make([]byte, msgLength) // buffer size taken from io.Copy
		n = 0
		for n < msgLength {
			i, e := r.Read(msgBuf[n:])
			if e != nil {
				return e
			}
			n += i
		}

		switch headerBuf[0] {
		case 0: // stdin
			if stdout != nil {
				_, _ = stdout.Write([]byte{'+'})
			}
		case 1: // stdout
			if stdout != nil {
				_, e := stdout.Write(msgBuf[:msgLength])
				if e != nil {
					return e
				}
			}
		case 2: // stderr
			if stderr != nil {
				_, e := stderr.Write(msgBuf[:msgLength])
				if e != nil {
					return e
				}
			}
		default:
			return fmt.Errorf("unknown stream source received")
		}
	}
}

// Attach to the given container with the given writer.
func (dh *DockerHost) AttachContainer(containerId string, opts *AttachOptions) (e error) {
	if opts == nil {
		opts = &AttachOptions{}
	}
	rsp, e := dh.post(dh.url() + "/containers/" + containerId + "/attach" + opts.Encode())
	if e != nil {
		return e
	}
	defer rsp.Body.Close()

	return handleMessages(rsp.Body, opts.Stdout, opts.Stderr)
}
<|endoftext|>


<commit_before>package echo

import (
	"bytes"
	"encoding/xml"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"
	"unicode"

	"github.com/webx-top/echo/encoding/json"
	"github.com/webx-top/echo/engine"
)

// Response returns *Response.
func (c *xContext) Response() engine.Response {
	return c.response
}

// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.SetRenderer()`.
func (c *xContext) Render(name string, data interface{}, codes ...int) (err error) {
	if c.auto {
		format := c.Format()
		if render, ok := c.echo.formatRenderers[format]; ok && render != nil {
			switch v := data.(type) {
			case Data: //Skip
			case error:
				c.dataEngine.SetError(v)
			case nil:
				if c.dataEngine.GetData() == nil {
					c.dataEngine.SetData(c.Stored(), c.dataEngine.GetCode().Int())
				}
			default:
				c.dataEngine.SetData(data, c.dataEngine.GetCode().Int())
			}
			return render(c, data)
		}
	}
	c.dataEngine.SetTmplFuncs()
	if data == nil {
		data = c.dataEngine.GetData()
	}
	b, err := c.Fetch(name, data)
	if err != nil {
		return
	}
	b = bytes.TrimLeftFunc(b, unicode.IsSpace)
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	err = c.Blob(b, codes...)
	return
}

// HTML sends an HTTP response with status code.
func (c *xContext) HTML(html string, codes ...int) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	err = c.Blob([]byte(html), codes...)
	return
}

// String sends a string response with status code.
func (c *xContext) String(s string, codes ...int) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextPlainCharsetUTF8)
	err = c.Blob([]byte(s), codes...)
	return
}

func (c *xContext) Blob(b []byte, codes ...int) (err error) {
	if len(codes) > 0 {
		c.code = codes[0]
	}
	if c.code == 0 {
		c.code = http.StatusOK
	}
	err = c.preResponse()
	if err != nil {
		return
	}
	c.response.WriteHeader(c.code)
	_, err = c.response.Write(b)
	return
}

// JSON sends a JSON response with status code.
func (c *xContext) JSON(i interface{}, codes ...int) (err error) {
	var b []byte
	if c.echo.Debug() {
		b, err = json.MarshalIndent(i, "", "  ")
	} else {
		b, err = json.Marshal(i)
	}
	if err != nil {
		return err
	}
	return c.JSONBlob(b, codes...)
}

// JSONBlob sends a JSON blob response with status code.
func (c *xContext) JSONBlob(b []byte, codes ...int) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8)
	err = c.Blob(b, codes...)
	return
}

// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
func (c *xContext) JSONP(callback string, i interface{}, codes ...int) (err error) {
	b, err := json.Marshal(i)
	if err != nil {
		return err
	}
	c.response.Header().Set(HeaderContentType, MIMEApplicationJavaScriptCharsetUTF8)
	b = []byte(callback + "(" + string(b) + ");")
	err = c.Blob(b, codes...)
	return
}

// XML sends an XML response with status code.
func (c *xContext) XML(i interface{}, codes ...int) (err error) {
	var b []byte
	if c.echo.Debug() {
		b, err = xml.MarshalIndent(i, "", "  ")
	} else {
		b, err = xml.Marshal(i)
	}
	if err != nil {
		return err
	}
	return c.XMLBlob(b, codes...)
}

// XMLBlob sends a XML blob response with status code.
func (c *xContext) XMLBlob(b []byte, codes ...int) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
	b = []byte(xml.Header + string(b))
	err = c.Blob(b, codes...)
	return
}

func (c *xContext) Stream(step func(w io.Writer) bool) {
	c.response.Stream(step)
}

func (c *xContext) SSEvent(event string, data chan interface{}) (err error) {
	hdr := c.response.Header()
	hdr.Set(HeaderContentType, MIMEEventStream)
	hdr.Set(`Cache-Control`, `no-cache`)
	hdr.Set(`Connection`, `keep-alive`)
	c.Stream(func(w io.Writer) bool {
		b, e := c.Fetch(event, <-data)
		if e != nil {
			err = e
			return false
		}
		_, e = w.Write(b)
		if e != nil {
			err = e
			return false
		}
		return true
	})
	return
}

func (c *xContext) Attachment(r io.Reader, name string, inline ...bool) (err error) {
	var typ string
	if len(inline) > 0 && inline[0] {
		typ = `inline`
	} else {
		typ = `attachment`
	}
	c.response.Header().Set(HeaderContentType, ContentTypeByExtension(name))
	encodedName := URLEncode(name, true)
	c.response.Header().Set(HeaderContentDisposition, typ+"; filename="+encodedName+"; filename*=utf-8''"+encodedName)
	c.response.WriteHeader(http.StatusOK)
	c.response.KeepBody(false)
	_, err = io.Copy(c.response, r)
	return
}

func (c *xContext) File(file string, fs ...http.FileSystem) (err error) {
	var f http.File
	customFS := len(fs) > 0 && fs[0] != nil
	if customFS {
		f, err = fs[0].Open(file)
	} else {
		f, err = os.Open(file)
	}
	if err != nil {
		return ErrNotFound
	}
	defer func() {
		f.Close()
	}()
	fi, err := f.Stat()
	if err != nil {
		return err
	}
	if fi.IsDir() {
		f.Close()
		file = filepath.Join(file, "index.html")
		if customFS {
			f, err = fs[0].Open(file)
		} else {
			f, err = os.Open(file)
		}
		if err != nil {
			return ErrNotFound
		}
		fi, err = f.Stat()
		if err != nil {
			return err
		}
	}
	return c.ServeContent(f, fi.Name(), fi.ModTime())
}

func (c *xContext) ServeContent(content io.Reader, name string, modtime time.Time) error {
	return c.ServeCallbackContent(func(_ Context) (io.Reader, error) {
		return content, nil
	}, name, modtime)
}

func (c *xContext) ServeCallbackContent(callback func(Context) (io.Reader, error), name string, modtime time.Time) error {
	rq := c.Request()
	rs := c.Response()

	if t, err := time.Parse(http.TimeFormat, rq.Header().Get(HeaderIfModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
		rs.Header().Del(HeaderContentType)
		rs.Header().Del(HeaderContentLength)
		return c.NoContent(http.StatusNotModified)
	}
	content, err := callback(c)
	if err != nil {
		return err
	}
	rs.Header().Set(HeaderContentType, ContentTypeByExtension(name))
	rs.Header().Set(HeaderLastModified, modtime.UTC().Format(http.TimeFormat))
	rs.WriteHeader(http.StatusOK)
	rs.KeepBody(false)
	_, err = io.Copy(rs, content)
	return err
}

// NoContent sends a response with no body and a status code.
func (c *xContext) NoContent(codes ...int) error {
	if len(codes) > 0 {
		c.code = codes[0]
	}
	if c.code == 0 {
		c.code = http.StatusOK
	}
	c.response.WriteHeader(c.code)
	return nil
}

// Redirect redirects the request with status code.
func (c *xContext) Redirect(url string, codes ...int) error {
	code := http.StatusFound
	if len(codes) > 0 {
		code = codes[0]
	}
	if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
		return ErrInvalidRedirectCode
	}
	err := c.preResponse()
	if err != nil {
		return err
	}
	format := c.Format()
	if format != `html` && c.auto {
		if render, ok := c.echo.formatRenderers[format]; ok && render != nil {
			if c.dataEngine.GetData() == nil {
				c.dataEngine.SetData(c.Stored(), c.dataEngine.GetCode().Int())
			}
			c.dataEngine.SetURL(url)
			return render(c, c.dataEngine.GetData())
		}
	}
	c.response.Redirect(url, code)
	return nil
}
<commit_msg>improved<commit_after>package echo

import (
	"bytes"
	"encoding/xml"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"
	"unicode"

	"github.com/webx-top/echo/encoding/json"
	"github.com/webx-top/echo/engine"
)

// Response returns *Response.
func (c *xContext) Response() engine.Response {
	return c.response
}

// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.SetRenderer()`.
func (c *xContext) Render(name string, data interface{}, codes ...int) (err error) {
	if c.auto {
		format := c.Format()
		if render, ok := c.echo.formatRenderers[format]; ok && render != nil {
			switch v := data.(type) {
			case Data: //Skip
			case error:
				c.dataEngine.SetError(v)
			case nil:
				if c.dataEngine.GetData() == nil {
					c.dataEngine.SetData(c.Stored(), c.dataEngine.GetCode().Int())
				}
			default:
				c.dataEngine.SetData(data, c.dataEngine.GetCode().Int())
			}
			return render(c, data)
		}
	}
	c.dataEngine.SetTmplFuncs()
	if data == nil {
		data = c.dataEngine.GetData()
	}
	b, err := c.Fetch(name, data)
	if err != nil {
		return
	}
	b = bytes.TrimLeftFunc(b, unicode.IsSpace)
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	err = c.Blob(b, codes...)
	return
}

// HTML sends an HTTP response with status code.
func (c *xContext) HTML(html string, codes ...int) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextHTMLCharsetUTF8)
	err = c.Blob([]byte(html), codes...)
	return
}

// String sends a string response with status code.
func (c *xContext) String(s string, codes ...int) (err error) {
	c.response.Header().Set(HeaderContentType, MIMETextPlainCharsetUTF8)
	err = c.Blob([]byte(s), codes...)
	return
}

func (c *xContext) Blob(b []byte, codes ...int) (err error) {
	if len(codes) > 0 {
		c.code = codes[0]
	}
	if c.code == 0 {
		c.code = http.StatusOK
	}
	err = c.preResponse()
	if err != nil {
		return
	}
	c.response.WriteHeader(c.code)
	_, err = c.response.Write(b)
	return
}

// JSON sends a JSON response with status code.
func (c *xContext) JSON(i interface{}, codes ...int) (err error) {
	var b []byte
	if c.echo.Debug() {
		b, err = json.MarshalIndent(i, "", "  ")
	} else {
		b, err = json.Marshal(i)
	}
	if err != nil {
		return err
	}
	return c.JSONBlob(b, codes...)
}

// JSONBlob sends a JSON blob response with status code.
func (c *xContext) JSONBlob(b []byte, codes ...int) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8)
	err = c.Blob(b, codes...)
	return
}

// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
func (c *xContext) JSONP(callback string, i interface{}, codes ...int) (err error) {
	b, err := json.Marshal(i)
	if err != nil {
		return err
	}
	c.response.Header().Set(HeaderContentType, MIMEApplicationJavaScriptCharsetUTF8)
	b = []byte(callback + "(" + string(b) + ");")
	err = c.Blob(b, codes...)
	return
}

// XML sends an XML response with status code.
func (c *xContext) XML(i interface{}, codes ...int) (err error) {
	var b []byte
	if c.echo.Debug() {
		b, err = xml.MarshalIndent(i, "", "  ")
	} else {
		b, err = xml.Marshal(i)
	}
	if err != nil {
		return err
	}
	return c.XMLBlob(b, codes...)
}

// XMLBlob sends a XML blob response with status code.
func (c *xContext) XMLBlob(b []byte, codes ...int) (err error) {
	c.response.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
	b = []byte(xml.Header + string(b))
	err = c.Blob(b, codes...)
	return
}

func (c *xContext) Stream(step func(w io.Writer) bool) {
	c.response.Stream(step)
}

func (c *xContext) SSEvent(event string, data chan interface{}) (err error) {
	hdr := c.response.Header()
	hdr.Set(HeaderContentType, MIMEEventStream)
	hdr.Set(`Cache-Control`, `no-cache`)
	hdr.Set(`Connection`, `keep-alive`)
	c.Stream(func(w io.Writer) bool {
		b, e := c.Fetch(event, <-data)
		if e != nil {
			err = e
			return false
		}
		_, e = w.Write(b)
		if e != nil {
			err = e
			return false
		}
		return true
	})
	return
}

func (c *xContext) Attachment(r io.Reader, name string, inline ...bool) (err error) {
	var typ string
	if len(inline) > 0 && inline[0] {
		typ = `inline`
	} else {
		typ = `attachment`
	}
	c.response.Header().Set(HeaderContentType, ContentTypeByExtension(name))
	encodedName := URLEncode(name, true)
	c.response.Header().Set(HeaderContentDisposition, typ+"; filename="+encodedName+"; filename*=utf-8''"+encodedName)
	c.response.WriteHeader(http.StatusOK)
	c.response.KeepBody(false)
	_, err = io.Copy(c.response, r)
	return
}

func (c *xContext) File(file string, fs ...http.FileSystem) (err error) {
	var f http.File
	customFS := len(fs) > 0 && fs[0] != nil
	if customFS {
		f, err = fs[0].Open(file)
	} else {
		f, err = os.Open(file)
	}
	if err != nil {
		return ErrNotFound
	}
	defer func() {
		if f != nil {
			f.Close()
		}
	}()
	fi, err := f.Stat()
	if err != nil {
		return err
	}
	if fi.IsDir() {
		f.Close()
		file = filepath.Join(file, "index.html")
		if customFS {
			f, err = fs[0].Open(file)
		} else {
			f, err = os.Open(file)
		}
		if err != nil {
			return ErrNotFound
		}
		fi, err = f.Stat()
		if err != nil {
			return err
		}
	}
	return c.ServeContent(f, fi.Name(), fi.ModTime())
}

func (c *xContext) ServeContent(content io.Reader, name string, modtime time.Time) error {
	return c.ServeCallbackContent(func(_ Context) (io.Reader, error) {
		return content, nil
	}, name, modtime)
}

func (c *xContext) ServeCallbackContent(callback func(Context) (io.Reader, error), name string, modtime time.Time) error {
	rq := c.Request()
	rs := c.Response()

	if t, err := time.Parse(http.TimeFormat, rq.Header().Get(HeaderIfModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
		rs.Header().Del(HeaderContentType)
		rs.Header().Del(HeaderContentLength)
		return c.NoContent(http.StatusNotModified)
	}
	content, err := callback(c)
	if err != nil {
		return err
	}
	rs.Header().Set(HeaderContentType, ContentTypeByExtension(name))
	rs.Header().Set(HeaderLastModified, modtime.UTC().Format(http.TimeFormat))
	rs.WriteHeader(http.StatusOK)
	rs.KeepBody(false)
	_, err = io.Copy(rs, content)
	return err
}

// NoContent sends a response with no body and a status code.
func (c *xContext) NoContent(codes ...int) error {
	if len(codes) > 0 {
		c.code = codes[0]
	}
	if c.code == 0 {
		c.code = http.StatusOK
	}
	c.response.WriteHeader(c.code)
	return nil
}

// Redirect redirects the request with status code.
func (c *xContext) Redirect(url string, codes ...int) error {
	code := http.StatusFound
	if len(codes) > 0 {
		code = codes[0]
	}
	if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
		return ErrInvalidRedirectCode
	}
	err := c.preResponse()
	if err != nil {
		return err
	}
	format := c.Format()
	if format != `html` && c.auto {
		if render, ok := c.echo.formatRenderers[format]; ok && render != nil {
			if c.dataEngine.GetData() == nil {
				c.dataEngine.SetData(c.Stored(), c.dataEngine.GetCode().Int())
			}
			c.dataEngine.SetURL(url)
			return render(c, c.dataEngine.GetData())
		}
	}
	c.response.Redirect(url, code)
	return nil
}
<|endoftext|>