<commit_before>package minify // import "github.com/tdewolff/minify"

import (
	"bytes"
	"encoding/base64"
	"math"
	"net/url"
	"strconv"

	"github.com/tdewolff/parse"
)

// Epsilon is the closest number to zero that is not considered to be zero.
var Epsilon = 0.00001

var (
	zeroBytes = []byte("0")
)

// ContentType minifies a given mediatype by removing all whitespace.
func ContentType(b []byte) []byte {
	j := 0
	start := 0
	inString := false
	for i, c := range b {
		if !inString && parse.IsWhitespace(c) {
			if start != 0 {
				j += copy(b[j:], b[start:i])
			} else {
				j += i
			}
			start = i + 1
		} else if c == '"' {
			inString = !inString
		}
	}
	if start != 0 {
		j += copy(b[j:], b[start:])
		return parse.ToLower(b[:j])
	}
	return parse.ToLower(b)
}

// DataURI minifies a data URI and calls a minifier by the specified mediatype. Specifications: https://www.ietf.org/rfc/rfc2397.txt.
func DataURI(m Minifier, dataURI []byte) []byte {
	if mediatype, data, err := parse.DataURI(dataURI); err == nil {
		dataURI, _ = Bytes(m, string(mediatype), data)
		base64Len := len(";base64") + base64.StdEncoding.EncodedLen(len(dataURI))
		asciiLen := len(dataURI)
		for _, c := range dataURI {
			if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-' || c == '_' || c == '.' || c == '~' || c == ' ' {
				asciiLen++
			} else {
				asciiLen += 2
			}
			if asciiLen > base64Len {
				break
			}
		}
		if asciiLen > base64Len {
			encoded := make([]byte, base64Len-len(";base64"))
			base64.StdEncoding.Encode(encoded, dataURI)
			dataURI = encoded
			mediatype = append(mediatype, []byte(";base64")...)
		} else {
			dataURI = []byte(url.QueryEscape(string(dataURI)))
			dataURI = bytes.Replace(dataURI, []byte("\""), []byte("\\\""), -1)
		}
		if len(mediatype) >= len("text/plain") && bytes.HasPrefix(mediatype, []byte("text/plain")) {
			mediatype = mediatype[len("text/plain"):]
		}
		dataURI = append(append(append([]byte("data:"), mediatype...), ','), dataURI...)
	}
	return dataURI
}

// Number minifies a given byte slice containing a number (see parse.Number) and remove superfluous characters.
func Number(num []byte) []byte {
	f, err := strconv.ParseFloat(string(num), 64)
	if err != nil {
		return num
	}
	if math.Abs(f) < Epsilon {
		return zeroBytes
	}
	if num[0] == '-' {
		n := 1
		for n < len(num) && num[n] == '0' {
			n++
		}
		num = num[n-1:]
		num[0] = '-'
	} else {
		if num[0] == '+' {
			num = num[1:]
		}
		// trim 0 left
		for len(num) > 0 && num[0] == '0' {
			num = num[1:]
		}
	}
	// trim 0 right
	for i, digit := range num {
		if digit == '.' {
			j := len(num) - 1
			for ; j > i; j-- {
				if num[j] == '0' {
					num = num[:len(num)-1]
				} else {
					break
				}
			}
			if j == i {
				num = num[:len(num)-1] // remove .
			}
			break
		}
	}
	return num
}
<commit_msg>TODO omit ParseFloat<commit_after>package minify // import "github.com/tdewolff/minify"

import (
	"bytes"
	"encoding/base64"
	"math"
	"net/url"
	"strconv"

	"github.com/tdewolff/parse"
)

// Epsilon is the closest number to zero that is not considered to be zero.
var Epsilon = 0.00001

var (
	zeroBytes = []byte("0")
)

// ContentType minifies a given mediatype by removing all whitespace.
func ContentType(b []byte) []byte {
	j := 0
	start := 0
	inString := false
	for i, c := range b {
		if !inString && parse.IsWhitespace(c) {
			if start != 0 {
				j += copy(b[j:], b[start:i])
			} else {
				j += i
			}
			start = i + 1
		} else if c == '"' {
			inString = !inString
		}
	}
	if start != 0 {
		j += copy(b[j:], b[start:])
		return parse.ToLower(b[:j])
	}
	return parse.ToLower(b)
}

// DataURI minifies a data URI and calls a minifier by the specified mediatype. Specifications: https://www.ietf.org/rfc/rfc2397.txt.
func DataURI(m Minifier, dataURI []byte) []byte {
	if mediatype, data, err := parse.DataURI(dataURI); err == nil {
		dataURI, _ = Bytes(m, string(mediatype), data)
		base64Len := len(";base64") + base64.StdEncoding.EncodedLen(len(dataURI))
		asciiLen := len(dataURI)
		for _, c := range dataURI {
			if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-' || c == '_' || c == '.' || c == '~' || c == ' ' {
				asciiLen++
			} else {
				asciiLen += 2
			}
			if asciiLen > base64Len {
				break
			}
		}
		if asciiLen > base64Len {
			encoded := make([]byte, base64Len-len(";base64"))
			base64.StdEncoding.Encode(encoded, dataURI)
			dataURI = encoded
			mediatype = append(mediatype, []byte(";base64")...)
		} else {
			dataURI = []byte(url.QueryEscape(string(dataURI)))
			dataURI = bytes.Replace(dataURI, []byte("\""), []byte("\\\""), -1)
		}
		if len(mediatype) >= len("text/plain") && bytes.HasPrefix(mediatype, []byte("text/plain")) {
			mediatype = mediatype[len("text/plain"):]
		}
		dataURI = append(append(append([]byte("data:"), mediatype...), ','), dataURI...)
	}
	return dataURI
}

// TODO: omit ParseFloat in favor of counting digit-zero bytes on the left, also useful for using exponents as shorter notations
// Number minifies a given byte slice containing a number (see parse.Number) and remove superfluous characters.
func Number(num []byte) []byte {
	f, err := strconv.ParseFloat(string(num), 64)
	if err != nil {
		return num
	}
	if math.Abs(f) < Epsilon {
		return zeroBytes
	}
	if num[0] == '-' {
		n := 1
		for n < len(num) && num[n] == '0' {
			n++
		}
		num = num[n-1:]
		num[0] = '-'
	} else {
		if num[0] == '+' {
			num = num[1:]
		}
		// trim 0 left
		for len(num) > 0 && num[0] == '0' {
			num = num[1:]
		}
	}
	// trim 0 right
	for i, digit := range num {
		if digit == '.' {
			j := len(num) - 1
			for ; j > i; j-- {
				if num[j] == '0' {
					num = num[:len(num)-1]
				} else {
					break
				}
			}
			if j == i {
				num = num[:len(num)-1] // remove .
			}
			break
		}
	}
	return num
}
<|endoftext|>


<commit_before>package enry

import (
	"bufio"
	"bytes"
	"path/filepath"
	"regexp"
	"strings"

	"gopkg.in/src-d/enry.v1/data"
)

// OtherLanguage is used as a zero value when a function can not return a specific language.
const OtherLanguage = ""

// Strategy type fix the signature for the functions that can be used as a strategy.
type Strategy func(filename string, content []byte, candidates []string) (languages []string)

// DefaultStrategies is the strategies' sequence GetLanguage uses to detect languages.
var DefaultStrategies = []Strategy{
	GetLanguagesByModeline,
	GetLanguagesByFilename,
	GetLanguagesByShebang,
	GetLanguagesByExtension,
	GetLanguagesByContent,
	GetLanguagesByClassifier,
}

var DefaultClassifier Classifier = &classifier{
	languagesLogProbabilities: data.LanguagesLogProbabilities,
	tokensLogProbabilities:    data.TokensLogProbabilities,
	tokensTotal:               data.TokensTotal,
}

// GetLanguage applies a sequence of strategies based on the given filename and content
// to find out the most probably language to return.
func GetLanguage(filename string, content []byte) (language string) {
	languages := GetLanguages(filename, content)
	return firstLanguage(languages)
}

func firstLanguage(languages []string) string {
	if len(languages) == 0 {
		return OtherLanguage
	}

	return languages[0]
}

// GetLanguageByModeline returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByModeline(content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByModeline, "", content, nil)
}

// GetLanguageByEmacsModeline returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByEmacsModeline(content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByEmacsModeline, "", content, nil)
}

// GetLanguageByVimModeline returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByVimModeline(content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByVimModeline, "", content, nil)
}

// GetLanguageByFilename returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByFilename(filename string) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByFilename, filename, nil, nil)
}

// GetLanguageByShebang returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByShebang(content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByShebang, "", content, nil)
}

// GetLanguageByExtension returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByExtension(filename string) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByExtension, filename, nil, nil)
}

// GetLanguageByContent returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByContent(filename string, content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByContent, filename, content, nil)
}

// GetLanguageByClassifier returns the most probably language detected for the given content. It uses
// DefaultClassifier, if no candidates are provided it returns OtherLanguage.
func GetLanguageByClassifier(content []byte, candidates []string) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByClassifier, "", content, candidates)
}

func getLanguageByStrategy(strategy Strategy, filename string, content []byte, candidates []string) (string, bool) {
	languages := strategy(filename, content, candidates)
	return getFirstLanguageAndSafe(languages)
}

func getFirstLanguageAndSafe(languages []string) (language string, safe bool) {
	language = firstLanguage(languages)
	safe = len(languages) == 1
	return
}

// GetLanguageBySpecificClassifier returns the most probably language for the given content using
// classifier to detect language.
func GetLanguageBySpecificClassifier(content []byte, candidates []string, classifier Classifier) (language string, safe bool) {
	languages := GetLanguagesBySpecificClassifier(content, candidates, classifier)
	return getFirstLanguageAndSafe(languages)
}

// GetLanguages applies a sequence of strategies based on the given filename and content
// to find out the most probably languages to return.
func GetLanguages(filename string, content []byte) []string {
	if IsBinary(content) {
		return nil
	}

	var languages []string
	candidates := []string{}
	for _, strategy := range DefaultStrategies {
		languages = strategy(filename, content, candidates)
		if len(languages) == 1 {
			return languages
		}

		if len(languages) > 0 {
			candidates = append(candidates, languages...)
		}
	}

	return languages
}

// GetLanguagesByModeline returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByModeline(_ string, content []byte, candidates []string) []string {
	headFoot := getHeaderAndFooter(content)
	var languages []string
	for _, getLang := range modelinesFunc {
		languages = getLang("", headFoot, candidates)
		if len(languages) > 0 {
			break
		}
	}

	return languages
}

var modelinesFunc = []Strategy{
	GetLanguagesByEmacsModeline,
	GetLanguagesByVimModeline,
}

func getHeaderAndFooter(content []byte) []byte {
	const searchScope = 5

	if len(content) == 0 {
		return content
	}

	if bytes.Count(content, []byte("\n")) < 2*searchScope {
		return content
	}

	header := headScope(content, searchScope)
	footer := footScope(content, searchScope)
	headerAndFooter := make([]byte, 0, len(content[:header])+len(content[footer:]))
	headerAndFooter = append(headerAndFooter, content[:header]...)
	headerAndFooter = append(headerAndFooter, content[footer:]...)
	return headerAndFooter
}

func headScope(content []byte, scope int) (index int) {
	for i := 0; i < scope; i++ {
		eol := bytes.IndexAny(content, "\n")
		content = content[eol+1:]
		index += eol
	}

	return index + scope - 1
}

func footScope(content []byte, scope int) (index int) {
	for i := 0; i < scope; i++ {
		index = bytes.LastIndexAny(content, "\n")
		content = content[:index]
	}

	return index + 1
}

var (
	reEmacsModeline = regexp.MustCompile(`.*-\*-\s*(.+?)\s*-\*-.*(?m:$)`)
	reEmacsLang     = regexp.MustCompile(`.*(?i:mode)\s*:\s*([^\s;]+)\s*;*.*`)
	reVimModeline   = regexp.MustCompile(`(?:(?m:\s|^)vi(?:m[<=>]?\d+|m)?|[\t\x20]*ex)\s*[:]\s*(.*)(?m:$)`)
	reVimLang       = regexp.MustCompile(`(?i:filetype|ft|syntax)\s*=(\w+)(?:\s|:|$)`)
)

