<commit_before>package lexer

// Type classifies the different Tokens
type Type string

// Token classifications
const (
	Error    Type = "Error"
	EOF           = "EOF"
	Plus          = "+"
	Dash          = "-"
	Star          = "*"
	Slash         = "/"
	Question      = "?"
	Semi          = ";"
	Comma         = ","
	ParenL        = "("
	ParenR        = ")"
	BraceL        = "{"
	BraceR        = "}"
	BracketL      = "["
	BracketR      = "]"
	Colon         = ":"
	Assign        = ":="
	Arrow         = "=>"
	LT            = "<"
	GT            = ">"
	LTEquals      = "<="
	GTEquals      = ">="
	Fn            = "fn"
	If            = "if"
	Let           = "let"
	Return        = "return"
	Self          = "self"
	Use           = "use"
	Ident         = "Ident"
	Number        = "Number"
	String        = "String"
	Boolean       = "Boolean"
)

// Token is a basic syntactic unit
type Token struct {
	Type   Type
	Lexeme string
	Loc    Loc
}

// Lexer contains methods for generating a sequence of Tokens
type Lexer struct {
	buffer  []Token
	scanner *Scanner
}

// Peek returns the next token but does not advance the Lexer
func (l *Lexer) Peek() Token {
	if len(l.buffer) > 0 {
		return l.buffer[0]
	}

	tok := l.Next()
	l.buffer = append(l.buffer, tok)
	return l.buffer[0]
}

// Next returns the next token and advances the Lexer
func (l *Lexer) Next() Token {
	if len(l.buffer) > 0 {
		tok := l.buffer[0]
		l.buffer = l.buffer[1:]
		return tok
	}

	return eatToken(l.scanner)
}

// Lex creates a new Lexer struct given a Scanner
func Lex(scanner *Scanner) *Lexer {
	return &Lexer{[]Token{}, scanner}
}

func isEOF(r rune) bool {
	return (r == '\000')
}

func isWhitespace(r rune) bool {
	return (r <= ' ') && (r != '\000')
}

func isOperator(r rune) bool {
	switch r {
	case '+':
		fallthrough
	case '-':
		fallthrough
	case '*':
		fallthrough
	case '/':
		return true
	case '?':
		return true
	case ':':
		return true
	case '=':
		return true
	case '<':
		return true
	case '>':
		return true
	default:
		return false
	}
}

func isSemicolon(r rune) bool {
	return (r == ';')
}

func isComma(r rune) bool {
	return (r == ',')
}

func isParen(r rune) bool {
	return (r == '(') || (r == ')')
}

func isBrace(r rune) bool {
	return (r == '{') || (r == '}')
}

func isBracket(r rune) bool {
	return (r == '[') || (r == ']')
}

func isLetter(r rune) bool {
	return ('a' <= r && r <= 'z') || ('A' <= r && r <= 'Z')
}

func isDigit(r rune) bool {
	return ('0' <= r && r <= '9')
}

func isDoubleQuote(r rune) bool {
	return (r == '"')
}

func eatToken(scanner *Scanner) Token {
	peek := scanner.Peek()

	switch {
	case isEOF(peek.char):
		return eatEOF(scanner)
	case isWhitespace(peek.char):
		return eatWhitespace(scanner)
	case isOperator(peek.char):
		return eatOperatorToken(scanner)
	case isSemicolon(peek.char):
		return eatSemicolonToken(scanner)
	case isComma(peek.char):
		return eatCommaToken(scanner)
	case isParen(peek.char):
		return eatParenToken(scanner)
	case isBrace(peek.char):
		return eatBraceToken(scanner)
	case isBracket(peek.char):
		return eatBracketToken(scanner)
	case isLetter(peek.char):
		return eatWordToken(scanner)
	case isDigit(peek.char):
		return eatNumberToken(scanner)
	case isDoubleQuote(peek.char):
		return eatStringToken(scanner)
	default:
		return Token{Error, "unexpected symbol", peek.loc}
	}
}

func eatEOF(scanner *Scanner) Token {
	return Token{EOF, "", scanner.Peek().loc}
}

func eatWhitespace(scanner *Scanner) Token {
	for isWhitespace(scanner.Peek().char) {
		scanner.Next()
	}

	return eatToken(scanner)
}

func eatOperatorToken(scanner *Scanner) Token {
	switch scanner.Peek().char {
	case '+':
		return Token{Plus, "+", scanner.Next().loc}
	case '-':
		return Token{Dash, "-", scanner.Next().loc}
	case '*':
		return Token{Star, "*", scanner.Next().loc}
	case '/':
		return Token{Slash, "/", scanner.Next().loc}
	case '?':
		return Token{Question, "?", scanner.Next().loc}
	case ':':
		colon := scanner.Next()
		tok := Token{Colon, ":", colon.loc}

		if scanner.Peek().char == '=' {
			scanner.Next()
			tok = Token{Assign, ":=", colon.loc}
		}

		return tok
	case '=':
		equals := scanner.Next()

		if scanner.Peek().char == '>' {
			scanner.Next()
			return Token{Arrow, "=>", equals.loc}
		}

		return Token{Error, "expected operator", equals.loc}
	case '<':
		lt := scanner.Next()

		if scanner.Peek().char == '=' {
			scanner.Next()
			return Token{LTEquals, "<=", lt.loc}
		}

		return Token{LT, "<", lt.loc}
	case '>':
		gt := scanner.Next()

		if scanner.Peek().char == '=' {
			scanner.Next()
			return Token{GTEquals, ">=", gt.loc}
		}

		return Token{GT, ">", gt.loc}
	default:
		return Token{Error, "expected operator", scanner.Next().loc}
	}
}

func eatSemicolonToken(scanner *Scanner) Token {
	if scanner.Peek().char != ';' {
		return Token{Error, "expected semicolon", scanner.Next().loc}
	}

	return Token{Semi, ";", scanner.Next().loc}
}

func eatCommaToken(scanner *Scanner) Token {
	if scanner.Peek().char != ',' {
		return Token{Error, "expected comma", scanner.Next().loc}
	}

	return Token{Comma, ",", scanner.Next().loc}
}

func eatParenToken(scanner *Scanner) Token {
	switch scanner.Peek().char {
	case '(':
		return Token{ParenL, "(", scanner.Next().loc}
	case ')':
		return Token{ParenR, ")", scanner.Next().loc}
	default:
		return Token{Error, "expected paren", scanner.Next().loc}
	}
}

func eatBraceToken(scanner *Scanner) Token {
	switch scanner.Peek().char {
	case '{':
		return Token{BraceL, "{", scanner.Next().loc}
	case '}':
		return Token{BraceR, "}", scanner.Next().loc}
	default:
		return Token{Error, "expected brace", scanner.Next().loc}
	}
}

func eatBracketToken(scanner *Scanner) Token {
	switch scanner.Peek().char {
	case '[':
		return Token{BracketL, "[", scanner.Next().loc}
	case ']':
		return Token{BracketR, "]", scanner.Next().loc}
	default:
		return Token{Error, "expected bracket", scanner.Next().loc}
	}
}

func eatWordToken(scanner *Scanner) Token {
	loc := scanner.Peek().loc
	lexeme := ""

	if isLetter(scanner.Peek().char) == false {
		return Token{Error, "expected word", loc}
	}

	for isLetter(scanner.Peek().char) {
		lexeme += string(scanner.Next().char)
	}

	switch lexeme {
	case "fn":
		return Token{Fn, "fn", loc}
	case "if":
		return Token{If, "if", loc}
	case "let":
		return Token{Let, "let", loc}
	case "return":
		return Token{Return, "return", loc}
	case "self":
		return Token{Self, "self", loc}
	case "use":
		return Token{Use, "use", loc}
	case "true":
		return Token{Boolean, "true", loc}
	case "false":
		return Token{Boolean, "false", loc}
	default:
		return Token{Ident, lexeme, loc}
	}
}

func eatNumberToken(scanner *Scanner) Token {
	loc := scanner.Peek().loc
	lexeme := ""

	if isDigit(scanner.Peek().char) == false {
		return Token{Error, "expected number", loc}
	}

	for isDigit(scanner.Peek().char) {
		lexeme += string(scanner.Next().char)
	}

	return Token{Number, lexeme, loc}
}

func eatStringToken(scanner *Scanner) Token {
	loc := scanner.Peek().loc
	lexeme := ""

	if isDoubleQuote(scanner.Peek().char) == false {
		return Token{Error, "expected string", loc}
	}

	lexeme += string(scanner.Next().char)
	for {
		switch scanner.Peek().char {
		case '"':
			lexeme += string(scanner.Next().char)
			return Token{String, lexeme, loc}
		case '\000':
			fallthrough
		case '\n':
			return Token{Error, "unclosed string", scanner.Peek().loc}
		default:
			lexeme += string(scanner.Next().char)
		}
	}
}
<commit_msg>add “Filepath” property to lexer<commit_after>package lexer

// Type classifies the different Tokens
type Type string

// Token classifications
const (
	Error    Type = "Error"
	EOF           = "EOF"
	Plus          = "+"
	Dash          = "-"
	Star          = "*"
	Slash         = "/"
	Question      = "?"
	Semi          = ";"
	Comma         = ","
	ParenL        = "("
	ParenR        = ")"
	BraceL        = "{"
	BraceR        = "}"
	BracketL      = "["
	BracketR      = "]"
	Colon         = ":"
	Assign        = ":="
	Arrow         = "=>"
	LT            = "<"
	GT            = ">"
	LTEquals      = "<="
	GTEquals      = ">="
	Fn            = "fn"
	If            = "if"
	Let           = "let"
	Return        = "return"
	Self          = "self"
	Use           = "use"
	Ident         = "Ident"
	Number        = "Number"
	String        = "String"
	Boolean       = "Boolean"
)

// Token is a basic syntactic unit
type Token struct {
	Type   Type
	Lexeme string
	Loc    Loc
}

// Lexer contains methods for generating a sequence of Tokens
type Lexer struct {
	Filepath string
	buffer   []Token
	scanner  *Scanner
}

// Peek returns the next token but does not advance the Lexer
func (l *Lexer) Peek() Token {
	if len(l.buffer) > 0 {
		return l.buffer[0]
	}

	tok := l.Next()
	l.buffer = append(l.buffer, tok)
	return l.buffer[0]
}

// Next returns the next token and advances the Lexer
func (l *Lexer) Next() Token {
	if len(l.buffer) > 0 {
		tok := l.buffer[0]
		l.buffer = l.buffer[1:]
		return tok
	}

	return eatToken(l.scanner)
}

// Lex creates a new Lexer struct given a Scanner
func Lex(scanner *Scanner) *Lexer {
	return &Lexer{"", []Token{}, scanner}
}

func isEOF(r rune) bool {
	return (r == '\000')
}

func isWhitespace(r rune) bool {
	return (r <= ' ') && (r != '\000')
}

func isOperator(r rune) bool {
	switch r {
	case '+':
		fallthrough
	case '-':
		fallthrough
	case '*':
		fallthrough
	case '/':
		return true
	case '?':
		return true
	case ':':
		return true
	case '=':
		return true
	case '<':
		return true
	case '>':
		return true
	default:
		return false
	}
}

func isSemicolon(r rune) bool {
	return (r == ';')
}

func isComma(r rune) bool {
	return (r == ',')
}

func isParen(r rune) bool {
	return (r == '(') || (r == ')')
}

func isBrace(r rune) bool {
	return (r == '{') || (r == '}')
}

func isBracket(r rune) bool {
	return (r == '[') || (r == ']')
}

func isLetter(r rune) bool {
	return ('a' <= r && r <= 'z') || ('A' <= r && r <= 'Z')
}

func isDigit(r rune) bool {
	return ('0' <= r && r <= '9')
}

func isDoubleQuote(r rune) bool {
	return (r == '"')
}

func eatToken(scanner *Scanner) Token {
	peek := scanner.Peek()

	switch {
	case isEOF(peek.char):
		return eatEOF(scanner)
	case isWhitespace(peek.char):
		return eatWhitespace(scanner)
	case isOperator(peek.char):
		return eatOperatorToken(scanner)
	case isSemicolon(peek.char):
		return eatSemicolonToken(scanner)
	case isComma(peek.char):
		return eatCommaToken(scanner)
	case isParen(peek.char):
		return eatParenToken(scanner)
	case isBrace(peek.char):
		return eatBraceToken(scanner)
	case isBracket(peek.char):
		return eatBracketToken(scanner)
	case isLetter(peek.char):
		return eatWordToken(scanner)
	case isDigit(peek.char):
		return eatNumberToken(scanner)
	case isDoubleQuote(peek.char):
		return eatStringToken(scanner)
	default:
		return Token{Error, "unexpected symbol", peek.loc}
	}
}