// GetLanguagesByEmacsModeline returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByEmacsModeline(_ string, content []byte, _ []string) []string {
	matched := reEmacsModeline.FindAllSubmatch(content, -1)
	if matched == nil {
		return nil
	}

	// only take the last matched line, discard previous lines
	lastLineMatched := matched[len(matched)-1][1]
	matchedAlias := reEmacsLang.FindSubmatch(lastLineMatched)
	var alias string
	if matchedAlias != nil {
		alias = string(matchedAlias[1])
	} else {
		alias = string(lastLineMatched)
	}

	language, ok := GetLanguageByAlias(alias)
	if !ok {
		return nil
	}

	return []string{language}
}

// GetLanguagesByVimModeline returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByVimModeline(_ string, content []byte, _ []string) []string {
	matched := reVimModeline.FindAllSubmatch(content, -1)
	if matched == nil {
		return nil
	}

	// only take the last matched line, discard previous lines
	lastLineMatched := matched[len(matched)-1][1]
	matchedAlias := reVimLang.FindAllSubmatch(lastLineMatched, -1)
	if matchedAlias == nil {
		return nil
	}

	alias := string(matchedAlias[0][1])
	if len(matchedAlias) > 1 {
		// cases:
		// matchedAlias = [["syntax=ruby " "ruby"] ["ft=python " "python"] ["filetype=perl " "perl"]] returns OtherLanguage;
		// matchedAlias = [["syntax=python " "python"] ["ft=python " "python"] ["filetype=python " "python"]] returns "Python";
		for _, match := range matchedAlias {
			otherAlias := string(match[1])
			if otherAlias != alias {
				return nil
			}
		}
	}

	language, ok := GetLanguageByAlias(alias)
	if !ok {
		return nil
	}

	return []string{language}
}

// GetLanguagesByFilename returns a slice of possible languages for the given filename.
// It complies with the signature to be a Strategy type.
func GetLanguagesByFilename(filename string, _ []byte, _ []string) []string {
	if filename == "" {
		return nil
	}

	return data.LanguagesByFilename[filepath.Base(filename)]
}

// GetLanguagesByShebang returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByShebang(_ string, content []byte, _ []string) (languages []string) {
	interpreter := getInterpreter(content)
	return data.LanguagesByInterpreter[interpreter]
}

var (
	shebangExecHack = regexp.MustCompile(`exec (\w+).+\$0.+\$@`)
	pythonVersion   = regexp.MustCompile(`python\d\.\d+`)
)

func getInterpreter(data []byte) (interpreter string) {
	line := getFirstLine(data)
	if !hasShebang(line) {
		return ""
	}

	// skip shebang
	line = bytes.TrimSpace(line[2:])
	splitted := bytes.Fields(line)
	if len(splitted) == 0 {
		return ""
	}

	if bytes.Contains(splitted[0], []byte("env")) {
		if len(splitted) > 1 {
			interpreter = string(splitted[1])
		}
	} else {
		splittedPath := bytes.Split(splitted[0], []byte{'/'})
		interpreter = string(splittedPath[len(splittedPath)-1])
	}

	if interpreter == "sh" {
		interpreter = lookForMultilineExec(data)
	}

	if pythonVersion.MatchString(interpreter) {
		interpreter = interpreter[:strings.Index(interpreter, `.`)]
	}

	return
}

func getFirstLine(data []byte) []byte {
	buf := bufio.NewScanner(bytes.NewReader(data))
	buf.Scan()
	line := buf.Bytes()
	if err := buf.Err(); err != nil {
		return nil
	}

	return line
}

func hasShebang(line []byte) bool {
	const shebang = `#!`
	prefix := []byte(shebang)
	return bytes.HasPrefix(line, prefix)
}

func lookForMultilineExec(data []byte) string {
	const magicNumOfLines = 5
	interpreter := "sh"

	buf := bufio.NewScanner(bytes.NewReader(data))
	for i := 0; i < magicNumOfLines && buf.Scan(); i++ {
		line := buf.Bytes()
		if shebangExecHack.Match(line) {
			interpreter = shebangExecHack.FindStringSubmatch(string(line))[1]
			break
		}
	}

	if err := buf.Err(); err != nil {
		return interpreter
	}

	return interpreter
}

// GetLanguagesByExtension returns a slice of possible languages for the given filename.
// It complies with the signature to be a Strategy type.
func GetLanguagesByExtension(filename string, _ []byte, _ []string) []string {
	if !strings.Contains(filename, ".") {
		return nil
	}

	filename = strings.ToLower(filename)
	dots := getDotIndexes(filename)
	for _, dot := range dots {
		ext := filename[dot:]
		languages, ok := data.LanguagesByExtension[ext]
		if ok {
			return languages
		}
	}

	return nil
}

func getDotIndexes(filename string) []int {
	dots := make([]int, 0, 2)
	for i, letter := range filename {
		if letter == rune('.') {
			dots = append(dots, i)
		}
	}

	return dots
}

// GetLanguagesByContent returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByContent(filename string, content []byte, _ []string) []string {
	if filename == "" {
		return nil
	}

	ext := strings.ToLower(filepath.Ext(filename))
	fnMatcher, ok := data.ContentMatchers[ext]
	if !ok {
		return nil
	}

	return fnMatcher(content)
}

// GetLanguagesByClassifier uses DefaultClassifier as a Classifier and returns a sorted slice of possible languages ordered by
// decreasing language's probability. If there are not candidates it returns nil. It complies with the signature to be a Strategy type.
func GetLanguagesByClassifier(filename string, content []byte, candidates []string) (languages []string) {
	if len(candidates) == 0 {
		return nil
	}

	return GetLanguagesBySpecificClassifier(content, candidates, DefaultClassifier)
}

// GetLanguagesBySpecificClassifier returns a slice of possible languages. It takes in a Classifier to be used.
func GetLanguagesBySpecificClassifier(content []byte, candidates []string, classifier Classifier) (languages []string) {
	mapCandidates := make(map[string]float64)
	for _, candidate := range candidates {
		mapCandidates[candidate]++
	}

	return classifier.Classify(content, mapCandidates)
}

// GetLanguageExtensions returns the different extensions being used by the language.
func GetLanguageExtensions(language string) []string {
	return data.ExtensionsByLanguage[language]
}

// Type represent language's type. Either data, programming, markup, prose, or unknown.
type Type int

// Type's values.
const (
	Unknown Type = iota
	Data
	Programming
	Markup
	Prose
)

// GetLanguageType returns the type of the given language.
func GetLanguageType(language string) (langType Type) {
	intType, ok := data.LanguagesType[language]
	langType = Type(intType)
	if !ok {
		langType = Unknown
	}
	return langType
}

// GetLanguageByAlias returns either the language related to the given alias and ok set to true
// or Otherlanguage and ok set to false if the alias is not recognized.
func GetLanguageByAlias(alias string) (lang string, ok bool) {
	a := strings.Split(alias, `,`)[0]
	a = strings.ToLower(a)
	lang, ok = data.LanguagesByAlias[a]
	if !ok {
		lang = OtherLanguage
	}

	return
}
<commit_msg>clarify GetLanguages usage<commit_after>package enry

import (
	"bufio"
	"bytes"
	"path/filepath"
	"regexp"
	"strings"

	"gopkg.in/src-d/enry.v1/data"
)

// OtherLanguage is used as a zero value when a function can not return a specific language.
const OtherLanguage = ""

// Strategy type fix the signature for the functions that can be used as a strategy.
type Strategy func(filename string, content []byte, candidates []string) (languages []string)

// DefaultStrategies is the strategies' sequence GetLanguage uses to detect languages.
var DefaultStrategies = []Strategy{
	GetLanguagesByModeline,
	GetLanguagesByFilename,
	GetLanguagesByShebang,
	GetLanguagesByExtension,
	GetLanguagesByContent,
	GetLanguagesByClassifier,
}

var DefaultClassifier Classifier = &classifier{
	languagesLogProbabilities: data.LanguagesLogProbabilities,
	tokensLogProbabilities:    data.TokensLogProbabilities,
	tokensTotal:               data.TokensTotal,
}

// GetLanguage applies a sequence of strategies based on the given filename and content
// to find out the most probably language to return.
func GetLanguage(filename string, content []byte) (language string) {
	languages := GetLanguages(filename, content)
	return firstLanguage(languages)
}

func firstLanguage(languages []string) string {
	if len(languages) == 0 {
		return OtherLanguage
	}

	return languages[0]
}

// GetLanguageByModeline returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByModeline(content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByModeline, "", content, nil)
}

// GetLanguageByEmacsModeline returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByEmacsModeline(content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByEmacsModeline, "", content, nil)
}

// GetLanguageByVimModeline returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByVimModeline(content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByVimModeline, "", content, nil)
}

// GetLanguageByFilename returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByFilename(filename string) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByFilename, filename, nil, nil)
}

// GetLanguageByShebang returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByShebang(content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByShebang, "", content, nil)
}

// GetLanguageByExtension returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByExtension(filename string) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByExtension, filename, nil, nil)
}

// GetLanguageByContent returns detected language. If there are more than one possibles languages
// it returns the first language by alphabetically order and safe to false.
func GetLanguageByContent(filename string, content []byte) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByContent, filename, content, nil)
}

// GetLanguageByClassifier returns the most probably language detected for the given content. It uses
// DefaultClassifier, if no candidates are provided it returns OtherLanguage.
func GetLanguageByClassifier(content []byte, candidates []string) (language string, safe bool) {
	return getLanguageByStrategy(GetLanguagesByClassifier, "", content, candidates)
}

func getLanguageByStrategy(strategy Strategy, filename string, content []byte, candidates []string) (string, bool) {
	languages := strategy(filename, content, candidates)
	return getFirstLanguageAndSafe(languages)
}

func getFirstLanguageAndSafe(languages []string) (language string, safe bool) {
	language = firstLanguage(languages)
	safe = len(languages) == 1
	return
}

// GetLanguageBySpecificClassifier returns the most probably language for the given content using
// classifier to detect language.
func GetLanguageBySpecificClassifier(content []byte, candidates []string, classifier Classifier) (language string, safe bool) {
	languages := GetLanguagesBySpecificClassifier(content, candidates, classifier)
	return getFirstLanguageAndSafe(languages)
}

// GetLanguages applies a sequence of strategies based on the given filename and content
// to find out the most probably languages to return.
// At least one of arguments should be set. If content is missing, language detection will be based on the filename.
// The function won't read the file, given an empty content.
func GetLanguages(filename string, content []byte) []string {
	if IsBinary(content) {
		return nil
	}

	var languages []string
	candidates := []string{}
	for _, strategy := range DefaultStrategies {
		languages = strategy(filename, content, candidates)
		if len(languages) == 1 {
			return languages
		}

		if len(languages) > 0 {
			candidates = append(candidates, languages...)
		}
	}

	return languages
}

// GetLanguagesByModeline returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByModeline(_ string, content []byte, candidates []string) []string {
	headFoot := getHeaderAndFooter(content)
	var languages []string
	for _, getLang := range modelinesFunc {
		languages = getLang("", headFoot, candidates)
		if len(languages) > 0 {
			break
		}
	}

	return languages
}

var modelinesFunc = []Strategy{
	GetLanguagesByEmacsModeline,
	GetLanguagesByVimModeline,
}

func getHeaderAndFooter(content []byte) []byte {
	const searchScope = 5

	if len(content) == 0 {
		return content
	}

	if bytes.Count(content, []byte("\n")) < 2*searchScope {
		return content
	}

	header := headScope(content, searchScope)
	footer := footScope(content, searchScope)
	headerAndFooter := make([]byte, 0, len(content[:header])+len(content[footer:]))
	headerAndFooter = append(headerAndFooter, content[:header]...)
	headerAndFooter = append(headerAndFooter, content[footer:]...)
	return headerAndFooter
}

func headScope(content []byte, scope int) (index int) {
	for i := 0; i < scope; i++ {
		eol := bytes.IndexAny(content, "\n")
		content = content[eol+1:]
		index += eol
	}

	return index + scope - 1
}

func footScope(content []byte, scope int) (index int) {
	for i := 0; i < scope; i++ {
		index = bytes.LastIndexAny(content, "\n")
		content = content[:index]
	}

	return index + 1
}

var (
	reEmacsModeline = regexp.MustCompile(`.*-\*-\s*(.+?)\s*-\*-.*(?m:$)`)
	reEmacsLang     = regexp.MustCompile(`.*(?i:mode)\s*:\s*([^\s;]+)\s*;*.*`)
	reVimModeline   = regexp.MustCompile(`(?:(?m:\s|^)vi(?:m[<=>]?\d+|m)?|[\t\x20]*ex)\s*[:]\s*(.*)(?m:$)`)
	reVimLang       = regexp.MustCompile(`(?i:filetype|ft|syntax)\s*=(\w+)(?:\s|:|$)`)
)

// GetLanguagesByEmacsModeline returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByEmacsModeline(_ string, content []byte, _ []string) []string {
	matched := reEmacsModeline.FindAllSubmatch(content, -1)
	if matched == nil {
		return nil
	}

	// only take the last matched line, discard previous lines
	lastLineMatched := matched[len(matched)-1][1]
	matchedAlias := reEmacsLang.FindSubmatch(lastLineMatched)
	var alias string
	if matchedAlias != nil {
		alias = string(matchedAlias[1])
	} else {
		alias = string(lastLineMatched)
	}

	language, ok := GetLanguageByAlias(alias)
	if !ok {
		return nil
	}

	return []string{language}
}

// GetLanguagesByVimModeline returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByVimModeline(_ string, content []byte, _ []string) []string {
	matched := reVimModeline.FindAllSubmatch(content, -1)
	if matched == nil {
		return nil
	}

	// only take the last matched line, discard previous lines
	lastLineMatched := matched[len(matched)-1][1]
	matchedAlias := reVimLang.FindAllSubmatch(lastLineMatched, -1)
	if matchedAlias == nil {
		return nil
	}

	alias := string(matchedAlias[0][1])
	if len(matchedAlias) > 1 {
		// cases:
		// matchedAlias = [["syntax=ruby " "ruby"] ["ft=python " "python"] ["filetype=perl " "perl"]] returns OtherLanguage;
		// matchedAlias = [["syntax=python " "python"] ["ft=python " "python"] ["filetype=python " "python"]] returns "Python";
		for _, match := range matchedAlias {
			otherAlias := string(match[1])
			if otherAlias != alias {
				return nil
			}
		}
	}

	language, ok := GetLanguageByAlias(alias)
	if !ok {
		return nil
	}

	return []string{language}
}

// GetLanguagesByFilename returns a slice of possible languages for the given filename.
// It complies with the signature to be a Strategy type.
func GetLanguagesByFilename(filename string, _ []byte, _ []string) []string {
	if filename == "" {
		return nil
	}

	return data.LanguagesByFilename[filepath.Base(filename)]
}

// GetLanguagesByShebang returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByShebang(_ string, content []byte, _ []string) (languages []string) {
	interpreter := getInterpreter(content)
	return data.LanguagesByInterpreter[interpreter]
}

var (
	shebangExecHack = regexp.MustCompile(`exec (\w+).+\$0.+\$@`)
	pythonVersion   = regexp.MustCompile(`python\d\.\d+`)
)

func getInterpreter(data []byte) (interpreter string) {
	line := getFirstLine(data)
	if !hasShebang(line) {
		return ""
	}

	// skip shebang
	line = bytes.TrimSpace(line[2:])
	splitted := bytes.Fields(line)
	if len(splitted) == 0 {
		return ""
	}

	if bytes.Contains(splitted[0], []byte("env")) {
		if len(splitted) > 1 {
			interpreter = string(splitted[1])
		}
	} else {
		splittedPath := bytes.Split(splitted[0], []byte{'/'})
		interpreter = string(splittedPath[len(splittedPath)-1])
	}

	if interpreter == "sh" {
		interpreter = lookForMultilineExec(data)
	}

	if pythonVersion.MatchString(interpreter) {
		interpreter = interpreter[:strings.Index(interpreter, `.`)]
	}

	return
}

func getFirstLine(data []byte) []byte {
	buf := bufio.NewScanner(bytes.NewReader(data))
	buf.Scan()
	line := buf.Bytes()
	if err := buf.Err(); err != nil {
		return nil
	}

	return line
}

func hasShebang(line []byte) bool {
	const shebang = `#!`
	prefix := []byte(shebang)
	return bytes.HasPrefix(line, prefix)
}

func lookForMultilineExec(data []byte) string {
	const magicNumOfLines = 5
	interpreter := "sh"

	buf := bufio.NewScanner(bytes.NewReader(data))
	for i := 0; i < magicNumOfLines && buf.Scan(); i++ {
		line := buf.Bytes()
		if shebangExecHack.Match(line) {
			interpreter = shebangExecHack.FindStringSubmatch(string(line))[1]
			break
		}
	}

	if err := buf.Err(); err != nil {
		return interpreter
	}

	return interpreter
}

// GetLanguagesByExtension returns a slice of possible languages for the given filename.
// It complies with the signature to be a Strategy type.
func GetLanguagesByExtension(filename string, _ []byte, _ []string) []string {
	if !strings.Contains(filename, ".") {
		return nil
	}

	filename = strings.ToLower(filename)
	dots := getDotIndexes(filename)
	for _, dot := range dots {
		ext := filename[dot:]
		languages, ok := data.LanguagesByExtension[ext]
		if ok {
			return languages
		}
	}

	return nil
}

func getDotIndexes(filename string) []int {
	dots := make([]int, 0, 2)
	for i, letter := range filename {
		if letter == rune('.') {
			dots = append(dots, i)
		}
	}

	return dots
}

// GetLanguagesByContent returns a slice of possible languages for the given content.
// It complies with the signature to be a Strategy type.
func GetLanguagesByContent(filename string, content []byte, _ []string) []string {
	if filename == "" {
		return nil
	}

	ext := strings.ToLower(filepath.Ext(filename))
	fnMatcher, ok := data.ContentMatchers[ext]
	if !ok {
		return nil
	}

	return fnMatcher(content)
}

// GetLanguagesByClassifier uses DefaultClassifier as a Classifier and returns a sorted slice of possible languages ordered by
// decreasing language's probability. If there are not candidates it returns nil. It complies with the signature to be a Strategy type.
func GetLanguagesByClassifier(filename string, content []byte, candidates []string) (languages []string) {
	if len(candidates) == 0 {
		return nil
	}

	return GetLanguagesBySpecificClassifier(content, candidates, DefaultClassifier)
}

// GetLanguagesBySpecificClassifier returns a slice of possible languages. It takes in a Classifier to be used.
func GetLanguagesBySpecificClassifier(content []byte, candidates []string, classifier Classifier) (languages []string) {
	mapCandidates := make(map[string]float64)
	for _, candidate := range candidates {
		mapCandidates[candidate]++
	}

	return classifier.Classify(content, mapCandidates)
}

// GetLanguageExtensions returns the different extensions being used by the language.
func GetLanguageExtensions(language string) []string {
	return data.ExtensionsByLanguage[language]
}

// Type represent language's type. Either data, programming, markup, prose, or unknown.
type Type int

// Type's values.
const (
	Unknown Type = iota
	Data
	Programming
	Markup
	Prose
)

// GetLanguageType returns the type of the given language.
func GetLanguageType(language string) (langType Type) {
	intType, ok := data.LanguagesType[language]
	langType = Type(intType)
	if !ok {
		langType = Unknown
	}
	return langType
}

// GetLanguageByAlias returns either the language related to the given alias and ok set to true
// or Otherlanguage and ok set to false if the alias is not recognized.
func GetLanguageByAlias(alias string) (lang string, ok bool) {
	a := strings.Split(alias, `,`)[0]
	a = strings.ToLower(a)
	lang, ok = data.LanguagesByAlias[a]
	if !ok {
		lang = OtherLanguage
	}

	return
}
<|endoftext|>


<commit_before>package project_test

import (
	"testing"

	"github.com/apex/apex/project"
	"github.com/apex/log"
	"github.com/apex/log/handlers/discard"
	"github.com/stretchr/testify/assert"

	_ "github.com/apex/apex/plugins/env"
	_ "github.com/apex/apex/plugins/golang"
	_ "github.com/apex/apex/plugins/hooks"
	_ "github.com/apex/apex/plugins/inference"
	_ "github.com/apex/apex/plugins/nodejs"
	_ "github.com/apex/apex/plugins/python"
	_ "github.com/apex/apex/plugins/shim"
)

func init() {
	log.SetHandler(discard.New())
}

func TestProject_Open_requireConfigValues(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/invalidName",
		Log:  log.Log,
	}
	nameErr := p.Open()

	assert.Contains(t, nameErr.Error(), "Name: zero value")
}

func TestProject_LoadFunctions_loadAll(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/twoFunctions",
		Log:  log.Log,
	}

	p.Open()
	p.LoadFunctions()

	assert.Equal(t, 2, len(p.Functions))
	assert.Equal(t, "bar", p.Functions[0].Name)
	assert.Equal(t, "foo", p.Functions[1].Name)
}

func TestProject_LoadFunctions_loadSpecified(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/twoFunctions",
		Log:  log.Log,
	}

	p.Open()
	p.LoadFunctions("foo")

	assert.Equal(t, 1, len(p.Functions))
	assert.Equal(t, "foo", p.Functions[0].Name)
}

func TestProject_LoadFunctions_onlyExisting(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/twoFunctions",
		Log:  log.Log,
	}

	p.Open()
	p.LoadFunctions("foo", "buz")

	assert.Equal(t, 1, len(p.Functions))
	assert.Equal(t, "foo", p.Functions[0].Name)
}

func TestProject_LoadFunctions_noFunctionLoaded(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/twoFunctions",
		Log:  log.Log,
	}

	p.Open()
	err := p.LoadFunctions("buz")

	assert.EqualError(t, err, "no function loaded")
}

func TestProject_LoadFunctionByPath_mergeEnvWithFunctionEnv(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/envMerge",
		Log:  log.Log,
	}

	p.Open()
	p.LoadFunctions("foo")

	assert.Equal(t, map[string]string{"PROJECT_ENV": "projectEnv", "FUNCTION_ENV": "functionEnv"}, p.Functions[0].Environment)
}
<commit_msg>add test for implicit env vars<commit_after>package project_test

import (
	"testing"

	"github.com/apex/apex/project"
	"github.com/apex/log"
	"github.com/apex/log/handlers/discard"
	"github.com/stretchr/testify/assert"

	_ "github.com/apex/apex/plugins/env"
	_ "github.com/apex/apex/plugins/golang"
	_ "github.com/apex/apex/plugins/hooks"
	_ "github.com/apex/apex/plugins/inference"
	_ "github.com/apex/apex/plugins/nodejs"
	_ "github.com/apex/apex/plugins/python"
	_ "github.com/apex/apex/plugins/shim"
)

func init() {
	log.SetHandler(discard.New())
}

func TestProject_Open_requireConfigValues(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/invalidName",
		Log:  log.Log,
	}
	nameErr := p.Open()

	assert.Contains(t, nameErr.Error(), "Name: zero value")
}

func TestProject_LoadFunctions_loadAll(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/twoFunctions",
		Log:  log.Log,
	}

	p.Open()
	p.LoadFunctions()

	assert.Equal(t, 2, len(p.Functions))
	assert.Equal(t, "bar", p.Functions[0].Name)
	assert.Equal(t, "foo", p.Functions[1].Name)
}

func TestProject_LoadFunctions_loadSpecified(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/twoFunctions",
		Log:  log.Log,
	}

	p.Open()
	p.LoadFunctions("foo")

	assert.Equal(t, 1, len(p.Functions))
	assert.Equal(t, "foo", p.Functions[0].Name)
}

func TestProject_LoadFunctions_onlyExisting(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/twoFunctions",
		Log:  log.Log,
	}

	p.Open()
	p.LoadFunctions("foo", "buz")

	assert.Equal(t, 1, len(p.Functions))
	assert.Equal(t, "foo", p.Functions[0].Name)
}

func TestProject_LoadFunctions_noFunctionLoaded(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/twoFunctions",
		Log:  log.Log,
	}

	p.Open()
	err := p.LoadFunctions("buz")

	assert.EqualError(t, err, "no function loaded")
}