func eatEOF(scanner *Scanner) Token {
	return Token{EOF, "", scanner.Peek().loc}
}

func eatWhitespace(scanner *Scanner) Token {
	for isWhitespace(scanner.Peek().char) {
		scanner.Next()
	}

	return eatToken(scanner)
}

func eatOperatorToken(scanner *Scanner) Token {
	switch scanner.Peek().char {
	case '+':
		return Token{Plus, "+", scanner.Next().loc}
	case '-':
		return Token{Dash, "-", scanner.Next().loc}
	case '*':
		return Token{Star, "*", scanner.Next().loc}
	case '/':
		return Token{Slash, "/", scanner.Next().loc}
	case '?':
		return Token{Question, "?", scanner.Next().loc}
	case ':':
		colon := scanner.Next()
		tok := Token{Colon, ":", colon.loc}

		if scanner.Peek().char == '=' {
			scanner.Next()
			tok = Token{Assign, ":=", colon.loc}
		}

		return tok
	case '=':
		equals := scanner.Next()

		if scanner.Peek().char == '>' {
			scanner.Next()
			return Token{Arrow, "=>", equals.loc}
		}

		return Token{Error, "expected operator", equals.loc}
	case '<':
		lt := scanner.Next()

		if scanner.Peek().char == '=' {
			scanner.Next()
			return Token{LTEquals, "<=", lt.loc}
		}

		return Token{LT, "<", lt.loc}
	case '>':
		gt := scanner.Next()

		if scanner.Peek().char == '=' {
			scanner.Next()
			return Token{GTEquals, ">=", gt.loc}
		}

		return Token{GT, ">", gt.loc}
	default:
		return Token{Error, "expected operator", scanner.Next().loc}
	}
}

func eatSemicolonToken(scanner *Scanner) Token {
	if scanner.Peek().char != ';' {
		return Token{Error, "expected semicolon", scanner.Next().loc}
	}

	return Token{Semi, ";", scanner.Next().loc}
}

func eatCommaToken(scanner *Scanner) Token {
	if scanner.Peek().char != ',' {
		return Token{Error, "expected comma", scanner.Next().loc}
	}

	return Token{Comma, ",", scanner.Next().loc}
}

func eatParenToken(scanner *Scanner) Token {
	switch scanner.Peek().char {
	case '(':
		return Token{ParenL, "(", scanner.Next().loc}
	case ')':
		return Token{ParenR, ")", scanner.Next().loc}
	default:
		return Token{Error, "expected paren", scanner.Next().loc}
	}
}

func eatBraceToken(scanner *Scanner) Token {
	switch scanner.Peek().char {
	case '{':
		return Token{BraceL, "{", scanner.Next().loc}
	case '}':
		return Token{BraceR, "}", scanner.Next().loc}
	default:
		return Token{Error, "expected brace", scanner.Next().loc}
	}
}

func eatBracketToken(scanner *Scanner) Token {
	switch scanner.Peek().char {
	case '[':
		return Token{BracketL, "[", scanner.Next().loc}
	case ']':
		return Token{BracketR, "]", scanner.Next().loc}
	default:
		return Token{Error, "expected bracket", scanner.Next().loc}
	}
}

func eatWordToken(scanner *Scanner) Token {
	loc := scanner.Peek().loc
	lexeme := ""

	if isLetter(scanner.Peek().char) == false {
		return Token{Error, "expected word", loc}
	}

	for isLetter(scanner.Peek().char) {
		lexeme += string(scanner.Next().char)
	}

	switch lexeme {
	case "fn":
		return Token{Fn, "fn", loc}
	case "if":
		return Token{If, "if", loc}
	case "let":
		return Token{Let, "let", loc}
	case "return":
		return Token{Return, "return", loc}
	case "self":
		return Token{Self, "self", loc}
	case "use":
		return Token{Use, "use", loc}
	case "true":
		return Token{Boolean, "true", loc}
	case "false":
		return Token{Boolean, "false", loc}
	default:
		return Token{Ident, lexeme, loc}
	}
}

func eatNumberToken(scanner *Scanner) Token {
	loc := scanner.Peek().loc
	lexeme := ""

	if isDigit(scanner.Peek().char) == false {
		return Token{Error, "expected number", loc}
	}

	for isDigit(scanner.Peek().char) {
		lexeme += string(scanner.Next().char)
	}

	return Token{Number, lexeme, loc}
}

func eatStringToken(scanner *Scanner) Token {
	loc := scanner.Peek().loc
	lexeme := ""

	if isDoubleQuote(scanner.Peek().char) == false {
		return Token{Error, "expected string", loc}
	}

	lexeme += string(scanner.Next().char)
	for {
		switch scanner.Peek().char {
		case '"':
			lexeme += string(scanner.Next().char)
			return Token{String, lexeme, loc}
		case '\000':
			fallthrough
		case '\n':
			return Token{Error, "unclosed string", scanner.Peek().loc}
		default:
			lexeme += string(scanner.Next().char)
		}
	}
}
<|endoftext|>


<commit_before>package lexers

import (
	. "github.com/alecthomas/chroma" // nolint
	"strings"
)

var httpBodyContentType string

// Http lexer.
var Http = Register(MustNewLexer(
	&Config{
		Name:         "HTTP",
		Aliases:      []string{"http"},
		Filenames:    []string{},
		MimeTypes:    []string{},
		NotMultiline: true,
		DotAll:       true,
	},
	Rules{
		"root": {
			{`(GET|POST|PUT|DELETE|HEAD|OPTIONS|TRACE|PATCH)( +)([^ ]+)( +)(HTTP)(/)(1\.[01])(\r?\n|\Z)`, ByGroups(NameFunction, Text, NameNamespace, Text, KeywordReserved, Operator, LiteralNumber, Text), Push("headers")},
			{`(HTTP)(/)(1\.[01])( +)(\d{3})( +)([^\r\n]+)(\r?\n|\Z)`, ByGroups(KeywordReserved, Operator, LiteralNumber, Text, LiteralNumber, Text, NameException, Text), Push("headers")},
		},
		"headers": {
			{`([^\s:]+)( *)(:)( *)([^\r\n]+)(\r?\n|\Z)`, EmitterFunc(httpHeaderBlock), nil},
			{`([\t ]+)([^\r\n]+)(\r?\n|\Z)`, EmitterFunc(httpContinuousHeaderBlock), nil},
			{`\r?\n`, Text, Push("content")},
		},
		"content": {
			{`.+`, EmitterFunc(httpContentBlock), nil},
		},
	},
))

func httpContentBlock(groups []string, lexer Lexer) Iterator {
	iterators := []Iterator{}
	code := groups[0]

	if len(httpBodyContentType) > 0 {
		lexer := MatchMimeType(httpBodyContentType)

		// application/calendar+xml can be treated as application/xml
		// if there's not a better match.
		if lexer == nil && strings.Contains(httpBodyContentType, "+") {
			slashPos := strings.Index(httpBodyContentType, "/")
			plusPos := strings.LastIndex(httpBodyContentType, "+")
			httpBodyContentType = httpBodyContentType[:slashPos+1] + httpBodyContentType[plusPos+1:]
			lexer = MatchMimeType(httpBodyContentType)
		}

		if lexer != nil {
			sub, err := lexer.Tokenise(nil, code)
			if err != nil {
				panic(err)
			}
			iterators = append(iterators, sub)
		} else {
			tokens := []*Token{
				{Text, code},
			}
			iterators = append(iterators, Literator(tokens...))
		}
	}
	return Concaterator(iterators...)
}

func httpHeaderBlock(groups []string, lexer Lexer) Iterator {
	if strings.ToLower(groups[1]) == "content-type" {
		contentType := strings.TrimSpace(groups[5])
		pos := strings.Index(contentType, ";")
		if pos > 0 {
			contentType = strings.TrimSpace(contentType[:pos])
		}

		httpBodyContentType = contentType
	}

	iterators := []Iterator{}
	tokens := []*Token{
		{Name, groups[1]},
		{Text, groups[2]},
		{Operator, groups[3]},
		{Text, groups[4]},
		{Literal, groups[5]},
		{Text, groups[6]},
	}
	iterators = append(iterators, Literator(tokens...))
	return Concaterator(iterators...)
}

func httpContinuousHeaderBlock(groups []string, lexer Lexer) Iterator {
	iterators := []Iterator{}
	tokens := []*Token{
		{Text, groups[1]},
		{Literal, groups[2]},
		{Text, groups[3]},
	}
	iterators = append(iterators, Literator(tokens...))
	return Concaterator(iterators...)
}
<commit_msg>improve http lexer<commit_after>package lexers

import (
	. "github.com/alecthomas/chroma" // nolint
	"strings"
)

// HTTP lexer.
var HTTP = Register(httpBodyContentTypeLexer(MustNewLexer(
	&Config{
		Name:         "HTTP",
		Aliases:      []string{"http"},
		Filenames:    []string{},
		MimeTypes:    []string{},
		NotMultiline: true,
		DotAll:       true,
	},
	Rules{
		"root": {
			{`(GET|POST|PUT|DELETE|HEAD|OPTIONS|TRACE|PATCH)( +)([^ ]+)( +)(HTTP)(/)(1\.[01])(\r?\n|\Z)`, ByGroups(NameFunction, Text, NameNamespace, Text, KeywordReserved, Operator, LiteralNumber, Text), Push("headers")},
			{`(HTTP)(/)(1\.[01])( +)(\d{3})( +)([^\r\n]+)(\r?\n|\Z)`, ByGroups(KeywordReserved, Operator, LiteralNumber, Text, LiteralNumber, Text, NameException, Text), Push("headers")},
		},
		"headers": {
			{`([^\s:]+)( *)(:)( *)([^\r\n]+)(\r?\n|\Z)`, EmitterFunc(httpHeaderBlock), nil},
			{`([\t ]+)([^\r\n]+)(\r?\n|\Z)`, EmitterFunc(httpContinuousHeaderBlock), nil},
			{`\r?\n`, Text, Push("content")},
		},
		"content": {
			{`.+`, EmitterFunc(httpContentBlock), nil},
		},
	},
)))

func httpContentBlock(groups []string, lexer Lexer) Iterator {
	tokens := []*Token{
		{Generic, groups[0]},
	}
	return Literator(tokens...)

}

func httpHeaderBlock(groups []string, lexer Lexer) Iterator {
	tokens := []*Token{
		{Name, groups[1]},
		{Text, groups[2]},
		{Operator, groups[3]},
		{Text, groups[4]},
		{Literal, groups[5]},
		{Text, groups[6]},
	}
	return Literator(tokens...)
}

func httpContinuousHeaderBlock(groups []string, lexer Lexer) Iterator {
	tokens := []*Token{
		{Text, groups[1]},
		{Literal, groups[2]},
		{Text, groups[3]},
	}
	return Literator(tokens...)
}

func httpBodyContentTypeLexer(lexer Lexer) Lexer { return &httpBodyContentTyper{lexer} }

type httpBodyContentTyper struct{ Lexer }

func (d *httpBodyContentTyper) Tokenise(options *TokeniseOptions, text string) (Iterator, error) {
	var contentType string
	var isContentType bool
	var subIterator Iterator

	it, err := d.Lexer.Tokenise(options, text)
	if err != nil {
		return nil, err
	}

	return func() *Token {
		for token := it(); token != nil; token = it() {
			switch {
			case token.Type == Name && strings.ToLower(token.Value) == "content-type":
				{
					isContentType = true
				}
			case token.Type == Literal && isContentType:
				{
					contentType = strings.TrimSpace(token.Value)
					pos := strings.Index(contentType, ";")
					if pos > 0 {
						contentType = strings.TrimSpace(contentType[:pos])
					}
				}
			case token.Type == Generic && contentType != "":
				{
					lexer := MatchMimeType(contentType)

					// application/calendar+xml can be treated as application/xml
					// if there's not a better match.
					if lexer == nil && strings.Contains(contentType, "+") {
						slashPos := strings.Index(contentType, "/")
						plusPos := strings.LastIndex(contentType, "+")
						contentType = contentType[:slashPos+1] + contentType[plusPos+1:]
						lexer = MatchMimeType(contentType)
					}

					if lexer == nil {
						token.Type = Text
					} else {
						subIterator, err = lexer.Tokenise(nil, token.Value)
						if err != nil {
							panic(err)
						}
						return nil
					}
				}

			}

			return token
		}

		if subIterator != nil {
			for token := subIterator(); token != nil; token = subIterator() {
				return token
			}
		}
		return nil

	}, nil
}
<|endoftext|>


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

package gltext