func TestProject_LoadFunctionByPath_mergeEnvWithFunctionEnv(t *testing.T) {
	p := &project.Project{
		Path: "_fixtures/envMerge",
		Log:  log.Log,
	}

	p.Open()
	p.LoadFunctions("foo")

	assert.Equal(t, map[string]string{"PROJECT_ENV": "projectEnv", "FUNCTION_ENV": "functionEnv", "APEX_FUNCTION_NAME": "foo", "LAMBDA_FUNCTION_NAME": "envMerge_foo"}, p.Functions[0].Environment)
}
<|endoftext|>


<commit_before>package packed

import (
	"github.com/balzaczyy/golucene/core/util"
)

// packed/AbstractAppendingLongBuffer.java

const MIN_PAGE_SIZE = 64

// More than 1M doesn't really makes sense with these appending buffers
// since their goal is to try to have small number of bits per value
const MAX_PAGE_SIZE = 1 << 20

type abstractAppendingLongBufferSPI interface {
	packPendingValues()
	grow(int)
	baseRamBytesUsed() int64
	getBulk(int, int, []int64) int
}

/* Common functionality shared by AppendingDeltaPackedLongBuffer and MonotonicAppendingLongBuffer. */
type abstractAppendingLongBuffer struct {
	spi                     abstractAppendingLongBufferSPI
	pageShift, pageMask     int
	values                  []PackedIntsReader
	valuesBytes             int64
	valuesOff               int
	pending                 []int64
	pendingOff              int
	acceptableOverheadRatio float32
}

func newAbstractAppendingLongBuffer(spi abstractAppendingLongBufferSPI,
	initialPageCount, pageSize int, acceptableOverheadRatio float32) *abstractAppendingLongBuffer {
	ps := checkBlockSize(pageSize, MIN_PAGE_SIZE, MAX_PAGE_SIZE)
	return &abstractAppendingLongBuffer{
		spi:                     spi,
		values:                  make([]PackedIntsReader, initialPageCount),
		pending:                 make([]int64, pageSize),
		pageShift:               ps,
		pageMask:                ps - 1,
		acceptableOverheadRatio: acceptableOverheadRatio,
	}
}

func (buf *abstractAppendingLongBuffer) pageSize() int {
	return buf.pageMask + 1
}

/* Get the numbre of values that have been added to the buffer. */
func (buf *abstractAppendingLongBuffer) Size() int64 {
	size := int64(buf.pendingOff)
	if buf.valuesOff > 0 {
		size += int64(buf.values[buf.valuesOff-1].Size())
	}
	if buf.valuesOff > 1 {
		size += int64((buf.valuesOff - 1) * buf.pageSize())
	}
	return size
}

/* Append a value to this buffer. */
func (buf *abstractAppendingLongBuffer) Add(l int64) {
	assert2(buf.pending != nil, "This buffer is frozen")
	if buf.pendingOff == len(buf.pending) {
		// check size
		if len(buf.values) == buf.valuesOff {
			newLength := util.Oversize(buf.valuesOff+1, 8)
			buf.spi.grow(newLength)
		}
		buf.spi.packPendingValues()
		buf.valuesBytes += buf.values[buf.valuesOff].RamBytesUsed()
		buf.valuesOff++
		// reset pending buffer
		buf.pendingOff = 0
	}
	buf.pending[buf.pendingOff] = l
	buf.pendingOff++
}

func (buf *abstractAppendingLongBuffer) grow(newBlockCount int) {
	arr := make([]PackedIntsReader, newBlockCount)
	copy(arr, buf.values)
	buf.values = arr
}

func (buf *abstractAppendingLongBuffer) Iterator() func() (int64, bool) {
	var currentValues []int64
	vOff, pOff := 0, 0
	var currentCount int // number of entries of the current page

	fillValues := func() {
		if vOff == buf.valuesOff {
			currentValues = buf.pending
			currentCount = buf.pendingOff
		} else {
			currentCount = int(buf.values[vOff].Size())
			for k := 0; k < currentCount; {
				k += buf.spi.getBulk(vOff, k, currentValues[k:currentCount])
			}
		}
	}

	if buf.valuesOff == 0 {
		currentValues = buf.pending
		currentCount = buf.pendingOff
	} else {
		currentValues = make([]int64, len(buf.values))
		fillValues()
	}

	return func() (int64, bool) {
		if pOff >= currentCount {
			return 0, false
		}
		result := currentValues[pOff]
		if pOff == currentCount {
			vOff++
			pOff = 0
			if vOff <= buf.valuesOff {
				fillValues()
			} else {
				currentCount = 0
			}
		}
		return result, true
	}
}

func (buf *abstractAppendingLongBuffer) baseRamBytesUsed() int64 {
	return util.NUM_BYTES_OBJECT_HEADER +
		2*util.NUM_BYTES_OBJECT_REF + // the 2 arrays
		2*util.NUM_BYTES_INT + // the 2 offsets
		2*util.NUM_BYTES_INT + // pageShift, pageMask
		util.NUM_BYTES_FLOAT + // acceptable overhead
		util.NUM_BYTES_LONG // valuesBytes
}

/* Return the number of bytes used by this instance. */
func (buf *abstractAppendingLongBuffer) RamBytesUsed() int64 {
	// TODO: this is called per-doc-per-norm/dv-field, can we optimize this?
	return util.AlignObjectSize(buf.spi.baseRamBytesUsed()) +
		util.SizeOf(buf.pending) +
		util.ShallowSizeOf(buf.values) +
		buf.valuesBytes
}

/*
Utility class to buffer a list of signed int64 in memory. This class
only supports appending and is optimized for the case where values
are close to each other.
*/
type AppendingDeltaPackedLongBuffer struct {
	*abstractAppendingLongBuffer
	minValues []int64
}

func NewAppendingDeltaPackedLongBuffer(initialPageCount,
	pageSize int, acceptableOverheadRatio float32) *AppendingDeltaPackedLongBuffer {
	ans := &AppendingDeltaPackedLongBuffer{minValues: make([]int64, initialPageCount)}
	ans.abstractAppendingLongBuffer = newAbstractAppendingLongBuffer(ans, initialPageCount, pageSize, acceptableOverheadRatio)
	return ans
}

/*
Create an AppendingDeltaPackedLongBuffer with initialPageCount=16,
pageSize=1024
*/
func NewAppendingDeltaPackedLongBufferWithOverhead(acceptableOverheadRatio float32) *AppendingDeltaPackedLongBuffer {
	return NewAppendingDeltaPackedLongBuffer(16, 1024, acceptableOverheadRatio)
}

func (buf *AppendingDeltaPackedLongBuffer) getBulk(block, element int, arr []int64) int {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) packPendingValues() {
	// compute max delta
	minValue, maxValue := buf.pending[0], buf.pending[0]
	for _, v := range buf.pending[1:buf.pendingOff] {
		if v < minValue {
			minValue = v
		} else if v > maxValue {
			maxValue = v
		}
	}
	delta := maxValue - minValue

	buf.minValues[buf.valuesOff] = minValue
	if delta == 0 {
		panic("niy")
	} else {
		// build a new packed reader
		bitsRequired := UnsignedBitsRequired(delta)
		for i := 0; i < buf.pendingOff; i++ {
			buf.pending[i] -= minValue
		}
		mutable := MutableFor(buf.pendingOff, bitsRequired, buf.acceptableOverheadRatio)
		for i := 0; i < buf.pendingOff; i++ {
			i += mutable.setBulk(i, buf.pending[i:buf.pendingOff])
		}
		buf.values[buf.valuesOff] = mutable
	}
}

func (buf *AppendingDeltaPackedLongBuffer) grow(newBlockCount int) {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) baseRamBytesUsed() int64 {
	return buf.abstractAppendingLongBuffer.baseRamBytesUsed() +
		util.NUM_BYTES_OBJECT_REF
}

func (buf *AppendingDeltaPackedLongBuffer) RamBytesUsed() int64 {
	return buf.abstractAppendingLongBuffer.RamBytesUsed() + util.SizeOf(buf.minValues)
}
<commit_msg>fix incorrect page mask<commit_after>package packed

import (
	"github.com/balzaczyy/golucene/core/util"
)

// packed/AbstractAppendingLongBuffer.java

const MIN_PAGE_SIZE = 64

// More than 1M doesn't really makes sense with these appending buffers
// since their goal is to try to have small number of bits per value
const MAX_PAGE_SIZE = 1 << 20

type abstractAppendingLongBufferSPI interface {
	packPendingValues()
	grow(int)
	baseRamBytesUsed() int64
	getBulk(int, int, []int64) int
}

/* Common functionality shared by AppendingDeltaPackedLongBuffer and MonotonicAppendingLongBuffer. */
type abstractAppendingLongBuffer struct {
	spi                     abstractAppendingLongBufferSPI
	pageShift, pageMask     int
	values                  []PackedIntsReader
	valuesBytes             int64
	valuesOff               int
	pending                 []int64
	pendingOff              int
	acceptableOverheadRatio float32
}

func newAbstractAppendingLongBuffer(spi abstractAppendingLongBufferSPI,
	initialPageCount, pageSize int, acceptableOverheadRatio float32) *abstractAppendingLongBuffer {
	pageShift := checkBlockSize(pageSize, MIN_PAGE_SIZE, MAX_PAGE_SIZE)
	return &abstractAppendingLongBuffer{
		spi:                     spi,
		values:                  make([]PackedIntsReader, initialPageCount),
		pending:                 make([]int64, pageSize),
		pageShift:               pageShift,
		pageMask:                pageSize - 1,
		acceptableOverheadRatio: acceptableOverheadRatio,
	}
}

func (buf *abstractAppendingLongBuffer) pageSize() int {
	return buf.pageMask + 1
}

/* Get the numbre of values that have been added to the buffer. */
func (buf *abstractAppendingLongBuffer) Size() int64 {
	size := int64(buf.pendingOff)
	if buf.valuesOff > 0 {
		size += int64(buf.values[buf.valuesOff-1].Size())
	}
	if buf.valuesOff > 1 {
		size += int64(buf.valuesOff-1) * int64(buf.pageSize())
	}
	return size
}

/* Append a value to this buffer. */
func (buf *abstractAppendingLongBuffer) Add(l int64) {
	assert2(buf.pending != nil, "This buffer is frozen")
	if buf.pendingOff == len(buf.pending) {
		// check size
		if len(buf.values) == buf.valuesOff {
			newLength := util.Oversize(buf.valuesOff+1, 8)
			buf.spi.grow(newLength)
		}
		buf.spi.packPendingValues()
		buf.valuesBytes += buf.values[buf.valuesOff].RamBytesUsed()
		buf.valuesOff++
		// reset pending buffer
		buf.pendingOff = 0
	}
	buf.pending[buf.pendingOff] = l
	buf.pendingOff++
}

func (buf *abstractAppendingLongBuffer) grow(newBlockCount int) {
	arr := make([]PackedIntsReader, newBlockCount)
	copy(arr, buf.values)
	buf.values = arr
}

func (buf *abstractAppendingLongBuffer) Iterator() func() (int64, bool) {
	var currentValues []int64
	vOff, pOff := 0, 0
	var currentCount int // number of entries of the current page

	fillValues := func() {
		if vOff == buf.valuesOff {
			currentValues = buf.pending
			currentCount = buf.pendingOff
		} else {
			currentCount = int(buf.values[vOff].Size())
			for k := 0; k < currentCount; {
				k += buf.spi.getBulk(vOff, k, currentValues[k:currentCount])
			}
		}
	}

	if buf.valuesOff == 0 {
		currentValues = buf.pending
		currentCount = buf.pendingOff
	} else {
		currentValues = make([]int64, len(buf.values))
		fillValues()
	}

	return func() (int64, bool) {
		if pOff >= currentCount {
			return 0, false
		}
		result := currentValues[pOff]
		if pOff == currentCount {
			vOff++
			pOff = 0
			if vOff <= buf.valuesOff {
				fillValues()
			} else {
				currentCount = 0
			}
		}
		return result, true
	}
}

func (buf *abstractAppendingLongBuffer) baseRamBytesUsed() int64 {
	return util.NUM_BYTES_OBJECT_HEADER +
		2*util.NUM_BYTES_OBJECT_REF + // the 2 arrays
		2*util.NUM_BYTES_INT + // the 2 offsets
		2*util.NUM_BYTES_INT + // pageShift, pageMask
		util.NUM_BYTES_FLOAT + // acceptable overhead
		util.NUM_BYTES_LONG // valuesBytes
}