import (
	"fmt"
	"github.com/go-gl/glow/gl-core/3.3/gl"
	"github.com/go-gl/mathgl/mgl32"
)

const IsEdit = false

type Text struct {
	font *Font

	// final position on screen
	finalPosition mgl32.Vec2

	// text color
	color mgl32.Vec4

	// scaling the text
	Scale       float32
	ScaleMax    float32
	scaleMatrix mgl32.Mat4

	// bounding box of text
	BoundingBox *BoundingBox

	// general opengl values
	vao           uint32
	vbo           uint32
	ebo           uint32
	vboData       []float32
	vboIndexCount int
	eboData       []int32
	eboIndexCount int

	// X1, X2: the lower left and upper right points of a box that bounds the text
	X1 Point
	X2 Point
}

func LoadText(f *Font) (t *Text) {
	t = new(Text)
	t.font = f

	// text hover values - implicit ScaleMin of 1.0
	t.ScaleMax = 1.1
	t.SetScale(1)

	// size of glfloat
	glfloat_size := int32(4)

	// stride of the buffered data
	xy_count := int32(2)
	stride := xy_count + int32(2)

	gl.GenVertexArrays(1, &t.vao)
	gl.GenBuffers(1, &t.vbo)
	gl.GenBuffers(1, &t.ebo)

	// vao
	gl.BindVertexArray(t.vao)

	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, t.font.textureID)

	// vbo
	// specify the buffer for which the VertexAttribPointer calls apply
	gl.BindBuffer(gl.ARRAY_BUFFER, t.vbo)

	gl.EnableVertexAttribArray(t.font.centeredPosition)
	gl.VertexAttribPointer(
		t.font.centeredPosition,
		2,
		gl.FLOAT,
		false,
		glfloat_size*stride,
		gl.PtrOffset(0),
	)

	gl.EnableVertexAttribArray(t.font.uv)
	gl.VertexAttribPointer(
		t.font.uv,
		2,
		gl.FLOAT,
		false,
		glfloat_size*stride,
		gl.PtrOffset(int(glfloat_size*xy_count)),
	)

	// ebo
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, t.ebo)

	// i am guessing that order is important here
	gl.BindVertexArray(0)
	gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
	return t
}

// Release releases font resources.
// A font can no longer be used for rendering after this call completes.
func (t *Text) Release() {
	gl.DeleteBuffers(1, &t.vbo)
	gl.DeleteBuffers(1, &t.ebo)
	gl.DeleteBuffers(1, &t.vao)
}

func (t *Text) SetScale(s float32) (changed bool) {
	if s > t.ScaleMax || s < 1.0 {
		return
	}
	changed = true
	t.Scale = s
	t.scaleMatrix = mgl32.Scale3D(s, s, s)
	return
}

func (t *Text) AddScale(s float32) (changed bool) {
	if s < 0 && t.Scale <= 1.0 {
		return
	}
	if s > 0 && t.Scale >= t.ScaleMax {
		return
	}
	changed = true
	t.Scale += s
	t.scaleMatrix = mgl32.Scale3D(t.Scale, t.Scale, t.Scale)
	return
}

func (t *Text) SetColor(r, g, b, a float32) {
	t.color = mgl32.Vec4{r, g, b, a}
}

func (t *Text) SetString(fs string, argv ...interface{}) (Point, Point) {
	indices := []rune(fmt.Sprintf(fs, argv...))
	if len(indices) == 0 {
		return Point{}, Point{}
	}

	// ebo, vbo data
	glfloat_size := int32(4)

	t.vboIndexCount = len(indices) * 4 * 2 * 2 // 4 indexes per rune (containing 2 position + 2 texture)
	t.eboIndexCount = len(indices) * 6         // each rune requires 6 triangle indices for a quad
	t.vboData = make([]float32, t.vboIndexCount, t.vboIndexCount)
	t.eboData = make([]int32, t.eboIndexCount, t.eboIndexCount)

	// generate the basic vbo data and bounding box
	t.makeBufferData(indices)
	// find the centered position of the bounding box
	lowerLeft := t.center()
	// reposition the vbo data so that it is centered on screen
	t.setDataPosition(lowerLeft)

	if IsDebug {
		fmt.Printf("bounding box %v %v\n", t.X1, t.X2)
		fmt.Printf("text vbo data\n%v\n", t.vboData)
		fmt.Printf("text ebo data\n%v\n", t.eboData)
	}
	gl.BindVertexArray(t.vao)
	gl.BindBuffer(gl.ARRAY_BUFFER, t.vbo)
	gl.BufferData(
		gl.ARRAY_BUFFER, int(glfloat_size)*t.vboIndexCount, gl.Ptr(t.vboData), gl.DYNAMIC_DRAW)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, t.ebo)
	gl.BufferData(
		gl.ELEMENT_ARRAY_BUFFER, int(glfloat_size)*t.eboIndexCount, gl.Ptr(t.eboData), gl.DYNAMIC_DRAW)
	gl.BindVertexArray(0)

	// not necesssary, but i just want to better understand using vertex arrays
	gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)

	return t.X1, t.X2
}

func (t *Text) center() (lowerLeft Point) {
	lineWidthHalf := (t.X2.X - t.X1.X) / 2
	lineHeightHalf := (t.X2.Y - t.X1.Y) / 2

	lowerLeft.X = -lineWidthHalf
	lowerLeft.Y = -lineHeightHalf
	return
}

func (t *Text) SetPosition(x, y float32) {
	// at this point we are in orthographic projection coordinates which range from -1 to 1
	// and the text's default position is with its bounding box perfectly centered in the screen

	// final place the corner on the position specified by the user
	t.finalPosition[0] = x
	t.finalPosition[1] = y
	if IsEdit {
		t.BoundingBox.finalPosition[0] = x
		t.BoundingBox.finalPosition[1] = y
	}
}

func (t *Text) Draw() {
	if IsEdit {
		t.BoundingBox.Draw()
	}
	gl.UseProgram(t.font.program)

	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, t.font.textureID)

	// uniforms
	gl.Uniform1i(t.font.fragmentTextureUniform, 0)
	gl.Uniform1f(t.font.textLowerBoundUniform, t.font.textLowerBound)
	gl.Uniform4fv(t.font.colorUniform, 1, &t.color[0])
	gl.Uniform2fv(t.font.finalPositionUniform, 1, &t.finalPosition[0])
	gl.UniformMatrix4fv(t.font.orthographicMatrixUniform, 1, false, &t.font.orthographicMatrix[0])
	gl.UniformMatrix4fv(t.font.scaleMatrixUniform, 1, false, &t.scaleMatrix[0])

	// draw
	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	gl.BindVertexArray(t.vao)
	gl.DrawElements(gl.TRIANGLES, int32(t.eboIndexCount), gl.UNSIGNED_INT, nil)
	gl.BindVertexArray(0)
	gl.Disable(gl.BLEND)
}

func (t *Text) getBoundingBox(vboIndex int) {
	// index -4: x, index -3: y, index -2: uv's x, index -1 uv's y
	x := t.vboData[vboIndex-4]
	y := t.vboData[vboIndex-3]

	if vboIndex-4 == 0 {
		t.X1.X = x
		t.X1.Y = y
	} else {
		if x < t.X1.X {
			t.X1.X = x
		}
		if y < t.X1.Y {
			t.X1.Y = y
		}
		if x > t.X2.X {
			t.X2.X = x
		}
		if y > t.X2.Y {
			t.X2.Y = y
		}
	}
}

// all text originally sits at point (0,0) which is the
// lower left hand corner of the screen.
func (t *Text) setDataPosition(lowerLeft Point) (err error) {
	length := len(t.vboData)
	for index := 0; index < length; {
		// index (0,0)
		t.vboData[index] += lowerLeft.X
		index++
		t.vboData[index] += lowerLeft.Y
		index += 3 // skip texture data

		// index (1,0)
		t.vboData[index] += lowerLeft.X
		index++
		t.vboData[index] += lowerLeft.Y
		index += 3

		// index (1,1)
		t.vboData[index] += lowerLeft.X
		index++
		t.vboData[index] += lowerLeft.Y
		index += 3

		// index (0,1)
		t.vboData[index] += lowerLeft.X
		index++
		t.vboData[index] += lowerLeft.Y
		index += 3
	}
	// update bounding box
	t.X1.X += lowerLeft.X
	t.X2.X += lowerLeft.X
	t.X1.Y += lowerLeft.Y
	t.X2.Y += lowerLeft.Y
	if IsEdit {
		t.BoundingBox, err = loadBoundingBox(t.font, t.X1, t.X2)
	}
	return
}

// currently only supports left to right text flow
func (t *Text) makeBufferData(indices []rune) {
	glyphs := t.font.config.Glyphs
	low := t.font.config.Low

	vboIndex := 0
	eboIndex := 0
	lineX := float32(0)
	eboOffset := int32(0)
	for _, r := range indices {
		r -= low
		if r >= 0 && int(r) < len(glyphs) {
			vw := float32(glyphs[r].Width)
			vh := float32(glyphs[r].Height)
			tP1, tP2 := glyphs[r].GetIndices(t.font)

			// counter-clockwise quad

			// index (0,0)
			t.vboData[vboIndex] = lineX // position
			vboIndex++
			t.vboData[vboIndex] = 0
			vboIndex++
			t.vboData[vboIndex] = tP1.X // texture uv
			vboIndex++
			t.vboData[vboIndex] = tP2.Y
			vboIndex++
			t.getBoundingBox(vboIndex)

			// index (1,0)
			t.vboData[vboIndex] = lineX + vw
			vboIndex++
			t.vboData[vboIndex] = 0
			vboIndex++
			t.vboData[vboIndex] = tP2.X
			vboIndex++
			t.vboData[vboIndex] = tP2.Y
			vboIndex++
			t.getBoundingBox(vboIndex)

			// index (1,1)
			t.vboData[vboIndex] = lineX + vw
			vboIndex++
			t.vboData[vboIndex] = vh
			vboIndex++
			t.vboData[vboIndex] = tP2.X
			vboIndex++
			t.vboData[vboIndex] = tP1.Y
			vboIndex++
			t.getBoundingBox(vboIndex)

			// index (0,1)
			t.vboData[vboIndex] = lineX
			vboIndex++
			t.vboData[vboIndex] = vh
			vboIndex++
			t.vboData[vboIndex] = tP1.X
			vboIndex++
			t.vboData[vboIndex] = tP1.Y
			vboIndex++
			t.getBoundingBox(vboIndex)

			advance := float32(glyphs[r].Advance)
			lineX += advance

			// ebo data
			t.eboData[eboIndex] = 0 + eboOffset
			eboIndex++
			t.eboData[eboIndex] = 1 + eboOffset
			eboIndex++
			t.eboData[eboIndex] = 2 + eboOffset
			eboIndex++

			t.eboData[eboIndex] = 0 + eboOffset
			eboIndex++
			t.eboData[eboIndex] = 2 + eboOffset
			eboIndex++
			t.eboData[eboIndex] = 3 + eboOffset
			eboIndex++
			eboOffset += 4
		}
	}
	return
}
<commit_msg>Notes about orthographic projection.<commit_after>// Copyright 2012 The go-gl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gltext

import (
	"fmt"
	"github.com/go-gl/glow/gl-core/3.3/gl"
	"github.com/go-gl/mathgl/mgl32"
)

const IsEdit = false

type Text struct {
	font *Font

	// final position on screen
	finalPosition mgl32.Vec2

	// text color
	color mgl32.Vec4

	// scaling the text
	Scale       float32
	ScaleMax    float32
	scaleMatrix mgl32.Mat4

	// bounding box of text
	BoundingBox *BoundingBox

	// general opengl values
	vao           uint32
	vbo           uint32
	ebo           uint32
	vboData       []float32
	vboIndexCount int
	eboData       []int32
	eboIndexCount int

	// X1, X2: the lower left and upper right points of a box that bounds the text
	X1 Point
	X2 Point
}

func LoadText(f *Font) (t *Text) {
	t = new(Text)
	t.font = f

	// text hover values - implicit ScaleMin of 1.0
	t.ScaleMax = 1.1
	t.SetScale(1)

	// size of glfloat
	glfloat_size := int32(4)

	// stride of the buffered data
	xy_count := int32(2)
	stride := xy_count + int32(2)

	gl.GenVertexArrays(1, &t.vao)
	gl.GenBuffers(1, &t.vbo)
	gl.GenBuffers(1, &t.ebo)

	// vao
	gl.BindVertexArray(t.vao)

	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, t.font.textureID)

	// vbo
	// specify the buffer for which the VertexAttribPointer calls apply
	gl.BindBuffer(gl.ARRAY_BUFFER, t.vbo)

	gl.EnableVertexAttribArray(t.font.centeredPosition)
	gl.VertexAttribPointer(
		t.font.centeredPosition,
		2,
		gl.FLOAT,
		false,
		glfloat_size*stride,
		gl.PtrOffset(0),
	)

	gl.EnableVertexAttribArray(t.font.uv)
	gl.VertexAttribPointer(
		t.font.uv,
		2,
		gl.FLOAT,
		false,
		glfloat_size*stride,
		gl.PtrOffset(int(glfloat_size*xy_count)),
	)

	// ebo
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, t.ebo)

	// i am guessing that order is important here
	gl.BindVertexArray(0)
	gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)
	return t
}

// Release releases font resources.
// A font can no longer be used for rendering after this call completes.
func (t *Text) Release() {
	gl.DeleteBuffers(1, &t.vbo)
	gl.DeleteBuffers(1, &t.ebo)
	gl.DeleteBuffers(1, &t.vao)
}

func (t *Text) SetScale(s float32) (changed bool) {
	if s > t.ScaleMax || s < 1.0 {
		return
	}
	changed = true
	t.Scale = s
	t.scaleMatrix = mgl32.Scale3D(s, s, s)
	return
}

func (t *Text) AddScale(s float32) (changed bool) {
	if s < 0 && t.Scale <= 1.0 {
		return
	}
	if s > 0 && t.Scale >= t.ScaleMax {
		return
	}
	changed = true
	t.Scale += s
	t.scaleMatrix = mgl32.Scale3D(t.Scale, t.Scale, t.Scale)
	return
}

func (t *Text) SetColor(r, g, b, a float32) {
	t.color = mgl32.Vec4{r, g, b, a}
}

func (t *Text) SetString(fs string, argv ...interface{}) (Point, Point) {
	indices := []rune(fmt.Sprintf(fs, argv...))
	if len(indices) == 0 {
		return Point{}, Point{}
	}

	// ebo, vbo data
	glfloat_size := int32(4)

	t.vboIndexCount = len(indices) * 4 * 2 * 2 // 4 indexes per rune (containing 2 position + 2 texture)
	t.eboIndexCount = len(indices) * 6         // each rune requires 6 triangle indices for a quad
	t.vboData = make([]float32, t.vboIndexCount, t.vboIndexCount)
	t.eboData = make([]int32, t.eboIndexCount, t.eboIndexCount)

	// generate the basic vbo data and bounding box
	t.makeBufferData(indices)

	// find the centered position of the bounding box
	lowerLeft := t.center()

	// reposition the vbo data so that it is centered at (0,0)
	// according to the orthographic projection being used
	t.setDataPosition(lowerLeft)

	if IsDebug {
		fmt.Printf("bounding box %v %v\n", t.X1, t.X2)
		fmt.Printf("text vbo data\n%v\n", t.vboData)
		fmt.Printf("text ebo data\n%v\n", t.eboData)
	}
	gl.BindVertexArray(t.vao)
	gl.BindBuffer(gl.ARRAY_BUFFER, t.vbo)
	gl.BufferData(
		gl.ARRAY_BUFFER, int(glfloat_size)*t.vboIndexCount, gl.Ptr(t.vboData), gl.DYNAMIC_DRAW)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, t.ebo)
	gl.BufferData(
		gl.ELEMENT_ARRAY_BUFFER, int(glfloat_size)*t.eboIndexCount, gl.Ptr(t.eboData), gl.DYNAMIC_DRAW)
	gl.BindVertexArray(0)

	// not necesssary, but i just want to better understand using vertex arrays
	gl.BindBuffer(gl.ARRAY_BUFFER, 0)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, 0)

	return t.X1, t.X2
}

func (t *Text) center() (lowerLeft Point) {
	lineWidthHalf := (t.X2.X - t.X1.X) / 2
	lineHeightHalf := (t.X2.Y - t.X1.Y) / 2

	lowerLeft.X = -lineWidthHalf
	lowerLeft.Y = -lineHeightHalf
	return
}

func (t *Text) SetPosition(x, y float32) {
	// at this point we are in orthographic projection coordinates which range from -1 to 1
	// and the text's default position is with its bounding box perfectly centered in the screen

	// final place the corner on the position specified by the user
	t.finalPosition[0] = x
	t.finalPosition[1] = y
	if IsEdit {
		t.BoundingBox.finalPosition[0] = x
		t.BoundingBox.finalPosition[1] = y
	}
}

func (t *Text) Draw() {
	if IsEdit {
		t.BoundingBox.Draw()
	}
	gl.UseProgram(t.font.program)

	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_2D, t.font.textureID)

	// uniforms
	gl.Uniform1i(t.font.fragmentTextureUniform, 0)
	gl.Uniform1f(t.font.textLowerBoundUniform, t.font.textLowerBound)
	gl.Uniform4fv(t.font.colorUniform, 1, &t.color[0])
	gl.Uniform2fv(t.font.finalPositionUniform, 1, &t.finalPosition[0])
	gl.UniformMatrix4fv(t.font.orthographicMatrixUniform, 1, false, &t.font.orthographicMatrix[0])
	gl.UniformMatrix4fv(t.font.scaleMatrixUniform, 1, false, &t.scaleMatrix[0])

	// draw
	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	gl.BindVertexArray(t.vao)
	gl.DrawElements(gl.TRIANGLES, int32(t.eboIndexCount), gl.UNSIGNED_INT, nil)
	gl.BindVertexArray(0)
	gl.Disable(gl.BLEND)
}

func (t *Text) getBoundingBox(vboIndex int) {
	// index -4: x, index -3: y, index -2: uv's x, index -1 uv's y
	x := t.vboData[vboIndex-4]
	y := t.vboData[vboIndex-3]

	if vboIndex-4 == 0 {
		t.X1.X = x
		t.X1.Y = y
	} else {
		if x < t.X1.X {
			t.X1.X = x
		}
		if y < t.X1.Y {
			t.X1.Y = y
		}
		if x > t.X2.X {
			t.X2.X = x
		}
		if y > t.X2.Y {
			t.X2.Y = y
		}
	}
}

// all text originally sits at point (0,0) which is the
// lower left hand corner of the screen.
func (t *Text) setDataPosition(lowerLeft Point) (err error) {
	length := len(t.vboData)
	for index := 0; index < length; {
		// index (0,0)
		t.vboData[index] += lowerLeft.X
		index++
		t.vboData[index] += lowerLeft.Y
		index += 3 // skip texture data

		// index (1,0)
		t.vboData[index] += lowerLeft.X
		index++
		t.vboData[index] += lowerLeft.Y
		index += 3

		// index (1,1)
		t.vboData[index] += lowerLeft.X
		index++
		t.vboData[index] += lowerLeft.Y
		index += 3

		// index (0,1)
		t.vboData[index] += lowerLeft.X
		index++
		t.vboData[index] += lowerLeft.Y
		index += 3
	}
	// update bounding box
	t.X1.X += lowerLeft.X
	t.X2.X += lowerLeft.X
	t.X1.Y += lowerLeft.Y
	t.X2.Y += lowerLeft.Y
	if IsEdit {
		t.BoundingBox, err = loadBoundingBox(t.font, t.X1, t.X2)
	}
	return
}