/* Return the number of bytes used by this instance. */
func (buf *abstractAppendingLongBuffer) RamBytesUsed() int64 {
	// TODO: this is called per-doc-per-norm/dv-field, can we optimize this?
	return util.AlignObjectSize(buf.spi.baseRamBytesUsed()) +
		util.SizeOf(buf.pending) +
		util.ShallowSizeOf(buf.values) +
		buf.valuesBytes
}

/*
Utility class to buffer a list of signed int64 in memory. This class
only supports appending and is optimized for the case where values
are close to each other.
*/
type AppendingDeltaPackedLongBuffer struct {
	*abstractAppendingLongBuffer
	minValues []int64
}

func NewAppendingDeltaPackedLongBuffer(initialPageCount,
	pageSize int, acceptableOverheadRatio float32) *AppendingDeltaPackedLongBuffer {
	ans := &AppendingDeltaPackedLongBuffer{minValues: make([]int64, initialPageCount)}
	ans.abstractAppendingLongBuffer = newAbstractAppendingLongBuffer(ans, initialPageCount, pageSize, acceptableOverheadRatio)
	return ans
}

/*
Create an AppendingDeltaPackedLongBuffer with initialPageCount=16,
pageSize=1024
*/
func NewAppendingDeltaPackedLongBufferWithOverhead(acceptableOverheadRatio float32) *AppendingDeltaPackedLongBuffer {
	return NewAppendingDeltaPackedLongBuffer(16, 1024, acceptableOverheadRatio)
}

func (buf *AppendingDeltaPackedLongBuffer) getBulk(block, element int, arr []int64) int {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) packPendingValues() {
	// compute max delta
	minValue, maxValue := buf.pending[0], buf.pending[0]
	for _, v := range buf.pending[1:buf.pendingOff] {
		if v < minValue {
			minValue = v
		} else if v > maxValue {
			maxValue = v
		}
	}
	delta := maxValue - minValue

	buf.minValues[buf.valuesOff] = minValue
	if delta == 0 {
		panic("niy")
	} else {
		// build a new packed reader
		bitsRequired := UnsignedBitsRequired(delta)
		for i := 0; i < buf.pendingOff; i++ {
			buf.pending[i] -= minValue
		}
		mutable := MutableFor(buf.pendingOff, bitsRequired, buf.acceptableOverheadRatio)
		for i := 0; i < buf.pendingOff; i++ {
			i += mutable.setBulk(i, buf.pending[i:buf.pendingOff])
		}
		buf.values[buf.valuesOff] = mutable
	}
}

func (buf *AppendingDeltaPackedLongBuffer) grow(newBlockCount int) {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) baseRamBytesUsed() int64 {
	return buf.abstractAppendingLongBuffer.baseRamBytesUsed() +
		util.NUM_BYTES_OBJECT_REF
}

func (buf *AppendingDeltaPackedLongBuffer) RamBytesUsed() int64 {
	return buf.abstractAppendingLongBuffer.RamBytesUsed() + util.SizeOf(buf.minValues)
}
<|endoftext|>