// currently only supports left to right text flow
func (t *Text) makeBufferData(indices []rune) {
	glyphs := t.font.config.Glyphs
	low := t.font.config.Low

	vboIndex := 0
	eboIndex := 0
	lineX := float32(0)
	eboOffset := int32(0)
	for _, r := range indices {
		r -= low
		if r >= 0 && int(r) < len(glyphs) {
			vw := float32(glyphs[r].Width)
			vh := float32(glyphs[r].Height)
			tP1, tP2 := glyphs[r].GetIndices(t.font)

			// counter-clockwise quad

			// index (0,0)
			t.vboData[vboIndex] = lineX // position
			vboIndex++
			t.vboData[vboIndex] = 0
			vboIndex++
			t.vboData[vboIndex] = tP1.X // texture uv
			vboIndex++
			t.vboData[vboIndex] = tP2.Y
			vboIndex++
			t.getBoundingBox(vboIndex)

			// index (1,0)
			t.vboData[vboIndex] = lineX + vw
			vboIndex++
			t.vboData[vboIndex] = 0
			vboIndex++
			t.vboData[vboIndex] = tP2.X
			vboIndex++
			t.vboData[vboIndex] = tP2.Y
			vboIndex++
			t.getBoundingBox(vboIndex)

			// index (1,1)
			t.vboData[vboIndex] = lineX + vw
			vboIndex++
			t.vboData[vboIndex] = vh
			vboIndex++
			t.vboData[vboIndex] = tP2.X
			vboIndex++
			t.vboData[vboIndex] = tP1.Y
			vboIndex++
			t.getBoundingBox(vboIndex)

			// index (0,1)
			t.vboData[vboIndex] = lineX
			vboIndex++
			t.vboData[vboIndex] = vh
			vboIndex++
			t.vboData[vboIndex] = tP1.X
			vboIndex++
			t.vboData[vboIndex] = tP1.Y
			vboIndex++
			t.getBoundingBox(vboIndex)

			advance := float32(glyphs[r].Advance)
			lineX += advance

			// ebo data
			t.eboData[eboIndex] = 0 + eboOffset
			eboIndex++
			t.eboData[eboIndex] = 1 + eboOffset
			eboIndex++
			t.eboData[eboIndex] = 2 + eboOffset
			eboIndex++

			t.eboData[eboIndex] = 0 + eboOffset
			eboIndex++
			t.eboData[eboIndex] = 2 + eboOffset
			eboIndex++
			t.eboData[eboIndex] = 3 + eboOffset
			eboIndex++
			eboOffset += 4
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2013 Matthew Baird
// 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 elastigo_test

import (
	"bytes"
	"fmt"
	elastigo "github.com/shutej/elastigo/lib"
	"strconv"
	"time"
)

// The simplest usage of background bulk indexing
func ExampleBulkIndexer_simple() {
	c := elastigo.NewConn()

	indexer := c.NewBulkIndexerErrors(10, 60)
	indexer.Start()
	indexer.Index("twitter", "user", "1", "", nil, `{"name":"bob"}`, true)
	indexer.Stop()
}

// The inspecting the response
func ExampleBulkIndexer_responses() {
	c := elastigo.NewConn()

	indexer := c.NewBulkIndexer(10)
	// Create a custom Sender Func, to allow inspection of response/error
	indexer.Sender = func(buf *bytes.Buffer) error {
		// @buf is the buffer of docs about to be written
		respJson, err := c.DoCommand("POST", "/_bulk", nil, buf)
		if err != nil {
			// handle it better than this
			fmt.Println(string(respJson))
		}
		return err
	}
	indexer.Start()
	for i := 0; i < 20; i++ {
		indexer.Index("twitter", "user", strconv.Itoa(i), "", nil, `{"name":"bob"}`, true)
	}
	indexer.Stop()
}
<commit_msg>replace shutej reference<commit_after>// Copyright 2013 Matthew Baird
// 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 elastigo_test

import (
	"bytes"
	"fmt"
	elastigo "github.com/mattbaird/elastigo/lib"
	"strconv"
)

// The simplest usage of background bulk indexing
func ExampleBulkIndexer_simple() {
	c := elastigo.NewConn()

	indexer := c.NewBulkIndexerErrors(10, 60)
	indexer.Start()
	indexer.Index("twitter", "user", "1", "", nil, `{"name":"bob"}`, true)
	indexer.Stop()
}

// The inspecting the response
func ExampleBulkIndexer_responses() {
	c := elastigo.NewConn()

	indexer := c.NewBulkIndexer(10)
	// Create a custom Sender Func, to allow inspection of response/error
	indexer.Sender = func(buf *bytes.Buffer) error {
		// @buf is the buffer of docs about to be written
		respJson, err := c.DoCommand("POST", "/_bulk", nil, buf)
		if err != nil {
			// handle it better than this
			fmt.Println(string(respJson))
		}
		return err
	}
	indexer.Start()
	for i := 0; i < 20; i++ {
		indexer.Index("twitter", "user", strconv.Itoa(i), "", nil, `{"name":"bob"}`, true)
	}
	indexer.Stop()
}
<|endoftext|>


<commit_before>package rogue

import "fmt"

// time constants
const (
	Minute = 1
	Hour   = Minute * 60
	Day    = Hour * 24
	Month  = Day * 30
	Season = Month * 3
	Year   = Month * 12
)

// GameTime is the object representing game server time
//
// Server ticks every 3 real-world seconds.
// A day has 24 hours.
// There are 4 seasons.
// Each season has 3 months (90 days).
//
// Each tick progresses the in-game time by 1 minutes,
// giving 60 ticks for an hour
//
// So 1 game year = 518400 * 3 = 1555200 real seconds,
// or 25920 real time minutes (432 real hours, 7.2 real days).
type GameTime struct {
	time int64
}

func newTime(t int64) *GameTime {

	return &GameTime{time: t}
}

// Set sets the current time
func (t *GameTime) Set(i int64) {
	t.time = i
}

// Tick progress the time
func (t *GameTime) Tick() {

	t.time++
}

// Current returns the current time
func (t *GameTime) Current() int64 {

	return t.time
}

// DateString returns "evening 19:20\nspring feb 20"
func (t *GameTime) DateString() string {

	return t.PartOfDay() + " " + t.TimeOfDay() + "\n" + t.Season() + " " + t.DayOfYear()
}

// TimeOfDay returns time as "19:30"
func (t *GameTime) TimeOfDay() string {

	minute, hour, _, _, _ := t.date()

	return fmt.Sprintf("%02d:%02d", hour, minute)
}

func (t *GameTime) date() (int64, int64, int64, int64, int64) {

	rest := t.time

	year := rest / Year
	if year > 0 {
		rest -= year * Year
	}

	month := rest / Month
	if month > 0 {
		rest -= month * Month
	}

	day := rest / Day
	if day > 0 {
		rest -= day * Day
	}

	hour := rest / Hour
	if hour > 0 {
		rest -= hour * Hour
	}

	minute := rest

	return minute, hour, day, month, year
}

// Minute returns the minute
func (t *GameTime) Minute() int64 {

	minute, _, _, _, _ := t.date()
	return minute
}

// Hour returns the hour
func (t *GameTime) Hour() int64 {

	_, hour, _, _, _ := t.date()
	return hour
}

// Day returns the day
func (t *GameTime) Day() int64 {

	_, _, day, _, _ := t.date()
	return day
}

// Month returns the month
func (t *GameTime) Month() int64 {

	_, _, _, month, _ := t.date()
	return month
}

// Year returns the year
func (t *GameTime) Year() int64 {

	_, _, _, _, year := t.date()
	return year
}

// PassedSinceStart describes distance of t.time to 0
func (t *GameTime) PassedSinceStart() string {

	minute, hour, day, month, year := t.date()

	if year > 0 {
		return plural(year, "year")
	}
	if month > 0 {
		return plural(month, "month")
	}
	if day > 0 {
		return plural(day, "day")
	}
	if hour > 0 {
		return plural(hour, "hour")
	}
	return plural(minute, "minute")
}

// DayOfYear returns "19 feb in year 5"
func (t *GameTime) DayOfYear() string {

	_, _, day, month, year := t.date()

	months := []string{"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}

	// NOTE: day is stored 0-based, but displayed 1-based
	day++

	if year > 0 {
		return fmt.Sprintf("%s %d in year %d", months[month], day, year)
	}
	return fmt.Sprintf("%s %d", months[month], day)
}

// Season returns "spring" or "winter"
func (t *GameTime) Season() string {
	seasons := []string{"spring", "summer", "autumn", "winter"}

	season := t.Month() / 4
	return seasons[season]
}

// IsDaytime ...
func (t *GameTime) IsDaytime() bool {
	h := t.Hour()
	if h >= 6 && h <= 17 {
		return true
	}

	return false
}

// IsNighttime ...
func (t *GameTime) IsNighttime() bool {
	return !t.IsDaytime()
}

// PartOfDay returns "morning" or "midnight"
func (t *GameTime) PartOfDay() string {

	hour := t.Hour()
	if hour == 0 {
		return "midnight"
	}
	if hour == 6 {
		return "sunrise"
	}
	if hour == 12 {
		return "midday"
	}
	if hour == 18 {
		return "sunset"
	}
	if hour <= 12 {
		return "morning"
	}
	if hour <= 18 {
		return "afternoon"
	}
	return "evening"
}

// Plural returns "1 item" or "2 items"
func plural(t int64, base string) string {

	if t == 1 {
		return fmt.Sprintf("%d %s", t, base)
	}
	return fmt.Sprintf("%d %ss", t, base)
}
<commit_msg>time: make prop public so it can be serialized<commit_after>package rogue

import "fmt"

// time constants
const (
	Minute = 1
	Hour   = Minute * 60
	Day    = Hour * 24
	Month  = Day * 30
	Season = Month * 3
	Year   = Month * 12
)

// GameTime is the object representing game server time
//
// Server ticks every 3 real-world seconds.
// A day has 24 hours.
// There are 4 seasons.
// Each season has 3 months (90 days).
//
// Each tick progresses the in-game time by 1 minutes,
// giving 60 ticks for an hour
//
// So 1 game year = 518400 * 3 = 1555200 real seconds,
// or 25920 real time minutes (432 real hours, 7.2 real days).
type GameTime struct {
	Time int64
}

func newTime(t int64) *GameTime {

	return &GameTime{Time: t}
}

// Set sets the current time
func (t *GameTime) Set(i int64) {
	t.Time = i
}

// Tick progress the time
func (t *GameTime) Tick() {

	t.Time++
}

// Current returns the current time
func (t *GameTime) Current() int64 {

	return t.Time
}

// DateString returns "evening 19:20\nspring feb 20"
func (t *GameTime) DateString() string {

	return t.PartOfDay() + " " + t.TimeOfDay() + "\n" + t.Season() + " " + t.DayOfYear()
}

// TimeOfDay returns time as "19:30"
func (t *GameTime) TimeOfDay() string {

	minute, hour, _, _, _ := t.date()

	return fmt.Sprintf("%02d:%02d", hour, minute)
}

func (t *GameTime) date() (int64, int64, int64, int64, int64) {

	rest := t.Time

	year := rest / Year
	if year > 0 {
		rest -= year * Year
	}

	month := rest / Month
	if month > 0 {
		rest -= month * Month
	}

	day := rest / Day
	if day > 0 {
		rest -= day * Day
	}

	hour := rest / Hour
	if hour > 0 {
		rest -= hour * Hour
	}

	minute := rest

	return minute, hour, day, month, year
}

// Minute returns the minute
func (t *GameTime) Minute() int64 {

	minute, _, _, _, _ := t.date()
	return minute
}

// Hour returns the hour
func (t *GameTime) Hour() int64 {

	_, hour, _, _, _ := t.date()
	return hour
}

// Day returns the day
func (t *GameTime) Day() int64 {

	_, _, day, _, _ := t.date()
	return day
}

// Month returns the month
func (t *GameTime) Month() int64 {

	_, _, _, month, _ := t.date()
	return month
}

// Year returns the year
func (t *GameTime) Year() int64 {

	_, _, _, _, year := t.date()
	return year
}

// PassedSinceStart describes distance of t.time to 0
func (t *GameTime) PassedSinceStart() string {

	minute, hour, day, month, year := t.date()

	if year > 0 {
		return plural(year, "year")
	}
	if month > 0 {
		return plural(month, "month")
	}
	if day > 0 {
		return plural(day, "day")
	}
	if hour > 0 {
		return plural(hour, "hour")
	}
	return plural(minute, "minute")
}

// DayOfYear returns "19 feb in year 5"
func (t *GameTime) DayOfYear() string {

	_, _, day, month, year := t.date()

	months := []string{"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}

	// NOTE: day is stored 0-based, but displayed 1-based
	day++

	if year > 0 {
		return fmt.Sprintf("%s %d in year %d", months[month], day, year)
	}
	return fmt.Sprintf("%s %d", months[month], day)
}

// Season returns "spring" or "winter"
func (t *GameTime) Season() string {
	seasons := []string{"spring", "summer", "autumn", "winter"}

	season := t.Month() / 4
	return seasons[season]
}

// IsDaytime ...
func (t *GameTime) IsDaytime() bool {
	h := t.Hour()
	if h >= 6 && h <= 17 {
		return true
	}

	return false
}

// IsNighttime ...
func (t *GameTime) IsNighttime() bool {
	return !t.IsDaytime()
}

// PartOfDay returns "morning" or "midnight"
func (t *GameTime) PartOfDay() string {

	hour := t.Hour()
	if hour == 0 {
		return "midnight"
	}
	if hour == 6 {
		return "sunrise"
	}
	if hour == 12 {
		return "midday"
	}
	if hour == 18 {
		return "sunset"
	}
	if hour <= 12 {
		return "morning"
	}
	if hour <= 18 {
		return "afternoon"
	}
	return "evening"
}

// Plural returns "1 item" or "2 items"
func plural(t int64, base string) string {

	if t == 1 {
		return fmt.Sprintf("%d %s", t, base)
	}
	return fmt.Sprintf("%d %ss", t, base)
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// 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 (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

func main() {
	funcMap := template.FuncMap{
		"Title": strings.Title,
	}

	// Hacky way to find the template directory. Switch to use zw's template helpers
	// once they are landed.
	importPath := "github.com/uber/zanzibar/lib/gencode"
	p, err := build.Default.Import(importPath, "", build.FindOnly)
	if err != nil {
		panic(fmt.Sprintf("Could not create build path for endpoint generation: %s", err))
	}
	templatePath := filepath.Join(p.Dir, "templates/endpoint_template.tmpl")
	handlerTemplate, err := template.New("endpoint_template.tmpl").Funcs(funcMap).ParseFiles(templatePath)
	if err != nil {
		fmt.Printf("Could not create template %s: %s (skip)\n", templatePath, err)
	}

	// Build a test file with benchmarking to validate the endpoint.
	// In the future, refactor this into a test runner instead of generating test
	// files for each endpoint.
	testCaseTemplatePath := filepath.Join(p.Dir, "templates/endpoint_test_template.tmpl")
	testCaseTemplate, err := template.New("endpoint_test_template.tmpl").Funcs(funcMap).ParseFiles(testCaseTemplatePath)
	if err != nil {
		fmt.Printf("Could not create template %s: %s (skip)\n", templatePath, err)
	}

	prefix := os.Args[1]
	// Iterate over all passed in endpoints.
	for i := 2; i < len(os.Args); i++ {
		endpoint := os.Args[i]
		endpointDir := prefix + string(os.PathSeparator) + strings.ToLower(endpoint)
		os.Mkdir(endpointDir, 0755)
		// PLACEHOLDER, REPLACE WITH HANDLERS FROM GENERATED CODE.
		// Read all handlers for an endpoint and generate each.

		handlers := []string{"foo"}
		for j := 0; j < len(handlers); j++ {
			dest := endpointDir + string(os.PathSeparator) + strings.ToLower(handlers[j]) + "_handler.go"
			file, err := os.Create(dest)
			if err != nil {
				fmt.Printf("Could not create %s: %s (skip)\n", dest, err)
				continue
			}

			// TODO(sindelar): Use an endpoint to client map.
			downstreamService := endpoint
			downstreamMethod := os.Args[i]

			vals := map[string]string{
				"MyHandler":         handlers[j],
				"Package":           endpoint,
				"DownstreamService": downstreamService,
				"DownstreamMethod":  downstreamMethod,
			}
			handlerTemplate.ExecuteTemplate(file, "endpoint_template.tmpl", vals)

			file.Close()

			dest = endpointDir + string(os.PathSeparator) + strings.ToLower(handlers[j]) + "_handler_test.go"
			file, err = os.Create(dest)
			if err != nil {
				fmt.Printf("Could not create %s: %s (skip)\n", dest, err)
				continue
			}

			// TODO(sindelar): Read from golden file.

			var clientResponse = "{\\\"statusCode\\\":200}"
			var endpointPath = "/googlenow/add-credentials"
			var endpointHttpMethod = "POST"
			var clientPath = "/add-credentials"
			var clientHttpMethod = "POST"
			var endpointRequest = "{\\\"testrequest\\\"}"

			vals = map[string]string{
				"MyHandler":          handlers[j],
				"Package":            endpoint,
				"DownstreamService":  downstreamService,
				"DownstreamMethod":   downstreamMethod,
				"EndpointPath":       endpointPath,
				"EndpointHttpMethod": endpointHttpMethod,
				"ClientPath":         clientPath,
				"ClientHttpMethod":   clientHttpMethod,
				"ClientResponse":     clientResponse,
				"EndpointRequest": 	  endpointRequest,
			}
			testCaseTemplate.Execute(file, vals)

			file.Close()
		}
	}
}
<commit_msg>Use serviceSpec<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// 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 (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

func main() {
	funcMap := template.FuncMap{
		"Title": strings.Title,
	}

	// Hacky way to find the template directory. Switch to use zw's template helpers
	// once they are landed.
	importPath := "github.com/uber/zanzibar/lib/gencode"
	p, err := build.Default.Import(importPath, "", build.FindOnly)
	if err != nil {
		panic(fmt.Sprintf("Could not create build path for endpoint generation: %s", err))
	}
	templatePath := filepath.Join(p.Dir, "templates/endpoint_template.tmpl")
	handlerTemplate, err := template.New("endpoint_template.tmpl").Funcs(funcMap).ParseFiles(templatePath)
	if err != nil {
		fmt.Printf("Could not create template %s: %s (skip)\n", templatePath, err)
	}

	// Build a test file with benchmarking to validate the endpoint.
	// In the future, refactor this into a test runner instead of generating test
	// files for each endpoint.
	testCaseTemplatePath := filepath.Join(p.Dir, "templates/endpoint_test_template.tmpl")
	testCaseTemplate, err := template.New("endpoint_test_template.tmpl").Funcs(funcMap).ParseFiles(testCaseTemplatePath)
	if err != nil {
		fmt.Printf("Could not create template %s: %s (skip)\n", templatePath, err)
	}

	prefix := os.Args[1]
	// Iterate over all passed in endpoints.
	for i := 2; i < len(os.Args); i++ {
		endpoint := os.Args[i]
		endpointDir := prefix + string(os.PathSeparator) + strings.ToLower(endpoint)
		os.Mkdir(endpointDir, 0755)

		// PLACEHOLDER, REPLACE WITH HANDLERS FROM GENERATED CODE.
		// Read all handlers for an endpoint and generate each.
		ServiceSpec()

		handlers := []string{"foo"}
		fmt.Printf("Methods for %s: %s \n", endpoint, handlers)

		for j := 0; j < len(handlers); j++ {
			dest := endpointDir + string(os.PathSeparator) + strings.ToLower(handlers[j]) + "_handler.go"
			file, err := os.Create(dest)
			if err != nil {
				fmt.Printf("Could not create %s: %s (skip)\n", dest, err)
				continue
			}

			// TODO(sindelar): Use an endpoint to client map.
			downstreamService := endpoint
			downstreamMethod := os.Args[i]

			vals := map[string]string{
				"MyHandler":         handlers[j],
				"Package":           endpoint,
				"DownstreamService": downstreamService,
				"DownstreamMethod":  downstreamMethod,
			}
			handlerTemplate.ExecuteTemplate(file, "endpoint_template.tmpl", vals)

			file.Close()

			dest = endpointDir + string(os.PathSeparator) + strings.ToLower(handlers[j]) + "_handler_test.go"
			file, err = os.Create(dest)
			if err != nil {
				fmt.Printf("Could not create %s: %s (skip)\n", dest, err)
				continue
			}

			// TODO(sindelar): Read from golden file.

			var clientResponse = "{\\\"statusCode\\\":200}"
			var endpointPath = "/googlenow/add-credentials"
			var endpointHttpMethod = "POST"
			var clientPath = "/add-credentials"
			var clientHttpMethod = "POST"
			var endpointRequest = "{\\\"testrequest\\\"}"

			vals = map[string]string{
				"MyHandler":          handlers[j],
				"Package":            endpoint,
				"DownstreamService":  downstreamService,
				"DownstreamMethod":   downstreamMethod,
				"EndpointPath":       endpointPath,
				"EndpointHttpMethod": endpointHttpMethod,
				"ClientPath":         clientPath,
				"ClientHttpMethod":   clientHttpMethod,
				"ClientResponse":     clientResponse,
				"EndpointRequest": 	  endpointRequest,
			}
			testCaseTemplate.Execute(file, vals)

			file.Close()
		}
	}
}
<|endoftext|>


<commit_before>package server

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"

	guerrilla "github.com/flashmob/go-guerrilla"
	"github.com/flashmob/go-guerrilla/util"
)

type SmtpdServer struct {
	mainConfig guerrilla.Config
	config     guerrilla.ServerConfig
	tlsConfig  *tls.Config
	maxSize    int // max email DATA size
	timeout    time.Duration
	sem        chan int // currently active client list
}

// Upgrades the connection to TLS
// Sets up buffers with the upgraded connection
func (server *SmtpdServer) upgradeToTls(client *guerrilla.Client) bool {
	var tlsConn *tls.Conn
	tlsConn = tls.Server(client.Conn, server.tlsConfig)
	err := tlsConn.Handshake()
	if err == nil {
		client.Conn = net.Conn(tlsConn)
		client.Bufin = guerrilla.NewSMTPBufferedReader(client.Conn)
		client.Bufout = bufio.NewWriter(client.Conn)
		client.TLS = true

		return true
	}

	log.WithError(err).Warn("Failed to TLS handshake")
	return false
}

func (server *SmtpdServer) handleClient(client *guerrilla.Client, backend guerrilla.Backend) {
	defer server.closeClient(client)
	advertiseTLS := "250-STARTTLS\r\n"
	if server.config.TLSAlwaysOn {
		if server.upgradeToTls(client) {
			advertiseTLS = ""
		}
	}
	greeting := fmt.Sprintf("220 %s SMTP guerrillad(%s) #%d (%d) %s",
		server.config.Hostname, guerrilla.Version, client.ClientID,
		len(server.sem), time.Now().Format(time.RFC1123Z))

	if !server.config.StartTLS {
		// STARTTLS turned off
		advertiseTLS = ""
	}
	for i := 0; i < 100; i++ {
		switch client.State {
		case 0:
			responseAdd(client, greeting)
			client.State = 1
		case 1:
			client.Bufin.SetLimit(guerrilla.CommandMaxLength)
			input, err := server.readSmtp(client)
			if err != nil {
				if err == io.EOF {
					log.WithError(err).Debugf("Client closed the connection already: %s", client.Address)
					return
				} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
					log.WithError(err).Debugf("Timeout: %s", client.Address)
					return
				} else if err == guerrilla.InputLimitExceeded {
					responseAdd(client, "500 Line too long.")
					// kill it so that another one can connect
					killClient(client)
				}
				log.WithError(err).Warnf("Read error: %s", client.Address)
				break
			}
			input = strings.Trim(input, " \n\r")
			bound := len(input)
			if bound > 16 {
				bound = 16
			}
			cmd := strings.ToUpper(input[0:bound])
			switch {
			case strings.Index(cmd, "HELO") == 0:
				if len(input) > 5 {
					client.Helo = input[5:]
				}
				responseAdd(client, "250 "+server.config.Hostname+" Hello ")
			case strings.Index(cmd, "EHLO") == 0:
				if len(input) > 5 {
					client.Helo = input[5:]
				}
				responseAdd(client, fmt.Sprintf(
					`250-%s Hello %s[%s]\r
250-SIZE %d\r
250-PIPELINING \r
%s250 HELP`,
					server.config.Hostname, client.Helo, client.Address,
					server.config.MaxSize, advertiseTLS))
			case strings.Index(cmd, "HELP") == 0:
				responseAdd(client, "250 Help! I need somebody...")
			case strings.Index(cmd, "MAIL FROM:") == 0:
				if len(input) > 10 {
					client.MailFrom = input[10:]
				}
				responseAdd(client, "250 Ok")
			case strings.Index(cmd, "XCLIENT") == 0:
				// Nginx sends this
				// XCLIENT ADDR=212.96.64.216 NAME=[UNAVAILABLE]
				client.Address = input[13:]
				client.Address = client.Address[0:strings.Index(client.Address, " ")]
				fmt.Println("client address:[" + client.Address + "]")
				responseAdd(client, "250 OK")
			case strings.Index(cmd, "RCPT TO:") == 0:
				if len(input) > 8 {
					client.RcptTo = input[8:]
				}
				responseAdd(client, "250 Accepted")
			case strings.Index(cmd, "NOOP") == 0:
				responseAdd(client, "250 OK")
			case strings.Index(cmd, "RSET") == 0:
				client.MailFrom = ""
				client.RcptTo = ""
				responseAdd(client, "250 OK")
			case strings.Index(cmd, "DATA") == 0:
				responseAdd(client, "354 Enter message, ending with \".\" on a line by itself")
				client.State = 2
			case (strings.Index(cmd, "STARTTLS") == 0) &&
				!client.TLS &&
				server.config.StartTLS:
				responseAdd(client, "220 Ready to start TLS")
				// go to start TLS state
				client.State = 3
			case strings.Index(cmd, "QUIT") == 0:
				responseAdd(client, "221 Bye")
				killClient(client)
			default:
				responseAdd(client, "500 unrecognized command: "+cmd)
				client.Errors++
				if client.Errors > 3 {
					responseAdd(client, "500 Too many unrecognized commands")
					killClient(client)
				}
			}
		case 2:
			var err error
			client.Bufin.SetLimit(int64(server.config.MaxSize) + 1024000) // This is a hard limit.
			client.Data, err = server.readSmtp(client)
			if err == nil {
				from, mailErr := util.ExtractEmail(client.MailFrom)
				if mailErr != nil {
					responseAdd(client, fmt.Sprintf("550 Error: invalid from: ", mailErr.Error()))
				} else {
					// TODO: support multiple RcptTo
					to, mailErr := util.ExtractEmail(client.RcptTo)
					if mailErr != nil {
						responseAdd(client, fmt.Sprintf("550 Error: invalid from: ", mailErr.Error()))
					} else {
						client.MailFrom = from.String()
						client.RcptTo = to.String()
						if !server.mainConfig.IsAllowed(to.Host) {
							responseAdd(client, "550 Error: not allowed")
						} else {
							toArray := []*guerrilla.EmailParts{to}
							resp := backend.Process(client, from, toArray)
							responseAdd(client, resp)
						}
					}
				}

			} else {
				if err == guerrilla.InputLimitExceeded {
					// hard limit reached, end to make room for other clients
					responseAdd(client, "550 Error: DATA limit exceeded by more than a megabyte!")
					killClient(client)
				} else {
					responseAdd(client, "550 Error: "+err.Error())
				}

				log.WithError(err).Warn("DATA read error")
			}
			client.State = 1
		case 3:
			// upgrade to TLS
			if server.upgradeToTls(client) {
				advertiseTLS = ""
				client.State = 1
			}
		}
		// Send a response back to the client
		err := server.responseWrite(client)
		if err != nil {
			if err == io.EOF {
				// client closed the connection already
				return
			}
			if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
				// too slow, timeout
				return
			}
		}
		if client.KillTime > 1 {
			return
		}
	}

}

// add a response on the response buffer
func responseAdd(client *guerrilla.Client, line string) {
	client.Response = line + "\r\n"
}
func (server *SmtpdServer) closeClient(client *guerrilla.Client) {
	client.Conn.Close()
	<-server.sem // Done; enable next client to run.
}
func killClient(client *guerrilla.Client) {
	client.KillTime = time.Now().Unix()
}

// Reads from the smtpBufferedReader, can be in command state or data state.
func (server *SmtpdServer) readSmtp(client *guerrilla.Client) (input string, err error) {
	var reply string
	// Command state terminator by default
	suffix := "\r\n"
	if client.State == 2 {
		// DATA state ends with a dot on a line by itself
		suffix = "\r\n.\r\n"
	}
	for err == nil {
		client.Conn.SetDeadline(time.Now().Add(server.timeout * time.Second))
		reply, err = client.Bufin.ReadString('\n')
		if reply != "" {
			input = input + reply
			if len(input) > server.config.MaxSize {
				err = fmt.Errorf("Maximum DATA size exceeded (%d)", server.config.MaxSize)
				return input, err
			}
			if client.State == 2 {
				// Extract the subject while we are at it.
				scanSubject(client, reply)
			}
		}
		if err != nil {
			break
		}
		if strings.HasSuffix(input, suffix) {
			break
		}
	}
	return input, err
}

// Scan the data part for a Subject line. Can be a multi-line
func scanSubject(client *guerrilla.Client, reply string) {
	if client.Subject == "" && (len(reply) > 8) {
		test := strings.ToUpper(reply[0:9])
		if i := strings.Index(test, "SUBJECT: "); i == 0 {
			// first line with \r\n
			client.Subject = reply[9:]
		}
	} else if strings.HasSuffix(client.Subject, "\r\n") {
		// chop off the \r\n
		client.Subject = client.Subject[0 : len(client.Subject)-2]
		if (strings.HasPrefix(reply, " ")) || (strings.HasPrefix(reply, "\t")) {
			// subject is multi-line
			client.Subject = client.Subject + reply[1:]
		}
	}
}

func (server *SmtpdServer) responseWrite(client *guerrilla.Client) (err error) {
	var size int
	client.Conn.SetDeadline(time.Now().Add(server.timeout * time.Second))
	size, err = client.Bufout.WriteString(client.Response)
	client.Bufout.Flush()
	client.Response = client.Response[size:]
	return err
}
<commit_msg>bug fix: the EHLO response wasn't formatted properly<commit_after>package server

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"

	guerrilla "github.com/flashmob/go-guerrilla"
	"github.com/flashmob/go-guerrilla/util"
)

type SmtpdServer struct {
	mainConfig guerrilla.Config
	config     guerrilla.ServerConfig
	tlsConfig  *tls.Config
	maxSize    int // max email DATA size
	timeout    time.Duration
	sem        chan int // currently active client list
}

// Upgrades the connection to TLS
// Sets up buffers with the upgraded connection
func (server *SmtpdServer) upgradeToTls(client *guerrilla.Client) bool {
	var tlsConn *tls.Conn
	tlsConn = tls.Server(client.Conn, server.tlsConfig)
	err := tlsConn.Handshake()
	if err == nil {
		client.Conn = net.Conn(tlsConn)
		client.Bufin = guerrilla.NewSMTPBufferedReader(client.Conn)
		client.Bufout = bufio.NewWriter(client.Conn)
		client.TLS = true

		return true
	}

	log.WithError(err).Warn("Failed to TLS handshake")
	return false
}

func (server *SmtpdServer) handleClient(client *guerrilla.Client, backend guerrilla.Backend) {
	defer server.closeClient(client)
	advertiseTLS := "250-STARTTLS\r\n"
	if server.config.TLSAlwaysOn {
		if server.upgradeToTls(client) {
			advertiseTLS = ""
		}
	}
	greeting := fmt.Sprintf("220 %s SMTP guerrillad(%s) #%d (%d) %s",
		server.config.Hostname, guerrilla.Version, client.ClientID,
		len(server.sem), time.Now().Format(time.RFC1123Z))

	if !server.config.StartTLS {
		// STARTTLS turned off
		advertiseTLS = ""
	}
	for i := 0; i < 100; i++ {
		switch client.State {
		case 0:
			responseAdd(client, greeting)
			client.State = 1
		case 1:
			client.Bufin.SetLimit(guerrilla.CommandMaxLength)
			input, err := server.readSmtp(client)
			if err != nil {
				if err == io.EOF {
					log.WithError(err).Debugf("Client closed the connection already: %s", client.Address)
					return
				} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
					log.WithError(err).Debugf("Timeout: %s", client.Address)
					return
				} else if err == guerrilla.InputLimitExceeded {
					responseAdd(client, "500 Line too long.")
					// kill it so that another one can connect
					killClient(client)
				}
				log.WithError(err).Warnf("Read error: %s", client.Address)
				break
			}
			input = strings.Trim(input, " \n\r")
			bound := len(input)
			if bound > 16 {
				bound = 16
			}
			cmd := strings.ToUpper(input[0:bound])
			switch {
			case strings.Index(cmd, "HELO") == 0:
				if len(input) > 5 {
					client.Helo = input[5:]
				}
				responseAdd(client, "250 "+server.config.Hostname+" Hello ")
			case strings.Index(cmd, "EHLO") == 0:
				if len(input) > 5 {
					client.Helo = input[5:]
				}
				responseAdd(client, fmt.Sprintf(
					"250-%s Hello %s[%s]\r\n"+
					"250-SIZE %d\r\n" +
					"250-PIPELINING\r\n" +
					"%s250 HELP",
					server.config.Hostname, client.Helo, client.Address,
					server.config.MaxSize, advertiseTLS))
			case strings.Index(cmd, "HELP") == 0:
				responseAdd(client, "250 Help! I need somebody...")
			case strings.Index(cmd, "MAIL FROM:") == 0:
				if len(input) > 10 {
					client.MailFrom = input[10:]
				}
				responseAdd(client, "250 Ok")
			case strings.Index(cmd, "XCLIENT") == 0:
				// Nginx sends this
				// XCLIENT ADDR=212.96.64.216 NAME=[UNAVAILABLE]
				client.Address = input[13:]
				client.Address = client.Address[0:strings.Index(client.Address, " ")]
				fmt.Println("client address:[" + client.Address + "]")
				responseAdd(client, "250 OK")
			case strings.Index(cmd, "RCPT TO:") == 0:
				if len(input) > 8 {
					client.RcptTo = input[8:]
				}
				responseAdd(client, "250 Accepted")
			case strings.Index(cmd, "NOOP") == 0:
				responseAdd(client, "250 OK")
			case strings.Index(cmd, "RSET") == 0:
				client.MailFrom = ""
				client.RcptTo = ""
				responseAdd(client, "250 OK")
			case strings.Index(cmd, "DATA") == 0:
				responseAdd(client, "354 Enter message, ending with \".\" on a line by itself")
				client.State = 2
			case (strings.Index(cmd, "STARTTLS") == 0) &&
				!client.TLS &&
				server.config.StartTLS:
				responseAdd(client, "220 Ready to start TLS")
				// go to start TLS state
				client.State = 3
			case strings.Index(cmd, "QUIT") == 0:
				responseAdd(client, "221 Bye")
				killClient(client)
			default:
				responseAdd(client, "500 unrecognized command: "+cmd)
				client.Errors++
				if client.Errors > 3 {
					responseAdd(client, "500 Too many unrecognized commands")
					killClient(client)
				}
			}
		case 2:
			var err error
			client.Bufin.SetLimit(int64(server.config.MaxSize) + 1024000) // This is a hard limit.
			client.Data, err = server.readSmtp(client)
			if err == nil {
				from, mailErr := util.ExtractEmail(client.MailFrom)
				if mailErr != nil {
					responseAdd(client, fmt.Sprintf("550 Error: invalid from: ", mailErr.Error()))
				} else {
					// TODO: support multiple RcptTo
					to, mailErr := util.ExtractEmail(client.RcptTo)
					if mailErr != nil {
						responseAdd(client, fmt.Sprintf("550 Error: invalid from: ", mailErr.Error()))
					} else {
						client.MailFrom = from.String()
						client.RcptTo = to.String()
						if !server.mainConfig.IsAllowed(to.Host) {
							responseAdd(client, "550 Error: not allowed")
						} else {
							toArray := []*guerrilla.EmailParts{to}
							resp := backend.Process(client, from, toArray)
							responseAdd(client, resp)
						}
					}
				}

			} else {
				if err == guerrilla.InputLimitExceeded {
					// hard limit reached, end to make room for other clients
					responseAdd(client, "550 Error: DATA limit exceeded by more than a megabyte!")
					killClient(client)
				} else {
					responseAdd(client, "550 Error: "+err.Error())
				}

				log.WithError(err).Warn("DATA read error")
			}
			client.State = 1
		case 3:
			// upgrade to TLS
			if server.upgradeToTls(client) {
				advertiseTLS = ""
				client.State = 1
			}
		}
		// Send a response back to the client
		err := server.responseWrite(client)
		if err != nil {
			if err == io.EOF {
				// client closed the connection already
				return
			}
			if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
				// too slow, timeout
				return
			}
		}
		if client.KillTime > 1 {
			return
		}
	}

}