<commit_before>/*
 * Minimal multicast DNS server.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package netlink

// #include <linux/rtnetlink.h>
import "C"

import "fmt"
import "syscall"
import "unsafe"

type NetlinkListener struct {
	fd int;
	sa *syscall.SockaddrNetlink;
}

func ListenNetlink() (*NetlinkListener, error) {
	groups := C.RTMGRP_LINK        |
	          C.RTMGRP_IPV4_IFADDR |
	          C.RTMGRP_IPV6_IFADDR;

	s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, syscall.NETLINK_ROUTE);
	if err != nil {
		return nil, fmt.Errorf("socket: %s", err);
	}

	saddr := new(syscall.SockaddrNetlink);
	saddr.Family = syscall.AF_NETLINK;
	saddr.Pid    = uint32(0);
	saddr.Groups = uint32(groups);

	err = syscall.Bind(s, saddr);
	if err != nil {
		return nil, fmt.Errorf("bind: %s", err);
	}

	l := new(NetlinkListener);
	l.fd = s;
	l.sa = saddr;

	return l, nil;
}

func (l *NetlinkListener) ReadMsgs() ([]syscall.NetlinkMessage, error) {
	defer func() {
		recover();
	}();

	pkt := make([]byte, 2048);

	n, err := syscall.Read(l.fd, pkt);
	if err != nil {
		return nil, fmt.Errorf("read: %s", err);
	}

	msgs, err := syscall.ParseNetlinkMessage(pkt[:n]);
	if err != nil {
		return nil, fmt.Errorf("parse: %s", err);
	}

	return msgs, nil;
}

func (l *NetlinkListener) SendRouteRequest(proto, family int) error {
	wb := newNetlinkRouteRequest(proto, 1, family);

	err := syscall.Sendto(l.fd, wb, 0, l.sa);
	if err != nil {
		return err;
	}

	return nil;
}

func toWireFormat(rr *syscall.NetlinkRouteRequest) []byte {
	b := make([]byte, rr.Header.Len);

	*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len;
	*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type;
	*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags;
	*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq;
	*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid;

	b[16] = byte(rr.Data.Family);
	return b;
}

func newNetlinkRouteRequest(proto, seq, family int) []byte {
	rr := &syscall.NetlinkRouteRequest{};
	rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg);
	rr.Header.Type = uint16(proto);
	rr.Header.Flags = syscall.NLM_F_DUMP | syscall.NLM_F_REQUEST;
	rr.Header.Seq = uint32(seq);
	rr.Data.Family = uint8(family);

	return toWireFormat(rr);
}

func IsNewAddr(msg *syscall.NetlinkMessage) bool {
	if msg.Header.Type == C.RTM_NEWADDR {
		return true;
	}

	return false;
}

func IsDelAddr(msg *syscall.NetlinkMessage) bool {
	if msg.Header.Type == C.RTM_DELADDR {
		return true;
	}

	return false;
}

func IsRelevant(msg *syscall.IfAddrmsg) bool {
	if msg.Scope == C.RT_SCOPE_UNIVERSE ||
	   msg.Scope == C.RT_SCOPE_SITE {
		return true;
	}

	return false;
}
<commit_msg>netlink: use syscall consts instead of C defines<commit_after>/*
 * Minimal multicast DNS server.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package netlink

import "fmt"
import "syscall"
import "unsafe"

type NetlinkListener struct {
	fd int;
	sa *syscall.SockaddrNetlink;
}

func ListenNetlink() (*NetlinkListener, error) {
	groups := syscall.RTNLGRP_LINK        |
	          syscall.RTNLGRP_IPV4_IFADDR |
	          syscall.RTNLGRP_IPV6_IFADDR;

	s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, syscall.NETLINK_ROUTE);
	if err != nil {
		return nil, fmt.Errorf("socket: %s", err);
	}

	saddr := new(syscall.SockaddrNetlink);
	saddr.Family = syscall.AF_NETLINK;
	saddr.Pid    = uint32(0);
	saddr.Groups = uint32(groups);

	err = syscall.Bind(s, saddr);
	if err != nil {
		return nil, fmt.Errorf("bind: %s", err);
	}

	l := new(NetlinkListener);
	l.fd = s;
	l.sa = saddr;

	return l, nil;
}

func (l *NetlinkListener) ReadMsgs() ([]syscall.NetlinkMessage, error) {
	defer func() {
		recover();
	}();

	pkt := make([]byte, 2048);

	n, err := syscall.Read(l.fd, pkt);
	if err != nil {
		return nil, fmt.Errorf("read: %s", err);
	}

	msgs, err := syscall.ParseNetlinkMessage(pkt[:n]);
	if err != nil {
		return nil, fmt.Errorf("parse: %s", err);
	}

	return msgs, nil;
}

func (l *NetlinkListener) SendRouteRequest(proto, family int) error {
	wb := newNetlinkRouteRequest(proto, 1, family);

	err := syscall.Sendto(l.fd, wb, 0, l.sa);
	if err != nil {
		return err;
	}

	return nil;
}

func toWireFormat(rr *syscall.NetlinkRouteRequest) []byte {
	b := make([]byte, rr.Header.Len);

	*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len;
	*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type;
	*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags;
	*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq;
	*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid;

	b[16] = byte(rr.Data.Family);
	return b;
}

func newNetlinkRouteRequest(proto, seq, family int) []byte {
	rr := &syscall.NetlinkRouteRequest{};
	rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg);
	rr.Header.Type = uint16(proto);
	rr.Header.Flags = syscall.NLM_F_DUMP | syscall.NLM_F_REQUEST;
	rr.Header.Seq = uint32(seq);
	rr.Data.Family = uint8(family);

	return toWireFormat(rr);
}

func IsNewAddr(msg *syscall.NetlinkMessage) bool {
	if msg.Header.Type == syscall.RTM_NEWADDR {
		return true;
	}

	return false;
}

func IsDelAddr(msg *syscall.NetlinkMessage) bool {
	if msg.Header.Type == syscall.RTM_DELADDR {
		return true;
	}

	return false;
}

func IsRelevant(msg *syscall.IfAddrmsg) bool {
	if msg.Scope == syscall.RT_SCOPE_UNIVERSE ||
	   msg.Scope == syscall.RT_SCOPE_SITE {
		return true;
	}

	return false;
}
<|endoftext|>


<commit_before>// Copyright 2016 The nvim-go 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 command

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"nvim-go/config"
	"nvim-go/nvimutil"

	"github.com/neovim/go-client/nvim"
	"github.com/pkg/errors"
)

// CmdBuildEval struct type for Eval of GoBuild command.
type CmdBuildEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func (c *Command) cmdBuild(bang bool, eval *CmdBuildEval) {
	go func() {
		c.errs.Delete("Build")

		err := c.Build(bang, eval)
		switch e := err.(type) {
		case error:
			nvimutil.ErrorWrap(c.Nvim, e)
		case []*nvim.QuickfixError:
			c.errs.Store("Build", e)
			errlist := make(map[string][]*nvim.QuickfixError)
			c.errs.Range(func(ki, vi interface{}) bool {
				k, v := ki.(string), vi.([]*nvim.QuickfixError)
				errlist[k] = append(errlist[k], v...)
				return true
			})
			nvimutil.ErrorList(c.Nvim, errlist, true)
		}
	}()
}

// Build builds the current buffers package use compile tool that determined
// from the package directory structure.
func (c *Command) Build(bang bool, eval *CmdBuildEval) interface{} {
	defer nvimutil.Profile(time.Now(), "GoBuild")

	if !bang {
		bang = config.BuildForce
	}

	cmd, err := c.compileCmd(bang, filepath.Dir(eval.File))
	if err != nil {
		return errors.WithStack(err)
	}
	var stderr bytes.Buffer
	cmd.Stderr = &stderr

	if buildErr := cmd.Run(); buildErr != nil {
		if buildErr.(*exec.ExitError) != nil {
			errlist, err := nvimutil.ParseError(stderr.Bytes(), eval.Cwd, &c.ctx.Build, nil)
			if err != nil {
				return errors.WithStack(err)
			}
			return errlist
		}
		return errors.WithStack(buildErr)
	}

	return nvimutil.EchoSuccess(c.Nvim, "GoBuild", fmt.Sprintf("compiler: %s", c.ctx.Build.Tool))
}

// compileCmd returns the *exec.Cmd corresponding to the compile tool.
func (c *Command) compileCmd(bang bool, dir string) (*exec.Cmd, error) {
	bin, err := exec.LookPath(c.ctx.Build.Tool)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	args := []string{}
	if len(config.BuildFlags) > 0 {
		args = append(args, config.BuildFlags...)
	}

	cmd := exec.Command(bin, "build")
	cmd.Dir = dir

	switch c.ctx.Build.Tool {
	case "go":
		// Outputs the binary to DevNull if without bang
		if !bang {
			args = append(args, "-o", os.DevNull)
		}
	case "gb":
		cmd.Dir = c.ctx.Build.ProjectRoot
	}

	cmd.Args = append(cmd.Args, args...)

	return cmd, nil
}
<commit_msg>command/build: support Google App Engine<commit_after>// Copyright 2016 The nvim-go 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 command

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"nvim-go/config"
	"nvim-go/internal/pathutil"
	"nvim-go/nvimutil"

	"github.com/neovim/go-client/nvim"
	"github.com/pkg/errors"
)

// CmdBuildEval struct type for Eval of GoBuild command.
type CmdBuildEval struct {
	Cwd  string `msgpack:",array"`
	File string
}

func (c *Command) cmdBuild(bang bool, eval *CmdBuildEval) {
	go func() {
		c.errs.Delete("Build")

		err := c.Build(bang, eval)
		switch e := err.(type) {
		case error:
			nvimutil.ErrorWrap(c.Nvim, e)
		case []*nvim.QuickfixError:
			c.errs.Store("Build", e)
			errlist := make(map[string][]*nvim.QuickfixError)
			c.errs.Range(func(ki, vi interface{}) bool {
				k, v := ki.(string), vi.([]*nvim.QuickfixError)
				errlist[k] = append(errlist[k], v...)
				return true
			})
			nvimutil.ErrorList(c.Nvim, errlist, true)
		}
	}()
}

// Build builds the current buffers package use compile tool that determined
// from the package directory structure.
func (c *Command) Build(bang bool, eval *CmdBuildEval) interface{} {
	defer nvimutil.Profile(time.Now(), "GoBuild")

	if !bang {
		bang = config.BuildForce
	}

	cmd, err := c.compileCmd(bang, filepath.Dir(eval.File))
	if err != nil {
		return errors.WithStack(err)
	}
	var stderr bytes.Buffer
	cmd.Stderr = &stderr

	if buildErr := cmd.Run(); buildErr != nil {
		if buildErr.(*exec.ExitError) != nil {
			errlist, err := nvimutil.ParseError(stderr.Bytes(), eval.Cwd, &c.ctx.Build, nil)
			if err != nil {
				return errors.WithStack(err)
			}
			return errlist
		}
		return errors.WithStack(buildErr)
	}

	return nvimutil.EchoSuccess(c.Nvim, "GoBuild", fmt.Sprintf("compiler: %s", c.ctx.Build.Tool))
}

// compileCmd returns the *exec.Cmd corresponding to the compile tool.
func (c *Command) compileCmd(bang bool, dir string) (*exec.Cmd, error) {
	bin, err := exec.LookPath(c.ctx.Build.Tool)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	args := []string{}
	if len(config.BuildFlags) > 0 {
		args = append(args, config.BuildFlags...)
	}

	cmd := exec.Command(bin, "build")
	cmd.Dir = dir

	switch c.ctx.Build.Tool {
	case "go":
		// Outputs the binary to DevNull if without bang
		if !bang {
			args = append(args, "-o", os.DevNull)
		}
		if config.BuildAppengine {
			cmd.Args[0] = cmd.Args[0] + "app"
		}
	case "gb":
		cmd.Dir = c.ctx.Build.ProjectRoot
		if config.BuildAppengine {
			cmd.Args = append([]string{cmd.Args[0], "gae"}, cmd.Args[1:]...)
			pkgs, err := pathutil.GbPackages(cmd.Dir)
			if err != nil {
				return nil, err
			}
			for _, pkg := range pkgs {
				cmd.Args = append(cmd.Args, pkg+string(filepath.Separator)+"...")
			}
		}
	}

	cmd.Args = append(cmd.Args, args...)

	return cmd, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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.

// The shenzhen-go binary serves a visual Go environment.
package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"time"

	"github.com/improbable-eng/grpc-web/go/grpcweb"
	"github.com/zserge/webview"
	"google.golang.org/grpc"

	pb "github.com/google/shenzhen-go/dev/proto/go"
	"github.com/google/shenzhen-go/dev/server"
	"github.com/google/shenzhen-go/dev/server/view"
)

const pingMsg = "Pong!"

var (
	uiAddr            = flag.String("ui_addr", "localhost:0", "Address to bind UI server to")
	useDefaultBrowser = flag.Bool("use_browser", true, "Load in the system's default web browser instead of the inbuilt webview")
)

func systemOpen(url string) error {
	switch runtime.GOOS {
	case "darwin":
		return exec.Command("open", url).Run()
	case "linux":
		// Seems to work on Linux Mint. YMMV.
		return exec.Command("xdg-open", url).Run()
	case "windows":
		return exec.Command("cmd.exe", "/C", "start", url).Run()
	default:
		fmt.Printf("Ready to open %s\n", url)
		return nil
	}
}

func webviewOpen(url string) error {
	return webview.Open("SHENZHEN GO", url, 1152, 720, true)
}

func isUp(url string) bool {
	resp, err := http.Get(url)
	if err != nil {
		return false
	}
	defer resp.Body.Close()
	msg, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false
	}
	return string(msg) == pingMsg
}

func waitForUp(addr net.Addr) error {
	url := fmt.Sprintf(`http://%s/ping`, addr)
	try := time.NewTicker(100 * time.Millisecond)
	defer try.Stop()
	timeout := time.NewTimer(5 * time.Second)
	defer timeout.Stop()
	for {
		select {
		case <-try.C:
			if isUp(url) {
				return nil
			}
		case <-timeout.C:
			return errors.New("timed out waiting 5s for server")
		}
	}
}

func open(addr net.Addr, path string, useBrowser bool) {
	url := fmt.Sprintf(`http://%s/%s`, addr, path)
	opener := systemOpen
	if !useBrowser {
		opener = webviewOpen
	}
	if err := opener(url); err != nil {
		fmt.Fprintf(os.Stderr, "Couldn't automatically open: %v\n", err)
		fmt.Printf("Ready to open %s\n", url)
	}
}

func main() {
	flag.Parse()

	args := flag.Args()
	if len(args) > 0 {
		switch args[0] {
		case "generate":
			log.Fatalf("TODO: generate is not yet implemented")
		case "build":
			log.Fatalf("TODO: build is not yet implemented")
		case "install":
			log.Fatalf("TODO: install is not yet implemented")
		case "run":
			log.Fatalf("TODO: run is not yet implemented")
		case "edit":
			args = args[1:]
		default:
			// Edit, but every arg is a file.
		}
	} else {
		// Opens the browser at the root.
		args = []string{""}
	}

	http.HandleFunc("/ping", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte(pingMsg)) })
	http.Handle("/favicon.ico", view.Favicon)
	http.Handle("/.static/", http.StripPrefix("/.static/", view.Static))

	gs := grpc.NewServer()
	pb.RegisterShenzhenGoServer(gs, server.S)
	ws := grpcweb.WrapServer(gs)
	http.Handle("/.api/", http.StripPrefix("/.api/", ws))

	// Finally, all unknown paths are assumed to be files.
	http.Handle("/", server.S)

	ln, err := net.Listen("tcp", *uiAddr)
	if err != nil {
		log.Fatalf("net.Listen failed: %v", err)
	}
	defer ln.Close()

	wait := make(chan struct{})
	go func() {
		if err := http.Serve(ln, nil); err != nil {
			log.Fatalf("http.Serve failed: %v", err)
		}
		close(wait)
	}()

	// Wait until properly serving.
	if err := waitForUp(ln.Addr()); err != nil {
		log.Fatalf("Couldn't reach server: %v", err)
	}

	for _, a := range args {
		// Launch "open" which should launch a browser,
		// or ask the user to do so.
		// This must be called from the main thread to avoid
		// https://github.com/zserge/webview/issues/29.
		open(ln.Addr(), a, *useDefaultBrowser)
	}

	// Job done.
	<-wait
}
<commit_msg>Add "serve" command and more usage help<commit_after>// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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.

// The shenzhen-go binary serves a visual Go environment.
package main

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"time"

	"github.com/improbable-eng/grpc-web/go/grpcweb"
	"github.com/zserge/webview"
	"google.golang.org/grpc"

	pb "github.com/google/shenzhen-go/dev/proto/go"
	"github.com/google/shenzhen-go/dev/server"
	"github.com/google/shenzhen-go/dev/server/view"
)

const pingMsg = "Pong!"

var (
	uiAddr            = flag.String("ui_addr", "localhost:0", "`address` to bind UI server to")
	useDefaultBrowser = flag.Bool("use_browser", true, "Load in the system's default web browser instead of the inbuilt webview")
)

func systemOpen(url string) error {
	switch runtime.GOOS {
	case "darwin":
		return exec.Command("open", url).Run()
	case "linux":
		// Seems to work on Linux Mint. YMMV.
		return exec.Command("xdg-open", url).Run()
	case "windows":
		return exec.Command("cmd.exe", "/C", "start", url).Run()
	default:
		fmt.Printf("Ready to open %s\n", url)
		return nil
	}
}

func webviewOpen(url string) error {
	return webview.Open("Shenzhen Go", url, 1152, 720, true)
}

func isUp(url string) bool {
	resp, err := http.Get(url)
	if err != nil {
		return false
	}
	defer resp.Body.Close()
	msg, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false
	}
	return string(msg) == pingMsg
}

func waitForUp(addr net.Addr) error {
	url := fmt.Sprintf(`http://%s/ping`, addr)
	try := time.NewTicker(100 * time.Millisecond)
	defer try.Stop()
	timeout := time.NewTimer(5 * time.Second)
	defer timeout.Stop()
	for {
		select {
		case <-try.C:
			if isUp(url) {
				return nil
			}
		case <-timeout.C:
			return errors.New("timed out waiting 5s for server")
		}
	}
}

func open(addr net.Addr, path string, useBrowser bool) {
	url := fmt.Sprintf(`http://%s/%s`, addr, path)
	opener := systemOpen
	if !useBrowser {
		opener = webviewOpen
	}
	if err := opener(url); err != nil {
		fmt.Fprintf(os.Stderr, "Couldn't automatically open: %v\n", err)
		fmt.Printf("Ready to open %s\n", url)
	}
}

func serve(addr chan<- net.Addr) error {
	ln, err := net.Listen("tcp", *uiAddr)
	if err != nil {
		return fmt.Errorf("net.Listen: %v", err)
	}
	defer ln.Close()

	if addr != nil {
		addr <- ln.Addr()
	}

	http.HandleFunc("/ping", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte(pingMsg)) })
	http.Handle("/favicon.ico", view.Favicon)
	http.Handle("/.static/", http.StripPrefix("/.static/", view.Static))

	gs := grpc.NewServer()
	pb.RegisterShenzhenGoServer(gs, server.S)
	ws := grpcweb.WrapServer(gs)
	http.Handle("/.api/", http.StripPrefix("/.api/", ws))

	// Finally, all unknown paths are assumed to be files.
	http.Handle("/", server.S)
	if err := http.Serve(ln, nil); err != nil {
		return fmt.Errorf("http.Serve: %v", err)
	}
	return nil
}

func usage() {
	fmt.Fprintf(flag.CommandLine.Output(), `Shenzhen Go is a tool for managing Shenzhen Go source code.

Usage:

  %s [command] [files]

The (optional) commands are:

  build     generate and build Go packages
  edit      launch a Shenzhen Go server and open the editor interface
  generate  generate Go packages
  install   generate and install Go packages
  run       generate Go package and run binaries
  serve     launch a Shenzhen Go server

"edit" is the default command.

Flags:`, os.Args[0])
	// TODO: Add per-command help. `shenzhen-go help [command]`

	flag.PrintDefaults()
}

func main() {
	flag.Usage = usage
	flag.Parse()

	openUI := true
	args := flag.Args()
	if len(args) > 0 {
		switch args[0] {
		case "build":
			log.Fatalf("TODO: build is not yet implemented")
		case "edit":
			args = args[1:]
		case "generate":
			log.Fatalf("TODO: generate is not yet implemented")
		case "help":
			usage()
			return
		case "install":
			log.Fatalf("TODO: install is not yet implemented")
		case "run":
			log.Fatalf("TODO: run is not yet implemented")
		case "serve":
			if len(args) > 1 {
				log.Print(`Note: extra arguments to "serve" command are ignored`)
			}
			openUI = false
		default:
			// Edit, but every arg is a file.
		}
	} else {
		// Opens the browser at the root.
		args = []string{""}
	}

	adch := make(chan net.Addr)
	wait := make(chan struct{})
	go func() {
		serve(adch)
		close(wait)
	}()

	// Wait until properly serving.
	addr := <-adch
	if err := waitForUp(addr); err != nil {
		log.Fatalf("Couldn't reach server: %v", err)
	}
	log.Printf("Serving HTTP on %v", addr)

	if openUI {
		for _, a := range args {
			// Launch "open" which should launch a browser,
			// or ask the user to do so.
			// This must be called from the main thread to avoid
			// https://github.com/zserge/webview/issues/29.
			open(addr, a, *useDefaultBrowser)
		}
	}

	// Job done.
	<-wait
}
<|endoftext|>


<commit_before><commit_msg>Revert ingress validation fix<commit_after><|endoftext|>


<commit_before><commit_msg>Make newKubeClient cluster bind to be used outside of helm<commit_after><|endoftext|>


<commit_before><commit_msg>Improve comments and error checking<commit_after><|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime"
	//	"path"
	//	"path/filepath"
	//	"time"

	//	"github.com/intelsdilabs/pulse/control"
)

var version = flag.Bool("version", false, "print Pulse version")
var maxProcs = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Default is use all cores.")

type Pulse struct{} //Will hold what modules start and stop

func main() {
	//TODO: Parse startup arguments for pulse
	flag.Parse()

	if *version {
		//TODO: Pass in version during build
		fmt.Println("Pulse version 1.0.0-alpha\n")
		os.Exit(0)
	}
	setMaxProcs()

	os.Exit(0)
}

func setMaxProcs() {
	var _maxProcs int
	numProcs := runtime.NumCPU()
	if *maxProcs == 0 {
		_maxProcs = numProcs
	} else if *maxProcs > numProcs {
		log.Printf("WARNING: Not allowed to set GOMAXPROCS above number of processors in system. Setting GOMAXPROCS to %v", numProcs)
		_maxProcs = numProcs
	} else {
		_maxProcs = *maxProcs
	}
	log.Printf("Setting GOMAXPROCS to %v\n", _maxProcs)
	runtime.GOMAXPROCS(_maxProcs)

	//Verify setting worked
	actualNumProcs := runtime.GOMAXPROCS(0)
	if actualNumProcs != _maxProcs {
		log.Println("WARNING: Specified max procs of %v but using %v", _maxProcs, actualNumProcs)
	}
}

//var (
// PulsePath is the local file path to a pulse build
//	PulsePath = os.Getenv("PULSE_PATH")
// CollectorPath is the path to collector plugins within a pulse build
//	CollectorPath = path.Join(PulsePath, "plugin", "collector")
//)

//func checkError(e error) {
//	if e != nil {
//		panic(e)
//	}
//}

//func isExecutable(p os.FileMode) bool {
//	return (p & 0111) != 0
//}

//func main() {
//	if PulsePath == "" {
//		log.Fatalln("PULSE_PATH not set")
//		os.Exit(1)
//	}
//
//	log.Println("Startup")
// TODO ERROR missing PULSE_PATH
// fmt.Println(PulsePath)

//	pluginControl := control.New()
//	pluginControl.Start()
//	defer pluginControl.Stop()

// fmt.Println(pluginControl)
// fmt.Println(CollectorPath)

//	m, err := filepath.Glob(CollectorPath + "/pulse-collector-*")
//	checkError(err)
//	for _, d := range m {
//		f, err := os.Stat(d)
//		checkError(err)
//		// Ignore directories
//		if f.Mode().IsDir() {
//			continue
//		}
//		// Ignore file without executable permission
//		if !isExecutable(f.Mode().Perm()) {
//			log.Printf("The plugin [%s] is not executable\n", d)
//			continue
//		}
//		pluginControl.Load(d)
//	}
//
//	for {
//		time.Sleep(time.Second * 1)
//	}
//	// err := pluginControl.Load(collectorPath)
//
//}
<commit_msg>Add interrupt handling<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	//	"path"
	//	"path/filepath"
	//	"time"

	//	"github.com/intelsdilabs/pulse/control"
)

var version = flag.Bool("version", false, "print Pulse version")
var maxProcs = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Default is use all cores.")

type PulseController struct{} //Will hold what modules start and stop

func main() {
	//TODO: Parse startup arguments for pulse
	flag.Parse()
	if *version {
		//TODO: Pass in version during build
		fmt.Println("Pulse version 1.0.0-alpha\n")
		os.Exit(0)
	}

	pc := &PulseController{}
	setMaxProcs()

	//TODO: Start pulse modules

	startInterruptHandling(pc)
	select {} //run forever and ever
}

func setMaxProcs() {
	var _maxProcs int
	numProcs := runtime.NumCPU()
	if *maxProcs == 0 {
		_maxProcs = numProcs
	} else if *maxProcs > numProcs {
		log.Printf("WARNING: Not allowed to set GOMAXPROCS above number of processors in system. Setting GOMAXPROCS to %v", numProcs)
		_maxProcs = numProcs
	} else {
		_maxProcs = *maxProcs
	}
	log.Printf("Setting GOMAXPROCS to %v\n", _maxProcs)
	runtime.GOMAXPROCS(_maxProcs)

	//Verify setting worked
	actualNumProcs := runtime.GOMAXPROCS(0)
	if actualNumProcs != _maxProcs {
		log.Println("WARNING: Specified max procs of %v but using %v", _maxProcs, actualNumProcs)
	}
}

func startInterruptHandling(pc *PulseController) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)

	//Let's block until someone tells us to quit
	go func() {
		sig := <-c
		//TODO: Stop pulse modules on exit signals
		log.Printf("Exiting given signal: %v", sig)
		os.Exit(0)
	}()
}

//var (
// PulsePath is the local file path to a pulse build
//	PulsePath = os.Getenv("PULSE_PATH")
// CollectorPath is the path to collector plugins within a pulse build
//	CollectorPath = path.Join(PulsePath, "plugin", "collector")
//)

//func checkError(e error) {
//	if e != nil {
//		panic(e)
//	}
//}

//func isExecutable(p os.FileMode) bool {
//	return (p & 0111) != 0
//}

//func main() {
//	if PulsePath == "" {
//		log.Fatalln("PULSE_PATH not set")
//		os.Exit(1)
//	}
//
//	log.Println("Startup")
// TODO ERROR missing PULSE_PATH
// fmt.Println(PulsePath)

//	pluginControl := control.New()
//	pluginControl.Start()
//	defer pluginControl.Stop()

// fmt.Println(pluginControl)
// fmt.Println(CollectorPath)

//	m, err := filepath.Glob(CollectorPath + "/pulse-collector-*")
//	checkError(err)
//	for _, d := range m {
//		f, err := os.Stat(d)
//		checkError(err)
//		// Ignore directories
//		if f.Mode().IsDir() {
//			continue
//		}
//		// Ignore file without executable permission
//		if !isExecutable(f.Mode().Perm()) {
//			log.Printf("The plugin [%s] is not executable\n", d)
//			continue
//		}
//		pluginControl.Load(d)
//	}
//
//	for {
//		time.Sleep(time.Second * 1)
//	}
//	// err := pluginControl.Load(collectorPath)
//
//}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/promise_impl.go                                *
 *                                                        *
 * promise implementation for Go.                         *
 *                                                        *
 * LastModified: Aug 11, 2015                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import (
	"sync/atomic"
	"time"
)

// Callable is a function type.
// It has no arguments and returns a result with an error.
type Callable func() (interface{}, error)

type subscriber struct {
	onFulfilled OnFulfilled
	onRejected  OnRejected
	next        Promise
}

type promiseImpl struct {
	value       interface{}
	reason      error
	state       uint32
	subscribers []subscriber
}

func resolve(onFulfilled OnFulfilled, next Promise, x interface{}) {
	if onFulfilled != nil {
		go func() {
			defer func() {
				if e := recover(); e != nil {
					next.Reject(NewPanicError(e))
				}
			}()
			if result, err := onFulfilled(x); err != nil {
				next.Reject(err)
			} else {
				next.Resolve(result)
			}
		}()
	} else {
		next.Resolve(x)
	}
}

func reject(onRejected OnRejected, next Promise, e error) {
	if onRejected != nil {
		go func() {
			defer func() {
				if e := recover(); e != nil {
					next.Reject(NewPanicError(e))
				}
			}()
			if result, err := onRejected(e); err != nil {
				next.Reject(err)
			} else {
				next.Resolve(result)
			}
		}()
	} else {
		next.Reject(e)
	}
}

func (p *promiseImpl) init(computation Callable) {
	result, err := computation()
	if err != nil {
		p.Reject(err)
	} else {
		p.Resolve(result)
	}
}

func (p *promiseImpl) then(onFulfilled OnFulfilled, onRejected OnRejected) Promise {
	next := new(promiseImpl)
	switch State(p.state) {
	case FULFILLED:
		resolve(onFulfilled, next, p.value)
	case REJECTED:
		reject(onRejected, next, p.reason)
	default:
		p.subscribers = append(p.subscribers,
			subscriber{onFulfilled, onRejected, next})
	}
	return next
}

func (p *promiseImpl) Then(onFulfilled OnFulfilled, onRejected ...OnRejected) Promise {
	if len(onRejected) == 0 {
		return p.then(onFulfilled, nil)
	}
	return p.then(onFulfilled, onRejected[0])
}

func (p *promiseImpl) catch(onRejected OnRejected, test TestFunc) Promise {
	if test != nil {
		return p.then(nil, func(e error) (interface{}, error) {
			if test(e) {
				return p.then(nil, onRejected), nil
			}
			return nil, e
		})
	}
	return p.then(nil, onRejected)
}

func (p *promiseImpl) Catch(onRejected OnRejected, test ...TestFunc) Promise {
	if len(test) == 0 {
		return p.catch(onRejected, nil)
	}
	return p.catch(onRejected, test[0])
}

func (p *promiseImpl) Complete(onCompleted OnCompleted) Promise {
	return p.then(OnFulfilled(onCompleted), func(e error) (interface{}, error) {
		return onCompleted(e)
	})
}

func (p *promiseImpl) WhenComplete(action func()) Promise {
	return p.then(func(v interface{}) (interface{}, error) {
		action()
		return v, nil
	}, func(e error) (interface{}, error) {
		action()
		return nil, e
	})
}

func (p *promiseImpl) Done(onFulfilled OnFulfilled, onRejected ...OnRejected) {
	p.
		Then(onFulfilled, onRejected...).
		Then(nil, func(e error) (interface{}, error) {
			go panic(e)
			return nil, nil
		})
}

func (p *promiseImpl) Fail(onRejected OnRejected) {
	p.Done(nil, onRejected)
}

func (p *promiseImpl) Always(onCompleted OnCompleted) {
	p.Done(OnFulfilled(onCompleted), func(e error) (interface{}, error) {
		return onCompleted(e)
	})
}

func (p *promiseImpl) State() State {
	return State(p.state)
}

func (p *promiseImpl) resolve(thenable Thenable) {
	var done uint32
	resolveFunc := func(y interface{}) (interface{}, error) {
		if atomic.CompareAndSwapUint32(&done, 0, 1) {
			p.Resolve(y)
		}
		return nil, nil
	}
	rejectFunc := func(e error) (interface{}, error) {
		if atomic.CompareAndSwapUint32(&done, 0, 1) {
			p.Reject(e)
		}
		return nil, nil
	}
	defer func() {
		e := recover()
		if e != nil && atomic.CompareAndSwapUint32(&done, 0, 1) {
			p.Reject(NewPanicError(e))
		}
	}()
	thenable.Then(resolveFunc, rejectFunc)
}

func (p *promiseImpl) Resolve(value interface{}) {
	if promise, ok := value.(*promiseImpl); ok && promise == p {
		p.Reject(TypeError{"Self resolution"})
		return
	}
	if promise, ok := value.(Promise); ok {
		promise.Fill(p)
		return
	}
	if thenable, ok := value.(Thenable); ok {
		p.resolve(thenable)
		return
	}
	if atomic.CompareAndSwapUint32(&p.state, uint32(PENDING), uint32(FULFILLED)) {
		p.value = value
		subscribers := p.subscribers
		p.subscribers = nil
		for _, subscriber := range subscribers {
			resolve(subscriber.onFulfilled, subscriber.next, value)
		}
	}
}

func (p *promiseImpl) Reject(reason error) {
	if atomic.CompareAndSwapUint32(&p.state, uint32(PENDING), uint32(REJECTED)) {
		p.reason = reason
		subscribers := p.subscribers
		p.subscribers = nil
		for _, subscriber := range subscribers {
			reject(subscriber.onRejected, subscriber.next, reason)
		}
	}
}

func (p *promiseImpl) Fill(promise Promise) {
	resolveFunc := func(v interface{}) (interface{}, error) {
		promise.Resolve(v)
		return nil, nil
	}
	rejectFunc := func(e error) (interface{}, error) {
		promise.Reject(e)
		return nil, nil
	}
	p.Then(resolveFunc, rejectFunc)
}

func (p *promiseImpl) Timeout(duration time.Duration, reason ...error) Promise {
	promise := new(promiseImpl)
	timer := time.AfterFunc(duration, func() {
		if len(reason) > 0 {
			promise.Reject(reason[0])
		} else {
			promise.Reject(TimeoutError{})
		}
	})
	p.WhenComplete(func() { timer.Stop() }).Fill(promise)
	return promise
}

func (p *promiseImpl) Delay(duration time.Duration) Promise {
	promise := new(promiseImpl)
	p.then(func(v interface{}) (interface{}, error) {
		go func() {
			time.Sleep(duration)
			promise.Resolve(v)
		}()
		return nil, nil
	}, func(e error) (interface{}, error) {
		promise.Reject(e)
		return nil, nil
	})
	return promise
}

func (p *promiseImpl) Tap(onfulfilledSideEffect OnfulfilledSideEffect) Promise {
	return p.then(func(v interface{}) (interface{}, error) {
		onfulfilledSideEffect(v)
		return v, nil
	}, nil)
}

func (p *promiseImpl) Get() (interface{}, error) {
	c := make(chan interface{})
	p.then(func(v interface{}) (interface{}, error) {
		c <- v
		return nil, nil
	}, func(e error) (interface{}, error) {
		c <- e
		return nil, nil
	})
	v := <-c
	if e, ok := v.(error); ok {
		return nil, e
	}
	return v, nil
}

// New creates a Promise object
func New(value ...interface{}) Promise {
	promise := new(promiseImpl)
	if len(value) > 0 {
		if computation, ok := value[0].(Callable); ok {
			go promise.init(computation)
		} else if e, ok := value[0].(error); ok {
			promise.Reject(e)
		} else {
			promise.Resolve(value[0])
		}
	}
	return promise
}

// Sync creates a Promise object containing the result of immediately calling
// computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Sync(computation Callable) Promise {
	promise := new(promiseImpl)
	promise.init(computation)
	return promise
}

// Delayed creates a Promise object with the given value after a delay.
//
// If the value is a Callable function, it will be executed after the given duration has passed, and the Promise object is completed with the result.
func Delayed(duration time.Duration, value interface{}) Promise {
	promise := new(promiseImpl)
	go func() {
		time.Sleep(duration)
		if computation, ok := value.(Callable); ok {
			promise.init(computation)
		} else if e, ok := value.(error); ok {
			promise.Reject(e)
		} else {
			promise.Resolve(value)
		}
	}()
	return promise
}
<commit_msg>Fixed Block nesting too deep<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/promise_impl.go                                *
 *                                                        *
 * promise implementation for Go.                         *
 *                                                        *
 * LastModified: Aug 12, 2015                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import (
	"sync/atomic"
	"time"
)

// Callable is a function type.
// It has no arguments and returns a result with an error.
type Callable func() (interface{}, error)

type subscriber struct {
	onFulfilled OnFulfilled
	onRejected  OnRejected
	next        Promise
}

type promiseImpl struct {
	value       interface{}
	reason      error
	state       uint32
	subscribers []subscriber
}

func call(onFulfilled OnFulfilled, next Promise, x interface{}) {
	defer func() {
		if e := recover(); e != nil {
			next.Reject(NewPanicError(e))
		}
	}()
	if result, err := onFulfilled(x); err != nil {
		next.Reject(err)
	} else {
		next.Resolve(result)
	}
}

func resolve(onFulfilled OnFulfilled, next Promise, x interface{}) {
	if onFulfilled != nil {
		go call(onFulfilled, next, x)
	} else {
		next.Resolve(x)
	}
}

func reject(onRejected OnRejected, next Promise, e error) {
	if onRejected != nil {
		go call(func(x interface{}) (interface{}, error) {
			return onRejected(x.(error))
		}, next, e)
	} else {
		next.Reject(e)
	}
}

func (p *promiseImpl) init(computation Callable) {
	result, err := computation()
	if err != nil {
		p.Reject(err)
	} else {
		p.Resolve(result)
	}
}

func (p *promiseImpl) then(onFulfilled OnFulfilled, onRejected OnRejected) Promise {
	next := new(promiseImpl)
	switch State(p.state) {
	case FULFILLED:
		resolve(onFulfilled, next, p.value)
	case REJECTED:
		reject(onRejected, next, p.reason)
	default:
		p.subscribers = append(p.subscribers,
			subscriber{onFulfilled, onRejected, next})
	}
	return next
}

func (p *promiseImpl) Then(onFulfilled OnFulfilled, onRejected ...OnRejected) Promise {
	if len(onRejected) == 0 {
		return p.then(onFulfilled, nil)
	}
	return p.then(onFulfilled, onRejected[0])
}

func (p *promiseImpl) catch(onRejected OnRejected, test TestFunc) Promise {
	if test == nil {
		return p.then(nil, onRejected)
	}
	return p.then(nil, func(e error) (interface{}, error) {
		if test(e) {
			return p.then(nil, onRejected), nil
		}
		return nil, e
	})
}

func (p *promiseImpl) Catch(onRejected OnRejected, test ...TestFunc) Promise {
	if len(test) == 0 {
		return p.catch(onRejected, nil)
	}
	return p.catch(onRejected, test[0])
}

func (p *promiseImpl) Complete(onCompleted OnCompleted) Promise {
	return p.then(OnFulfilled(onCompleted), func(e error) (interface{}, error) {
		return onCompleted(e)
	})
}

func (p *promiseImpl) WhenComplete(action func()) Promise {
	return p.then(func(v interface{}) (interface{}, error) {
		action()
		return v, nil
	}, func(e error) (interface{}, error) {
		action()
		return nil, e
	})
}

func (p *promiseImpl) Done(onFulfilled OnFulfilled, onRejected ...OnRejected) {
	p.
		Then(onFulfilled, onRejected...).
		Then(nil, func(e error) (interface{}, error) {
			go panic(e)
			return nil, nil
		})
}

func (p *promiseImpl) Fail(onRejected OnRejected) {
	p.Done(nil, onRejected)
}

func (p *promiseImpl) Always(onCompleted OnCompleted) {
	p.Done(OnFulfilled(onCompleted), func(e error) (interface{}, error) {
		return onCompleted(e)
	})
}

func (p *promiseImpl) State() State {
	return State(p.state)
}

func (p *promiseImpl) resolve(thenable Thenable) {
	var done uint32
	resolveFunc := func(y interface{}) (interface{}, error) {
		if atomic.CompareAndSwapUint32(&done, 0, 1) {
			p.Resolve(y)
		}
		return nil, nil
	}
	rejectFunc := func(e error) (interface{}, error) {
		if atomic.CompareAndSwapUint32(&done, 0, 1) {
			p.Reject(e)
		}
		return nil, nil
	}
	defer func() {
		e := recover()
		if e != nil && atomic.CompareAndSwapUint32(&done, 0, 1) {
			p.Reject(NewPanicError(e))
		}
	}()
	thenable.Then(resolveFunc, rejectFunc)
}

func (p *promiseImpl) Resolve(value interface{}) {
	if promise, ok := value.(*promiseImpl); ok && promise == p {
		p.Reject(TypeError{"Self resolution"})
		return
	}
	if promise, ok := value.(Promise); ok {
		promise.Fill(p)
		return
	}
	if thenable, ok := value.(Thenable); ok {
		p.resolve(thenable)
		return
	}
	if atomic.CompareAndSwapUint32(&p.state, uint32(PENDING), uint32(FULFILLED)) {
		p.value = value
		subscribers := p.subscribers
		p.subscribers = nil
		for _, subscriber := range subscribers {
			resolve(subscriber.onFulfilled, subscriber.next, value)
		}
	}
}

func (p *promiseImpl) Reject(reason error) {
	if atomic.CompareAndSwapUint32(&p.state, uint32(PENDING), uint32(REJECTED)) {
		p.reason = reason
		subscribers := p.subscribers
		p.subscribers = nil
		for _, subscriber := range subscribers {
			reject(subscriber.onRejected, subscriber.next, reason)
		}
	}
}

func (p *promiseImpl) Fill(promise Promise) {
	resolveFunc := func(v interface{}) (interface{}, error) {
		promise.Resolve(v)
		return nil, nil
	}
	rejectFunc := func(e error) (interface{}, error) {
		promise.Reject(e)
		return nil, nil
	}
	p.Then(resolveFunc, rejectFunc)
}

func (p *promiseImpl) Timeout(duration time.Duration, reason ...error) Promise {
	promise := new(promiseImpl)
	timer := time.AfterFunc(duration, func() {
		if len(reason) > 0 {
			promise.Reject(reason[0])
		} else {
			promise.Reject(TimeoutError{})
		}
	})
	p.WhenComplete(func() { timer.Stop() }).Fill(promise)
	return promise
}

func (p *promiseImpl) Delay(duration time.Duration) Promise {
	promise := new(promiseImpl)
	p.then(func(v interface{}) (interface{}, error) {
		go func() {
			time.Sleep(duration)
			promise.Resolve(v)
		}()
		return nil, nil
	}, func(e error) (interface{}, error) {
		promise.Reject(e)
		return nil, nil
	})
	return promise
}

func (p *promiseImpl) Tap(onfulfilledSideEffect OnfulfilledSideEffect) Promise {
	return p.then(func(v interface{}) (interface{}, error) {
		onfulfilledSideEffect(v)
		return v, nil
	}, nil)
}

func (p *promiseImpl) Get() (interface{}, error) {
	c := make(chan interface{})
	p.then(func(v interface{}) (interface{}, error) {
		c <- v
		return nil, nil
	}, func(e error) (interface{}, error) {
		c <- e
		return nil, nil
	})
	v := <-c
	if e, ok := v.(error); ok {
		return nil, e
	}
	return v, nil
}

// New creates a Promise object
func New(value ...interface{}) Promise {
	promise := new(promiseImpl)
	if len(value) > 0 {
		if computation, ok := value[0].(Callable); ok {
			go promise.init(computation)
		} else if e, ok := value[0].(error); ok {
			promise.Reject(e)
		} else {
			promise.Resolve(value[0])
		}
	}
	return promise
}

// Sync creates a Promise object containing the result of immediately calling
// computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Sync(computation Callable) Promise {
	promise := new(promiseImpl)
	promise.init(computation)
	return promise
}

// Delayed creates a Promise object with the given value after a delay.
//
// If the value is a Callable function, it will be executed after the given duration has passed, and the Promise object is completed with the result.
func Delayed(duration time.Duration, value interface{}) Promise {
	promise := new(promiseImpl)
	go func() {
		time.Sleep(duration)
		if computation, ok := value.(Callable); ok {
			promise.init(computation)
		} else if e, ok := value.(error); ok {
			promise.Reject(e)
		} else {
			promise.Resolve(value)
		}
	}()
	return promise
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"

	"github.com/labstack/echo"
	"github.com/pyprism/Hiren-Reminder/controllers"
	"github.com/labstack/echo/middleware"
)

func main() {
	e := echo.New()
	// middleware
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())
	e.Use(middleware.CSRF())
	e.Use(middleware.Gzip())
	e.Use(middleware.RequestID())
	e.Use(middleware.BodyLimit("2M"))
	e.Use(middleware.Secure())

	// static files
	e.Static("/static", "static")
	e.File("/favicon.ico", "static/favicon.ico")

	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello, World! d")
	})
	e.GET("/hello/", controllers.X)
	e.Logger.Fatal(e.Start(":8000"))
}<commit_msg>added index route<commit_after>package main

import (
	//"net/http"

	"github.com/labstack/echo"
	"github.com/pyprism/Hiren-Reminder/controllers"
	"github.com/labstack/echo/middleware"
)

func main() {
	e := echo.New()
	// middleware
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())
	e.Use(middleware.CSRF())
	e.Use(middleware.Gzip())
	e.Use(middleware.RequestID())
	e.Use(middleware.BodyLimit("2M"))
	e.Use(middleware.Secure())

	// static files
	e.Static("/static", "static")
	//e.File("/favicon.ico", "static/favicon.ico")

	e.GET("/", controllers.Index)
	//e.GET("/hello/", controllers.X)
	e.Logger.Fatal(e.Start(":8000"))
}<|endoftext|>