// add a response on the response buffer
func responseAdd(client *guerrilla.Client, line string) {
	client.Response = line + "\r\n"
}
func (server *SmtpdServer) closeClient(client *guerrilla.Client) {
	client.Conn.Close()
	<-server.sem // Done; enable next client to run.
}
func killClient(client *guerrilla.Client) {
	client.KillTime = time.Now().Unix()
}

// Reads from the smtpBufferedReader, can be in command state or data state.
func (server *SmtpdServer) readSmtp(client *guerrilla.Client) (input string, err error) {
	var reply string
	// Command state terminator by default
	suffix := "\r\n"
	if client.State == 2 {
		// DATA state ends with a dot on a line by itself
		suffix = "\r\n.\r\n"
	}
	for err == nil {
		client.Conn.SetDeadline(time.Now().Add(server.timeout * time.Second))
		reply, err = client.Bufin.ReadString('\n')
		if reply != "" {
			input = input + reply
			if len(input) > server.config.MaxSize {
				err = fmt.Errorf("Maximum DATA size exceeded (%d)", server.config.MaxSize)
				return input, err
			}
			if client.State == 2 {
				// Extract the subject while we are at it.
				scanSubject(client, reply)
			}
		}
		if err != nil {
			break
		}
		if strings.HasSuffix(input, suffix) {
			break
		}
	}
	return input, err
}

// Scan the data part for a Subject line. Can be a multi-line
func scanSubject(client *guerrilla.Client, reply string) {
	if client.Subject == "" && (len(reply) > 8) {
		test := strings.ToUpper(reply[0:9])
		if i := strings.Index(test, "SUBJECT: "); i == 0 {
			// first line with \r\n
			client.Subject = reply[9:]
		}
	} else if strings.HasSuffix(client.Subject, "\r\n") {
		// chop off the \r\n
		client.Subject = client.Subject[0 : len(client.Subject)-2]
		if (strings.HasPrefix(reply, " ")) || (strings.HasPrefix(reply, "\t")) {
			// subject is multi-line
			client.Subject = client.Subject + reply[1:]
		}
	}
}

func (server *SmtpdServer) responseWrite(client *guerrilla.Client) (err error) {
	var size int
	client.Conn.SetDeadline(time.Now().Add(server.timeout * time.Second))
	size, err = client.Bufout.WriteString(client.Response)
	client.Bufout.Flush()
	client.Response = client.Response[size:]
	return err
}
<|endoftext|>


<commit_before>package router

import (
	"bytes"
	"io/ioutil"
	"net/http"

	log "github.com/Sirupsen/logrus"
)

type responseLogger struct {
	w      http.ResponseWriter
	status int
	size   int
	b      bytes.Buffer
}

func (l *responseLogger) Header() http.Header {
	return l.w.Header()
}

func (l *responseLogger) Write(b []byte) (int, error) {
	if l.status == 0 {
		// The status will be StatusOK if WriteHeader has not been called yet
		l.status = http.StatusOK
	}
	l.b.Write(b)
	size, err := l.w.Write(b)
	l.size += size
	return size, err
}

func (l *responseLogger) WriteHeader(s int) {
	l.w.WriteHeader(s)
	l.status = s
}

func (l *responseLogger) Status() int {
	return l.status
}

func (l *responseLogger) Size() int {
	return l.size
}

func (l *responseLogger) String() string {
	return l.b.String()
}

func LoggingMiddleware(next http.Handler, skipRequestBody bool) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Debugf("%v %v", r.Method, r.RequestURI)

		log.Debugln("------ Header: ------")
		for key, value := range r.Header {
			log.Debugf("%s: %v", key, value)
		}

		body, _ := ioutil.ReadAll(r.Body)
		r.Body = ioutil.NopCloser(bytes.NewReader(body))

		log.Debugln("------ Request: ------")
		if !skipRequestBody && (r.Header.Get("Content-Type") == "" || r.Header.Get("Content-Type") == "application/json") {
			log.Debugln(string(body))
		} else {
			log.Debugf("%d bytes of request body", len(body))
		}

		rlogger := &responseLogger{w: w}
		next.ServeHTTP(rlogger, r)

		log.Debugln("------ Response: ------")
		if w.Header().Get("Content-Type") == "" || w.Header().Get("Content-Type") == "application/json" {
			log.Debugln(rlogger.String())
		} else {
			log.Debugf("%d bytes of response body", len(rlogger.String()))
		}
	})
}
<commit_msg>Remove logging for asset download<commit_after>package router

import (
	"bytes"
	"io/ioutil"
	"net/http"

	log "github.com/Sirupsen/logrus"
)

type responseLogger struct {
	w      http.ResponseWriter
	status int
	size   int
	b      bytes.Buffer
}

func (l *responseLogger) Header() http.Header {
	return l.w.Header()
}

func (l *responseLogger) Write(b []byte) (int, error) {
	if l.status == 0 {
		// The status will be StatusOK if WriteHeader has not been called yet
		l.status = http.StatusOK
	}
	l.b.Write(b)
	size, err := l.w.Write(b)
	l.size += size
	return size, err
}

func (l *responseLogger) WriteHeader(s int) {
	l.w.WriteHeader(s)
	l.status = s
}

func (l *responseLogger) Status() int {
	return l.status
}

func (l *responseLogger) Size() int {
	return l.size
}

func (l *responseLogger) String() string {
	return l.b.String()
}

func LoggingMiddleware(next http.Handler, skipBody bool) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Debugf("%v %v", r.Method, r.RequestURI)

		log.Debugln("------ Header: ------")
		for key, value := range r.Header {
			log.Debugf("%s: %v", key, value)
		}

		body, _ := ioutil.ReadAll(r.Body)
		r.Body = ioutil.NopCloser(bytes.NewReader(body))

		log.Debugln("------ Request: ------")
		if !skipBody && (r.Header.Get("Content-Type") == "" || r.Header.Get("Content-Type") == "application/json") {
			log.Debugln(string(body))
		} else {
			log.Debugf("%d bytes of request body", len(body))
		}

		rlogger := &responseLogger{w: w}
		next.ServeHTTP(rlogger, r)

		log.Debugln("------ Response: ------")
		if !skipBody && (w.Header().Get("Content-Type") == "" || w.Header().Get("Content-Type") == "application/json") {
			log.Debugln(rlogger.String())
		} else {
			log.Debugf("%d bytes of response body", len(rlogger.String()))
		}
	})
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "time"
    "math/rand"
    "flag"
)

var randomCount = flag.Int("randoms", 5, "Number of randoms to generate")

func timedRandom(randomCount int, timedRandomChannel chan uint32, quit chan uint32) {
    for i := 0; i < randomCount; i++ {
        time.Sleep(200 * time.Millisecond)
        timedRandomChannel <- rand.New(rand.NewSource(time.Now().UnixNano())).Uint32()
    }

    quit <- 0
}

func main() {
    flag.Parse()

    timedRandomChannel := make(chan uint32)
    quit := make(chan uint32)

    go timedRandom(*randomCount, timedRandomChannel, quit)

    main:
        for {
            var randomNumber uint32
            select {
                case randomNumber = <-timedRandomChannel:
                    fmt.Println(randomNumber)
                case <-quit:
                    break main
            }
        }

    fmt.Println("you have all the randoms woo!")
}
<commit_msg>Changed package name<commit_after>package time_random

import (
    "fmt"
    "time"
    "math/rand"
    "flag"
)

var randomCount = flag.Int("randoms", 5, "Number of randoms to generate")

func timedRandom(randomCount int, timedRandomChannel chan uint32, quit chan uint32) {
    for i := 0; i < randomCount; i++ {
        time.Sleep(200 * time.Millisecond)
        timedRandomChannel <- rand.New(rand.NewSource(time.Now().UnixNano())).Uint32()
    }

    quit <- 0
}

func main() {
    flag.Parse()

    timedRandomChannel := make(chan uint32)
    quit := make(chan uint32)

    go timedRandom(*randomCount, timedRandomChannel, quit)

    main:
        for {
            var randomNumber uint32
            select {
                case randomNumber = <-timedRandomChannel:
                    fmt.Println(randomNumber)
                case <-quit:
                    break main
            }
        }

    fmt.Println("you have all the randoms woo!")
}
<|endoftext|>


<commit_before>package imageprocessor

import (
	"image"
	"image/color"
	"io/ioutil"
	"testing"
)

var (
	jpgPath  = "../test/img/Lenna.jpg"
	bmpPath  = "../test/img/Lenna.bmp"
	pngPath  = "../test/img/Lenna.png"
	gifPath  = "../test/img/Lenna.gif"
	confPath = "../test/test_conf.json"
)

var (
	jpegBin, _ = ioutil.ReadFile(jpgPath)
	bmpBin, _  = ioutil.ReadFile(bmpPath)
	pngBin, _  = ioutil.ReadFile(pngPath)
	gifBin, _  = ioutil.ReadFile(gifPath)
	confBin, _ = ioutil.ReadFile(confPath)
)

var testRect = image.Rect(0, 0, 100, 100)
var ResizeImage = resizeImage
var ResizeAndFillImage = resizeAndFillImage
var Crop = crop

func TestEncodeJpeg(t *testing.T) {
	img, _ := DecodeImage(jpegBin)
	bin, err := EncodeJpeg(img.GetImg(), -1)
	if err != nil {
		t.Fatalf("err is %v.", err)
	}
	if bin == nil {
		t.Fatalf("bin is nil.")
	}

	img, _ = DecodeImage(confBin)
	_, err = EncodeJpeg(img.GetImg(), 50)
	if err == nil {
		t.Fatalf("err is %v.", err)
	}
}

func TestDecodeImage(t *testing.T) {
	img, err := DecodeImage(nil)
	if err == nil {
		t.Fatalf("err is nil")
	}

	img, err = DecodeImage(jpegBin)
	if err != nil {
		t.Log(err)
		t.Fatalf("err is not nil.")
	}
	if img == nil {
		t.Fatalf("can not decode.")
	}

	img, err = DecodeImage(bmpBin)
	if err != nil {
		t.Fatalf("err is not nil. : %v", err)
	}
	if img == nil {
		t.Fatalf("img.%v", img)
	}

	img, err = DecodeImage(pngBin)
	if err != nil {
		t.Log(err)
		t.Fatalf("err is not nil.")
	}
	if img == nil {
		t.Fatalf("can not decode.")
	}

	img, err = DecodeImage(gifBin)
	if err != nil {
		t.Log(err)
		t.Fatalf("err is not nil.")
	}
	if img == nil {
		t.Fatalf("can not decode.")
	}

	img, err = DecodeImage(confBin)
	if err == nil {
		t.Log(err)
		t.Fatalf("err is nil")
	}

	if img == nil {
		t.Fatalf("can not decode.")
	}
}

func TestResizeImage(t *testing.T) {
	img, _ := DecodeImage(confBin)

	resizeImg := ResizeImage(*img.GetImg(), 100, 100, 10000, 10000)
	if resizeImg != nil {
		t.Fatalf("value is not nil.")
	}

	img, _ = DecodeImage(jpegBin)
	ii := *img.GetImg()
	jpegRect := ii.Bounds()

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X*2), uint(jpegRect.Max.Y*2), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X), uint(jpegRect.Max.Y), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X*100000), uint(jpegRect.Max.Y*100000), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X), uint(jpegRect.Max.Y*100000), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X*100000), uint(jpegRect.Max.Y), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X), uint(jpegRect.Max.Y+1000), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X+1000), uint(jpegRect.Max.Y), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X), uint(jpegRect.Max.Y-100), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X-100), uint(jpegRect.Max.Y), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), 0, 0, 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}
}

func TestResizeAndFillImage(t *testing.T) {
	c := color.RGBA{
		R: 0xff,
		G: 0xff,
		B: 0xff,
		A: 0xff,
	}
	img, _ := DecodeImage(confBin)

	fillImg := ResizeAndFillImage(*img.GetImg(), 100, 100, c, 10000, 10000)
	if fillImg != nil {
		t.Fatalf("value is not nil.")
	}

	img, _ = DecodeImage(pngBin)

	fillImg = ResizeAndFillImage(*img.GetImg(), 100, 100, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is nil.")
	}
	if fillImg.Bounds().Max.X != 100 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 100 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 1000, 100, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 1000 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 100 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 100, 1000, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 100 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 1000 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 5000, 5000, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 5000 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 5000 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 0, 0, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 512 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 1000000, 1000000, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 512 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)

func TestCrop(t *testing.T) {
	img, _ := DecodeImage(confBin)

	cropImg := Crop(*img.GetImg(), 100, 100)
	if cropImg != nil {
		t.Fatalf("value is not nil.")
	}

	img, _ = DecodeImage(pngBin)

	cropImg = Crop(*img.GetImg(), 100, 100)
	if cropImg == nil {
		t.Fatalf("value is nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 1000, 100)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 51 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 100, 1000)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 51 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 5000, 5000)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 0, 0)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 1000000, 1000000)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}
}
<commit_msg>デグレの修正<commit_after>package imageprocessor

import (
	"image"
	"image/color"
	"io/ioutil"
	"testing"
)

var (
	jpgPath  = "../test/img/Lenna.jpg"
	bmpPath  = "../test/img/Lenna.bmp"
	pngPath  = "../test/img/Lenna.png"
	gifPath  = "../test/img/Lenna.gif"
	confPath = "../test/test_conf.json"
)

var (
	jpegBin, _ = ioutil.ReadFile(jpgPath)
	bmpBin, _  = ioutil.ReadFile(bmpPath)
	pngBin, _  = ioutil.ReadFile(pngPath)
	gifBin, _  = ioutil.ReadFile(gifPath)
	confBin, _ = ioutil.ReadFile(confPath)
)

var testRect = image.Rect(0, 0, 100, 100)
var ResizeImage = resizeImage
var ResizeAndFillImage = resizeAndFillImage
var Crop = crop

func TestEncodeJpeg(t *testing.T) {
	img, _ := DecodeImage(jpegBin)
	bin, err := EncodeJpeg(img.GetImg(), -1)
	if err != nil {
		t.Fatalf("err is %v.", err)
	}
	if bin == nil {
		t.Fatalf("bin is nil.")
	}

	img, _ = DecodeImage(confBin)
	_, err = EncodeJpeg(img.GetImg(), 50)
	if err == nil {
		t.Fatalf("err is %v.", err)
	}
}

func TestDecodeImage(t *testing.T) {
	img, err := DecodeImage(nil)
	if err == nil {
		t.Fatalf("err is nil")
	}

	img, err = DecodeImage(jpegBin)
	if err != nil {
		t.Log(err)
		t.Fatalf("err is not nil.")
	}
	if img == nil {
		t.Fatalf("can not decode.")
	}

	img, err = DecodeImage(bmpBin)
	if err != nil {
		t.Fatalf("err is not nil. : %v", err)
	}
	if img == nil {
		t.Fatalf("img.%v", img)
	}

	img, err = DecodeImage(pngBin)
	if err != nil {
		t.Log(err)
		t.Fatalf("err is not nil.")
	}
	if img == nil {
		t.Fatalf("can not decode.")
	}

	img, err = DecodeImage(gifBin)
	if err != nil {
		t.Log(err)
		t.Fatalf("err is not nil.")
	}
	if img == nil {
		t.Fatalf("can not decode.")
	}

	img, err = DecodeImage(confBin)
	if err == nil {
		t.Log(err)
		t.Fatalf("err is nil")
	}

	if img == nil {
		t.Fatalf("can not decode.")
	}
}

func TestResizeImage(t *testing.T) {
	img, _ := DecodeImage(confBin)

	resizeImg := ResizeImage(*img.GetImg(), 100, 100, 10000, 10000)
	if resizeImg != nil {
		t.Fatalf("value is not nil.")
	}

	img, _ = DecodeImage(jpegBin)
	ii := *img.GetImg()
	jpegRect := ii.Bounds()

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X*2), uint(jpegRect.Max.Y*2), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X), uint(jpegRect.Max.Y), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X*100000), uint(jpegRect.Max.Y*100000), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X), uint(jpegRect.Max.Y*100000), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X*100000), uint(jpegRect.Max.Y), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X), uint(jpegRect.Max.Y+1000), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X+1000), uint(jpegRect.Max.Y), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X), uint(jpegRect.Max.Y-100), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), uint(jpegRect.Max.X-100), uint(jpegRect.Max.Y), 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}

	resizeImg = ResizeImage(*img.GetImg(), 0, 0, 10000, 10000)
	if resizeImg == nil {
		t.Fatalf("value is nil.")
	}
}

func TestResizeAndFillImage(t *testing.T) {
	c := color.RGBA{
		R: 0xff,
		G: 0xff,
		B: 0xff,
		A: 0xff,
	}
	img, _ := DecodeImage(confBin)

	fillImg := ResizeAndFillImage(*img.GetImg(), 100, 100, c, 10000, 10000)
	if fillImg != nil {
		t.Fatalf("value is not nil.")
	}

	img, _ = DecodeImage(pngBin)

	fillImg = ResizeAndFillImage(*img.GetImg(), 100, 100, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is nil.")
	}
	if fillImg.Bounds().Max.X != 100 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 100 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 1000, 100, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 1000 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 100 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 100, 1000, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 100 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 1000 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 5000, 5000, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 5000 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 5000 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 0, 0, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 512 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}

	fillImg = ResizeAndFillImage(*img.GetImg(), 1000000, 1000000, c, 10000, 10000)
	if fillImg == nil {
		t.Fatalf("value is not nil.")
	}
	if fillImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
	if fillImg.Bounds().Max.Y != 512 {
		t.Fatalf("x is %v.", fillImg.Bounds().Max.X)
	}
}

func TestCrop(t *testing.T) {
	img, _ := DecodeImage(confBin)

	cropImg := Crop(*img.GetImg(), 100, 100)
	if cropImg != nil {
		t.Fatalf("value is not nil.")
	}

	img, _ = DecodeImage(pngBin)

	cropImg = Crop(*img.GetImg(), 100, 100)
	if cropImg == nil {
		t.Fatalf("value is nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 1000, 100)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 51 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 100, 1000)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 51 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 5000, 5000)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 0, 0)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}

	cropImg = Crop(*img.GetImg(), 1000000, 1000000)
	if cropImg == nil {
		t.Fatalf("value is not nil.")
	}
	if cropImg.Bounds().Max.X != 512 {
		t.Fatalf("x is %v.", cropImg.Bounds().Max.X)
	}
	if cropImg.Bounds().Max.Y != 512 {
		t.Fatalf("y is %v.", cropImg.Bounds().Max.Y)
	}
}
<|endoftext|>