<commit_before>package webloop

import (
	"errors"
	"github.com/sourcegraph/go-webkit2/webkit2"
	"github.com/sqs/gojs"
	"github.com/sqs/gotk3/glib"
)

// ErrLoadFailed indicates that the View failed to load the requested resource.
var ErrLoadFailed = errors.New("load failed")

// Context stores common settings for a group of Views.
type Context struct{}

// New creates a new Context.
func New() *Context {
	return &Context{}
}

// NewView creates a new View in the context.
func (c *Context) NewView() *View {
	view := make(chan *View, 1)
	glib.IdleAdd(func() bool {
		webView := webkit2.NewWebView()
		webView.Settings().SetEnableWriteConsoleMessagesToStdout(true)
		v := &View{WebView: webView}
		loadChangedHandler, _ := webView.Connect("load-changed", func(ctx *glib.CallbackContext) {
			loadEvent := webkit2.LoadEvent(ctx.Arg(0).Int())
			switch loadEvent {
			case webkit2.LoadFinished:
				// If we're here, then the load must not have failed, because
				// otherwise we would've disconnected this handler in the
				// load-failed signal handler.
				v.load <- struct{}{}
			}
		})
		webView.Connect("load-failed", func() {
			v.lastLoadErr = ErrLoadFailed
			webView.HandlerDisconnect(loadChangedHandler)
		})
		view <- v
		return false
	})
	return <-view
}

// View represents a WebKit view that can load resources at a given URL and
// query information about them.
type View struct {
	*webkit2.WebView

	load        chan struct{}
	lastLoadErr error

	destroyed bool
}

// Open starts loading the resource at the specified URL.
func (v *View) Open(url string) {
	v.load = make(chan struct{}, 1)
	v.lastLoadErr = nil
	glib.IdleAdd(func() bool {
		if !v.destroyed {
			v.WebView.LoadURI(url)
		}
		return false
	})
}

// Wait waits for the current page to finish loading.
func (v *View) Wait() error {
	<-v.load
	return v.lastLoadErr
}

// URI returns the URI of the current resource in the view.
func (v *View) URI() string {
	uri := make(chan string, 1)
	glib.IdleAdd(func() bool {
		uri <- v.WebView.URI()
		return false
	})
	return <-uri
}

// Title returns the title of the current resource in the view.
func (v *View) Title() string {
	title := make(chan string, 1)
	glib.IdleAdd(func() bool {
		title <- v.WebView.Title()
		return false
	})
	return <-title
}

// EvaluateJavaScript runs the JavaScript in script in the view's context and
// returns the script's result as a Go value.
func (v *View) EvaluateJavaScript(script string) (result interface{}, err error) {
	resultChan := make(chan interface{}, 1)
	errChan := make(chan error, 1)

	glib.IdleAdd(func() bool {
		v.WebView.RunJavaScript(script, func(result *gojs.Value, err error) {
			glib.IdleAdd(func() bool {
				if err == nil {
					goval, err := result.GoValue()
					if err != nil {
						errChan <- err
						return false
					}
					resultChan <- goval
				} else {
					errChan <- err
				}
				return false
			})
		})
		return false
	})

	select {
	case result = <-resultChan:
		return result, nil
	case err = <-errChan:
		return nil, err
	}
}

// Close closes the view and releases associated resources. Ensure that Close is
// called after all other pending operations on View have returned, or they may
// hang indefinitely.
func (v *View) Close() {
	// TODO(sqs): remove all of the source funcs we added via IdleAdd, etc.,
	// using g_source_remove, to fix "assertion
	// 'WEBKIT_IS_WEB_VIEW(webView) failed" messages.
	v.destroyed = true
	v.Destroy()
}
<commit_msg>Set User-Agent<commit_after>package webloop

import (
	"errors"
	"github.com/sourcegraph/go-webkit2/webkit2"
	"github.com/sqs/gojs"
	"github.com/sqs/gotk3/glib"
)

// ErrLoadFailed indicates that the View failed to load the requested resource.
var ErrLoadFailed = errors.New("load failed")

// Context stores common settings for a group of Views.
type Context struct{}

// New creates a new Context.
func New() *Context {
	return &Context{}
}

// NewView creates a new View in the context.
func (c *Context) NewView() *View {
	view := make(chan *View, 1)
	glib.IdleAdd(func() bool {
		webView := webkit2.NewWebView()
		settings := webView.Settings()
		settings.SetEnableWriteConsoleMessagesToStdout(true)
		settings.SetUserAgentWithApplicationDetails("WebLoop", "v1")
		v := &View{WebView: webView}
		loadChangedHandler, _ := webView.Connect("load-changed", func(ctx *glib.CallbackContext) {
			loadEvent := webkit2.LoadEvent(ctx.Arg(0).Int())
			switch loadEvent {
			case webkit2.LoadFinished:
				// If we're here, then the load must not have failed, because
				// otherwise we would've disconnected this handler in the
				// load-failed signal handler.
				v.load <- struct{}{}
			}
		})
		webView.Connect("load-failed", func() {
			v.lastLoadErr = ErrLoadFailed
			webView.HandlerDisconnect(loadChangedHandler)
		})
		view <- v
		return false
	})
	return <-view
}

// View represents a WebKit view that can load resources at a given URL and
// query information about them.
type View struct {
	*webkit2.WebView

	load        chan struct{}
	lastLoadErr error

	destroyed bool
}

// Open starts loading the resource at the specified URL.
func (v *View) Open(url string) {
	v.load = make(chan struct{}, 1)
	v.lastLoadErr = nil
	glib.IdleAdd(func() bool {
		if !v.destroyed {
			v.WebView.LoadURI(url)
		}
		return false
	})
}

// Wait waits for the current page to finish loading.
func (v *View) Wait() error {
	<-v.load
	return v.lastLoadErr
}

// URI returns the URI of the current resource in the view.
func (v *View) URI() string {
	uri := make(chan string, 1)
	glib.IdleAdd(func() bool {
		uri <- v.WebView.URI()
		return false
	})
	return <-uri
}

// Title returns the title of the current resource in the view.
func (v *View) Title() string {
	title := make(chan string, 1)
	glib.IdleAdd(func() bool {
		title <- v.WebView.Title()
		return false
	})
	return <-title
}

// EvaluateJavaScript runs the JavaScript in script in the view's context and
// returns the script's result as a Go value.
func (v *View) EvaluateJavaScript(script string) (result interface{}, err error) {
	resultChan := make(chan interface{}, 1)
	errChan := make(chan error, 1)

	glib.IdleAdd(func() bool {
		v.WebView.RunJavaScript(script, func(result *gojs.Value, err error) {
			glib.IdleAdd(func() bool {
				if err == nil {
					goval, err := result.GoValue()
					if err != nil {
						errChan <- err
						return false
					}
					resultChan <- goval
				} else {
					errChan <- err
				}
				return false
			})
		})
		return false
	})

	select {
	case result = <-resultChan:
		return result, nil
	case err = <-errChan:
		return nil, err
	}
}

// Close closes the view and releases associated resources. Ensure that Close is
// called after all other pending operations on View have returned, or they may
// hang indefinitely.
func (v *View) Close() {
	// TODO(sqs): remove all of the source funcs we added via IdleAdd, etc.,
	// using g_source_remove, to fix "assertion
	// 'WEBKIT_IS_WEB_VIEW(webView) failed" messages.
	v.destroyed = true
	v.Destroy()
}
<|endoftext|>


<commit_before>package stats

import (
	"fmt"
	"time"

	"github.com/rancher/sparse-tools/log"
)

import "sync"

const (
	defaultBufferSize = 100 * 1000 // sample buffer size (cyclic)
)

//SampleOp operation
type SampleOp int

const (
	OpRead  = SampleOp(0)
	OpWrite = SampleOp(1)
	OpPing  = SampleOp(2)
)

type dataPoint struct {
	target    int // e.g replica index
	op        SampleOp
	timestamp time.Time
	duration  time.Duration
	size      int // i/o operation size
}

// String conversions
func (op SampleOp) String() string {
	switch op {
	case OpRead:
		return "R"
	case OpWrite:
		return "W"
	case OpPing:
		return "P"
	}
	return "<unknown op>"
}

func (sample dataPoint) String() string {
	return fmt.Sprintf("%s: #%d %v[%4dkB] %8dus", sample.timestamp.Format(time.StampMicro), sample.target, sample.op, sample.size, sample.duration.Nanoseconds()/1000)
}

var (
	bufferSize = defaultBufferSize
	data       []dataPoint
	mutex      sync.Mutex
	head       = 0 // next sample index
	length     = 0
	unreported = 0 // count of not yet reported/processed samples
)

func initStats(size int) {
	bufferSize = size
	data = make([]dataPoint, size)
	head = 0
	length = 0
	unreported = 0
	log.Debug("Stats.init=", size)
}

func init() {
	initStats(bufferSize)
}

func wrapIndex(pos int) int {
	return (pos + bufferSize) % bufferSize
}

func storeSample(sample dataPoint) {
	mutex.Lock()
	log.Debug("Stats.sample[", head, "]=", sample)
	if length < bufferSize {
		length++
	}
	if unreported < bufferSize {
		unreported++
	}
	data[head] = sample
	head = wrapIndex(head + 1)
	mutex.Unlock()
}

// Sample to the cyclic buffer
func Sample(timestamp time.Time, duration time.Duration, target int, op SampleOp, size int) {
	storeSample(dataPoint{target, op, timestamp, duration, size})
}

// Process unreported samples
func Process(processor func(dataPoint)) chan struct{} {
	// Fetch unreported window
	mutex.Lock()
	items := unreported
	unreported = 0
	log.Debug("Stats.Processing unreported=", items)
	i := wrapIndex(head - items)
	dataCopy := make([]dataPoint, items)
	if i+items <= bufferSize {
		copy(dataCopy, data[i:i+items])
	} else {
		copy(dataCopy, data[i:])
		items -= bufferSize - i
		copy(dataCopy[bufferSize-i:], data[:items])
	}
	mutex.Unlock()

	done := make(chan struct{})
	go func(data []dataPoint, done chan struct{}) {
		for _, sample := range data {
			log.Debug("Stats.Processing=", sample)
			processor(sample)
		}
		close(done)
	}(dataCopy, done)
	return done
}

func printSample(sample dataPoint) {
	fmt.Println(sample)
}

// Print samples
func Print() chan struct{} {
	return Process(printSample)
}

// Test helper to exercise small buffer sizes
func resetStats(size int) {
	log.Debug("Stats.reset")
	initStats(size)
}
<commit_msg>stats: added comments to make lint happy<commit_after>package stats

import (
	"fmt"
	"time"

	"github.com/rancher/sparse-tools/log"
)

import "sync"

const (
	defaultBufferSize = 100 * 1000 // sample buffer size (cyclic)
)

//SampleOp operation
type SampleOp int

const (
	// OpRead read from replica
	OpRead = SampleOp(0)
	// OpWrite write to replica
	OpWrite = SampleOp(1)
	// OpPing ping replica
	OpPing = SampleOp(2)
)

type dataPoint struct {
	target    int // e.g replica index
	op        SampleOp
	timestamp time.Time
	duration  time.Duration
	size      int // i/o operation size
}

// String conversions
func (op SampleOp) String() string {
	switch op {
	case OpRead:
		return "R"
	case OpWrite:
		return "W"
	case OpPing:
		return "P"
	}
	return "<unknown op>"
}

func (sample dataPoint) String() string {
	return fmt.Sprintf("%s: #%d %v[%4dkB] %8dus", sample.timestamp.Format(time.StampMicro), sample.target, sample.op, sample.size, sample.duration.Nanoseconds()/1000)
}

var (
	bufferSize = defaultBufferSize
	data       []dataPoint
	mutex      sync.Mutex
	head       = 0 // next sample index
	length     = 0
	unreported = 0 // count of not yet reported/processed samples
)

func initStats(size int) {
	bufferSize = size
	data = make([]dataPoint, size)
	head = 0
	length = 0
	unreported = 0
	log.Debug("Stats.init=", size)
}

func init() {
	initStats(bufferSize)
}

func wrapIndex(pos int) int {
	return (pos + bufferSize) % bufferSize
}

func storeSample(sample dataPoint) {
	mutex.Lock()
	log.Debug("Stats.sample[", head, "]=", sample)
	if length < bufferSize {
		length++
	}
	if unreported < bufferSize {
		unreported++
	}
	data[head] = sample
	head = wrapIndex(head + 1)
	mutex.Unlock()
}

// Sample to the cyclic buffer
func Sample(timestamp time.Time, duration time.Duration, target int, op SampleOp, size int) {
	storeSample(dataPoint{target, op, timestamp, duration, size})
}

// Process unreported samples
func Process(processor func(dataPoint)) chan struct{} {
	// Fetch unreported window
	mutex.Lock()
	items := unreported
	unreported = 0
	log.Debug("Stats.Processing unreported=", items)
	i := wrapIndex(head - items)
	dataCopy := make([]dataPoint, items)
	if i+items <= bufferSize {
		copy(dataCopy, data[i:i+items])
	} else {
		copy(dataCopy, data[i:])
		items -= bufferSize - i
		copy(dataCopy[bufferSize-i:], data[:items])
	}
	mutex.Unlock()

	done := make(chan struct{})
	go func(data []dataPoint, done chan struct{}) {
		for _, sample := range data {
			log.Debug("Stats.Processing=", sample)
			processor(sample)
		}
		close(done)
	}(dataCopy, done)
	return done
}

func printSample(sample dataPoint) {
	fmt.Println(sample)
}

// Print samples
func Print() chan struct{} {
	return Process(printSample)
}

// Test helper to exercise small buffer sizes
func resetStats(size int) {
	log.Debug("Stats.reset")
	initStats(size)
}
<|endoftext|>


<commit_before>package stats

import (
	"fmt"
	"math"
	"net/url"
	"regexp"
	"sort"
	"sync"

	"github.com/tkuchiki/alp/errors"
	"github.com/tkuchiki/alp/helpers"
	"github.com/tkuchiki/alp/options"
	"github.com/tkuchiki/alp/parsers"
)

type hints struct {
	values map[string]int
	len    int
	mu     sync.RWMutex
}

func newHints() *hints {
	return &hints{
		values: make(map[string]int),
	}
}

func (h *hints) loadOrStore(key string) int {
	h.mu.Lock()
	defer h.mu.Unlock()
	_, ok := h.values[key]
	if !ok {
		h.values[key] = h.len
		h.len++
	}

	return h.values[key]
}

type HTTPStats struct {
	hints                          *hints
	stats                          httpStats
	useResponseTimePercentile      bool
	useRequestBodyBytesPercentile  bool
	useResponseBodyBytesPercentile bool
	filter                         *Filter
	options                        *options.Options
	sortOptions                    *SortOptions
	uriMatchingGroups              []*regexp.Regexp
}

func NewHTTPStats(useResTimePercentile, useRequestBodyBytesPercentile, useResponseBodyBytesPercentile bool) *HTTPStats {
	return &HTTPStats{
		hints:                          newHints(),
		stats:                          make([]*HTTPStat, 0),
		useResponseTimePercentile:      useResTimePercentile,
		useResponseBodyBytesPercentile: useResponseBodyBytesPercentile,
	}
}

func (hs *HTTPStats) Set(uri, method string, status int, restime, resBodyBytes, reqBodyBytes float64) {
	if len(hs.uriMatchingGroups) > 0 {
		for _, re := range hs.uriMatchingGroups {
			if ok := re.Match([]byte(uri)); ok {
				pattern := re.String()
				uri = pattern
			}
		}
	}

	key := fmt.Sprintf("%s_%s", method, uri)

	idx := hs.hints.loadOrStore(key)

	if idx >= len(hs.stats) {
		hs.stats = append(hs.stats, newHTTPStat(uri, method, hs.useResponseTimePercentile, hs.useRequestBodyBytesPercentile, hs.useResponseBodyBytesPercentile))
	}

	hs.stats[idx].Set(status, restime, resBodyBytes, reqBodyBytes)
}

func (hs *HTTPStats) Stats() []*HTTPStat {
	return hs.stats
}

func (hs *HTTPStats) CountUris() int {
	return hs.hints.len
}

func (hs *HTTPStats) SetOptions(options *options.Options) {
	hs.options = options
}

func (hs *HTTPStats) SetSortOptions(options *SortOptions) {
	hs.sortOptions = options
}

func (hs *HTTPStats) SetURIMatchingGroups(groups []string) error {
	uriGroups, err := helpers.CompileUriMatchingGroups(groups)
	if err != nil {
		return err
	}

	hs.uriMatchingGroups = uriGroups

	return nil
}

func (hs *HTTPStats) InitFilter(options *options.Options) error {
	hs.filter = NewFilter(options)
	return hs.filter.Init()
}

func (hs *HTTPStats) DoFilter(pstat *parsers.ParsedHTTPStat) (bool, error) {
	err := hs.filter.Do(pstat)
	if err == errors.SkipReadLineErr {
		return false, nil
	} else if err != nil {
		return false, err
	}

	return true, nil
}

func (hs *HTTPStats) CountAll() map[string]int {
	counts := make(map[string]int, 6)

	for _, s := range hs.stats {
		counts["count"] += s.Cnt
		counts["1xx"] += s.Status1xx
		counts["2xx"] += s.Status2xx
		counts["3xx"] += s.Status3xx
		counts["4xx"] += s.Status4xx
		counts["5xx"] += s.Status5xx
	}

	return counts
}

func (hs *HTTPStats) SortWithOptions() {
	hs.Sort(hs.sortOptions, hs.options.Reverse)
}

type HTTPStat struct {
	Uri               string        `yaml:"uri"`
	Cnt               int           `yaml:"count"`
	Status1xx         int           `yaml:"status1xx"`
	Status2xx         int           `yaml:"status2xx"`
	Status3xx         int           `yaml:"status3xx"`
	Status4xx         int           `yaml:"status4xx"`
	Status5xx         int           `yaml:"status5xx"`
	Method            string        `yaml:"method"`
	ResponseTime      *responseTime `yaml:"response_time"`
	RequestBodyBytes  *bodyBytes    `yaml:"request_body_bytes"`
	ResponseBodyBytes *bodyBytes    `yaml:"response_body_bytes"`
	Time              string
}

type httpStats []*HTTPStat

func newHTTPStat(uri, method string, useResTimePercentile, useRequestBodyBytesPercentile, useResponseBodyBytesPercentile bool) *HTTPStat {
	return &HTTPStat{
		Uri:               uri,
		Method:            method,
		ResponseTime:      newResponseTime(useResTimePercentile),
		RequestBodyBytes:  newBodyBytes(useRequestBodyBytesPercentile),
		ResponseBodyBytes: newBodyBytes(useResponseBodyBytesPercentile),
	}
}

func (hs *HTTPStat) Set(status int, restime, reqBodyBytes, resBodyBytes float64) {
	hs.Cnt++
	hs.setStatus(status)
	hs.ResponseTime.Set(restime)
	hs.RequestBodyBytes.Set(reqBodyBytes)
	hs.ResponseBodyBytes.Set(resBodyBytes)
}

func (hs *HTTPStat) setStatus(status int) {
	if status >= 100 && status <= 199 {
		hs.Status1xx++
	} else if status >= 200 && status <= 299 {
		hs.Status2xx++
	} else if status >= 300 && status <= 399 {
		hs.Status3xx++
	} else if status >= 400 && status <= 499 {
		hs.Status4xx++
	} else if status >= 500 && status <= 599 {
		hs.Status5xx++
	}
}

func (hs *HTTPStat) UriWithOptions(decode bool) string {
	if !decode {
		return hs.Uri
	}

	u, err := url.Parse(hs.Uri)
	if err != nil {
		return hs.Uri
	}

	if u.RawQuery == "" {
		unescaped, _ := url.PathUnescape(u.EscapedPath())
		return unescaped
	}

	unescaped, _ := url.PathUnescape(u.EscapedPath())
	decoded, _ := url.QueryUnescape(u.Query().Encode())

	return fmt.Sprintf("%s?%s", unescaped, decoded)
}

func (hs *HTTPStat) StrStatus1xx() string {
	return fmt.Sprint(hs.Status1xx)
}

func (hs *HTTPStat) StrStatus2xx() string {
	return fmt.Sprint(hs.Status2xx)
}

func (hs *HTTPStat) StrStatus3xx() string {
	return fmt.Sprint(hs.Status3xx)
}

func (hs *HTTPStat) StrStatus4xx() string {
	return fmt.Sprint(hs.Status4xx)
}

func (hs *HTTPStat) StrStatus5xx() string {
	return fmt.Sprint(hs.Status5xx)
}

func (hs *HTTPStat) Count() int {
	return hs.Cnt
}

func (hs *HTTPStat) StrCount() string {
	return fmt.Sprint(hs.Cnt)
}

func (hs *HTTPStat) MaxResponseTime() float64 {
	return hs.ResponseTime.Max
}

func (hs *HTTPStat) MinResponseTime() float64 {
	return hs.ResponseTime.Min
}

func (hs *HTTPStat) SumResponseTime() float64 {
	return hs.ResponseTime.Sum
}

func (hs *HTTPStat) AvgResponseTime() float64 {
	return hs.ResponseTime.Avg(hs.Cnt)
}

func (hs *HTTPStat) PNResponseTime(n int) float64 {
	return hs.ResponseTime.PN(hs.Cnt, n)
}

func (hs *HTTPStat) StddevResponseTime() float64 {
	return hs.ResponseTime.Stddev(hs.Cnt)
}

// request
func (hs *HTTPStat) MaxRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Max
}

func (hs *HTTPStat) MinRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Min
}

func (hs *HTTPStat) SumRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Sum
}

func (hs *HTTPStat) AvgRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Avg(hs.Cnt)
}

func (hs *HTTPStat) PNRequestBodyBytes(n int) float64 {
	return hs.RequestBodyBytes.PN(hs.Cnt, n)
}

func (hs *HTTPStat) StddevRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Stddev(hs.Cnt)
}

// response
func (hs *HTTPStat) MaxResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Max
}

func (hs *HTTPStat) MinResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Min
}

func (hs *HTTPStat) SumResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Sum
}

func (hs *HTTPStat) AvgResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Avg(hs.Cnt)
}

func (hs *HTTPStat) PNResponseBodyBytes(n int) float64 {
	return hs.RequestBodyBytes.PN(hs.Cnt, n)
}

func (hs *HTTPStat) StddevResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Stddev(hs.Cnt)
}

func percentRank(n int, pi int) int {
	if pi == 0 {
		return 0
	} else if pi == 100 {
		return n - 1
	}

	p := float64(pi) / 100.0
	pos := int(float64(n+1) * p)
	if pos < 0 {
		pos = 0
	}

	return pos - 1
}

type responseTime struct {
	Max           float64 `yaml:"max"`
	Min           float64 `yaml:"min"`
	Sum           float64 `yaml:"sum"`
	UsePercentile bool
	Percentiles   []float64 `yaml:"percentiles"`
}

func newResponseTime(usePercentile bool) *responseTime {
	return &responseTime{
		UsePercentile: usePercentile,
		Percentiles:   make([]float64, 0),
	}
}

func (res *responseTime) Set(val float64) {
	if res.Max < val {
		res.Max = val
	}

	if res.Min >= val || res.Min == 0 {
		res.Min = val
	}

	res.Sum += val

	if res.UsePercentile {
		res.Percentiles = append(res.Percentiles, val)
	}
}

func (res *responseTime) Avg(cnt int) float64 {
	return res.Sum / float64(cnt)
}

func (res *responseTime) PN(cnt, n int) float64 {
	if !res.UsePercentile {
		return 0.0
	}

	plen := percentRank(cnt, n)
	res.Sort()
	return res.Percentiles[plen]
}

func (res *responseTime) Stddev(cnt int) float64 {
	if !res.UsePercentile {
		return 0.0
	}

	var stdd float64
	avg := res.Avg(cnt)
	n := float64(cnt)

	for _, v := range res.Percentiles {
		stdd += (v - avg) * (v - avg)
	}

	return math.Sqrt(stdd / n)
}

func (res *responseTime) Sort() {
	sort.Slice(res.Percentiles, func(i, j int) bool {
		return res.Percentiles[i] < res.Percentiles[j]
	})
}

type bodyBytes struct {
	Max           float64 `yaml:"max"`
	Min           float64 `yaml:"min"`
	Sum           float64 `yaml:"sum"`
	UsePercentile bool
	Percentiles   []float64 `yaml:"percentiles"`
}

func newBodyBytes(usePercentile bool) *bodyBytes {
	return &bodyBytes{
		UsePercentile: usePercentile,
		Percentiles:   make([]float64, 0),
	}
}

func (body *bodyBytes) Set(val float64) {
	if body.Max < val {
		body.Max = val
	}

	if body.Min >= val || body.Min == 0.0 {
		body.Min = val
	}

	body.Sum += val

	if body.UsePercentile {
		body.Percentiles = append(body.Percentiles, val)
	}
}

func (body *bodyBytes) Avg(cnt int) float64 {
	return body.Sum / float64(cnt)
}

func (body *bodyBytes) PN(cnt, n int) float64 {
	if !body.UsePercentile {
		return 0.0
	}

	plen := percentRank(cnt, n)
	body.Sort()
	return body.Percentiles[plen]
}

func (body *bodyBytes) Stddev(cnt int) float64 {
	if !body.UsePercentile {
		return 0.0
	}

	var stdd float64
	avg := body.Avg(cnt)
	n := float64(cnt)

	for _, v := range body.Percentiles {
		stdd += (v - avg) * (v - avg)
	}

	return math.Sqrt(stdd / n)
}

func (body *bodyBytes) Sort() {
	sort.Slice(body.Percentiles, func(i, j int) bool {
		return body.Percentiles[i] < body.Percentiles[j]
	})
}
<commit_msg>break...<commit_after>package stats

import (
	"fmt"
	"math"
	"net/url"
	"regexp"
	"sort"
	"sync"

	"github.com/tkuchiki/alp/errors"
	"github.com/tkuchiki/alp/helpers"
	"github.com/tkuchiki/alp/options"
	"github.com/tkuchiki/alp/parsers"
)

type hints struct {
	values map[string]int
	len    int
	mu     sync.RWMutex
}

func newHints() *hints {
	return &hints{
		values: make(map[string]int),
	}
}

func (h *hints) loadOrStore(key string) int {
	h.mu.Lock()
	defer h.mu.Unlock()
	_, ok := h.values[key]
	if !ok {
		h.values[key] = h.len
		h.len++
	}

	return h.values[key]
}

type HTTPStats struct {
	hints                          *hints
	stats                          httpStats
	useResponseTimePercentile      bool
	useRequestBodyBytesPercentile  bool
	useResponseBodyBytesPercentile bool
	filter                         *Filter
	options                        *options.Options
	sortOptions                    *SortOptions
	uriMatchingGroups              []*regexp.Regexp
}

func NewHTTPStats(useResTimePercentile, useRequestBodyBytesPercentile, useResponseBodyBytesPercentile bool) *HTTPStats {
	return &HTTPStats{
		hints:                          newHints(),
		stats:                          make([]*HTTPStat, 0),
		useResponseTimePercentile:      useResTimePercentile,
		useResponseBodyBytesPercentile: useResponseBodyBytesPercentile,
	}
}

func (hs *HTTPStats) Set(uri, method string, status int, restime, resBodyBytes, reqBodyBytes float64) {
	if len(hs.uriMatchingGroups) > 0 {
		for _, re := range hs.uriMatchingGroups {
			if ok := re.Match([]byte(uri)); ok {
				pattern := re.String()
				uri = pattern
				break
			}
		}
	}

	key := fmt.Sprintf("%s_%s", method, uri)

	idx := hs.hints.loadOrStore(key)

	if idx >= len(hs.stats) {
		hs.stats = append(hs.stats, newHTTPStat(uri, method, hs.useResponseTimePercentile, hs.useRequestBodyBytesPercentile, hs.useResponseBodyBytesPercentile))
	}

	hs.stats[idx].Set(status, restime, resBodyBytes, reqBodyBytes)
}

func (hs *HTTPStats) Stats() []*HTTPStat {
	return hs.stats
}

func (hs *HTTPStats) CountUris() int {
	return hs.hints.len
}

func (hs *HTTPStats) SetOptions(options *options.Options) {
	hs.options = options
}

func (hs *HTTPStats) SetSortOptions(options *SortOptions) {
	hs.sortOptions = options
}

func (hs *HTTPStats) SetURIMatchingGroups(groups []string) error {
	uriGroups, err := helpers.CompileUriMatchingGroups(groups)
	if err != nil {
		return err
	}

	hs.uriMatchingGroups = uriGroups

	return nil
}

func (hs *HTTPStats) InitFilter(options *options.Options) error {
	hs.filter = NewFilter(options)
	return hs.filter.Init()
}

func (hs *HTTPStats) DoFilter(pstat *parsers.ParsedHTTPStat) (bool, error) {
	err := hs.filter.Do(pstat)
	if err == errors.SkipReadLineErr {
		return false, nil
	} else if err != nil {
		return false, err
	}

	return true, nil
}

func (hs *HTTPStats) CountAll() map[string]int {
	counts := make(map[string]int, 6)

	for _, s := range hs.stats {
		counts["count"] += s.Cnt
		counts["1xx"] += s.Status1xx
		counts["2xx"] += s.Status2xx
		counts["3xx"] += s.Status3xx
		counts["4xx"] += s.Status4xx
		counts["5xx"] += s.Status5xx
	}

	return counts
}

func (hs *HTTPStats) SortWithOptions() {
	hs.Sort(hs.sortOptions, hs.options.Reverse)
}

type HTTPStat struct {
	Uri               string        `yaml:"uri"`
	Cnt               int           `yaml:"count"`
	Status1xx         int           `yaml:"status1xx"`
	Status2xx         int           `yaml:"status2xx"`
	Status3xx         int           `yaml:"status3xx"`
	Status4xx         int           `yaml:"status4xx"`
	Status5xx         int           `yaml:"status5xx"`
	Method            string        `yaml:"method"`
	ResponseTime      *responseTime `yaml:"response_time"`
	RequestBodyBytes  *bodyBytes    `yaml:"request_body_bytes"`
	ResponseBodyBytes *bodyBytes    `yaml:"response_body_bytes"`
	Time              string
}

type httpStats []*HTTPStat

func newHTTPStat(uri, method string, useResTimePercentile, useRequestBodyBytesPercentile, useResponseBodyBytesPercentile bool) *HTTPStat {
	return &HTTPStat{
		Uri:               uri,
		Method:            method,
		ResponseTime:      newResponseTime(useResTimePercentile),
		RequestBodyBytes:  newBodyBytes(useRequestBodyBytesPercentile),
		ResponseBodyBytes: newBodyBytes(useResponseBodyBytesPercentile),
	}
}

func (hs *HTTPStat) Set(status int, restime, reqBodyBytes, resBodyBytes float64) {
	hs.Cnt++
	hs.setStatus(status)
	hs.ResponseTime.Set(restime)
	hs.RequestBodyBytes.Set(reqBodyBytes)
	hs.ResponseBodyBytes.Set(resBodyBytes)
}

func (hs *HTTPStat) setStatus(status int) {
	if status >= 100 && status <= 199 {
		hs.Status1xx++
	} else if status >= 200 && status <= 299 {
		hs.Status2xx++
	} else if status >= 300 && status <= 399 {
		hs.Status3xx++
	} else if status >= 400 && status <= 499 {
		hs.Status4xx++
	} else if status >= 500 && status <= 599 {
		hs.Status5xx++
	}
}

func (hs *HTTPStat) UriWithOptions(decode bool) string {
	if !decode {
		return hs.Uri
	}

	u, err := url.Parse(hs.Uri)
	if err != nil {
		return hs.Uri
	}

	if u.RawQuery == "" {
		unescaped, _ := url.PathUnescape(u.EscapedPath())
		return unescaped
	}

	unescaped, _ := url.PathUnescape(u.EscapedPath())
	decoded, _ := url.QueryUnescape(u.Query().Encode())

	return fmt.Sprintf("%s?%s", unescaped, decoded)
}

func (hs *HTTPStat) StrStatus1xx() string {
	return fmt.Sprint(hs.Status1xx)
}

func (hs *HTTPStat) StrStatus2xx() string {
	return fmt.Sprint(hs.Status2xx)
}

func (hs *HTTPStat) StrStatus3xx() string {
	return fmt.Sprint(hs.Status3xx)
}

func (hs *HTTPStat) StrStatus4xx() string {
	return fmt.Sprint(hs.Status4xx)
}

func (hs *HTTPStat) StrStatus5xx() string {
	return fmt.Sprint(hs.Status5xx)
}

func (hs *HTTPStat) Count() int {
	return hs.Cnt
}

func (hs *HTTPStat) StrCount() string {
	return fmt.Sprint(hs.Cnt)
}

func (hs *HTTPStat) MaxResponseTime() float64 {
	return hs.ResponseTime.Max
}

func (hs *HTTPStat) MinResponseTime() float64 {
	return hs.ResponseTime.Min
}

func (hs *HTTPStat) SumResponseTime() float64 {
	return hs.ResponseTime.Sum
}

func (hs *HTTPStat) AvgResponseTime() float64 {
	return hs.ResponseTime.Avg(hs.Cnt)
}

func (hs *HTTPStat) PNResponseTime(n int) float64 {
	return hs.ResponseTime.PN(hs.Cnt, n)
}

func (hs *HTTPStat) StddevResponseTime() float64 {
	return hs.ResponseTime.Stddev(hs.Cnt)
}

// request
func (hs *HTTPStat) MaxRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Max
}

func (hs *HTTPStat) MinRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Min
}

func (hs *HTTPStat) SumRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Sum
}

func (hs *HTTPStat) AvgRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Avg(hs.Cnt)
}

func (hs *HTTPStat) PNRequestBodyBytes(n int) float64 {
	return hs.RequestBodyBytes.PN(hs.Cnt, n)
}

func (hs *HTTPStat) StddevRequestBodyBytes() float64 {
	return hs.RequestBodyBytes.Stddev(hs.Cnt)
}

// response
func (hs *HTTPStat) MaxResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Max
}

func (hs *HTTPStat) MinResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Min
}

func (hs *HTTPStat) SumResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Sum
}

func (hs *HTTPStat) AvgResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Avg(hs.Cnt)
}

func (hs *HTTPStat) PNResponseBodyBytes(n int) float64 {
	return hs.RequestBodyBytes.PN(hs.Cnt, n)
}

func (hs *HTTPStat) StddevResponseBodyBytes() float64 {
	return hs.RequestBodyBytes.Stddev(hs.Cnt)
}

func percentRank(n int, pi int) int {
	if pi == 0 {
		return 0
	} else if pi == 100 {
		return n - 1
	}

	p := float64(pi) / 100.0
	pos := int(float64(n+1) * p)
	if pos < 0 {
		pos = 0
	}

	return pos - 1
}

type responseTime struct {
	Max           float64 `yaml:"max"`
	Min           float64 `yaml:"min"`
	Sum           float64 `yaml:"sum"`
	UsePercentile bool
	Percentiles   []float64 `yaml:"percentiles"`
}

func newResponseTime(usePercentile bool) *responseTime {
	return &responseTime{
		UsePercentile: usePercentile,
		Percentiles:   make([]float64, 0),
	}
}

func (res *responseTime) Set(val float64) {
	if res.Max < val {
		res.Max = val
	}

	if res.Min >= val || res.Min == 0 {
		res.Min = val
	}

	res.Sum += val

	if res.UsePercentile {
		res.Percentiles = append(res.Percentiles, val)
	}
}

func (res *responseTime) Avg(cnt int) float64 {
	return res.Sum / float64(cnt)
}

func (res *responseTime) PN(cnt, n int) float64 {
	if !res.UsePercentile {
		return 0.0
	}

	plen := percentRank(cnt, n)
	res.Sort()
	return res.Percentiles[plen]
}

func (res *responseTime) Stddev(cnt int) float64 {
	if !res.UsePercentile {
		return 0.0
	}

	var stdd float64
	avg := res.Avg(cnt)
	n := float64(cnt)

	for _, v := range res.Percentiles {
		stdd += (v - avg) * (v - avg)
	}

	return math.Sqrt(stdd / n)
}

func (res *responseTime) Sort() {
	sort.Slice(res.Percentiles, func(i, j int) bool {
		return res.Percentiles[i] < res.Percentiles[j]
	})
}

type bodyBytes struct {
	Max           float64 `yaml:"max"`
	Min           float64 `yaml:"min"`
	Sum           float64 `yaml:"sum"`
	UsePercentile bool
	Percentiles   []float64 `yaml:"percentiles"`
}

func newBodyBytes(usePercentile bool) *bodyBytes {
	return &bodyBytes{
		UsePercentile: usePercentile,
		Percentiles:   make([]float64, 0),
	}
}

func (body *bodyBytes) Set(val float64) {
	if body.Max < val {
		body.Max = val
	}

	if body.Min >= val || body.Min == 0.0 {
		body.Min = val
	}

	body.Sum += val

	if body.UsePercentile {
		body.Percentiles = append(body.Percentiles, val)
	}
}

func (body *bodyBytes) Avg(cnt int) float64 {
	return body.Sum / float64(cnt)
}

func (body *bodyBytes) PN(cnt, n int) float64 {
	if !body.UsePercentile {
		return 0.0
	}

	plen := percentRank(cnt, n)
	body.Sort()
	return body.Percentiles[plen]
}

func (body *bodyBytes) Stddev(cnt int) float64 {
	if !body.UsePercentile {
		return 0.0
	}

	var stdd float64
	avg := body.Avg(cnt)
	n := float64(cnt)

	for _, v := range body.Percentiles {
		stdd += (v - avg) * (v - avg)
	}

	return math.Sqrt(stdd / n)
}

func (body *bodyBytes) Sort() {
	sort.Slice(body.Percentiles, func(i, j int) bool {
		return body.Percentiles[i] < body.Percentiles[j]
	})
}
<|endoftext|>


<commit_before>package stats

import (
	"encoding/json"
	"fmt"
	"github.com/dustin/go-humanize"
	"github.com/gin-gonic/gin"
	"runtime"
	"time"

	e "github.com/eirka/eirka-libs/errors"
)

var (
	startTime = time.Now()
)

type Statistics struct {
	Uptime       string
	NumGoroutine int

	// General statistics.
	MemAllocated string // bytes allocated and still in use
	MemTotal     string // bytes allocated (even if freed)
	MemSys       string // bytes obtained from system (sum of XxxSys below)
	Lookups      uint64 // number of pointer lookups
	MemMallocs   uint64 // number of mallocs
	MemFrees     uint64 // number of frees

	// Main allocation heap statistics.
	HeapAlloc    string // bytes allocated and still in use
	HeapSys      string // bytes obtained from system
	HeapIdle     string // bytes in idle spans
	HeapInuse    string // bytes in non-idle span
	HeapReleased string // bytes released to the OS
	HeapObjects  uint64 // total number of allocated objects

	// Low-level fixed-size structure allocator statistics.
	//	Inuse is bytes used now.
	//	Sys is bytes obtained from system.
	StackInuse  string // bootstrap stacks
	StackSys    string
	MSpanInuse  string // mspan structures
	MSpanSys    string
	MCacheInuse string // mcache structures
	MCacheSys   string
	BuckHashSys string // profiling bucket hash table
	GCSys       string // GC metadata
	OtherSys    string // other system allocations

	// Garbage collector statistics.
	NextGC       string // next run in HeapAlloc time (bytes)
	LastGC       string // last run in absolute time (ns)
	PauseTotalNs string
	PauseNs      string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
	NumGC        uint32
}

func StatusController(c *gin.Context) {
	m := new(runtime.MemStats)
	runtime.ReadMemStats(m)

	stats := &Statistics{
		Uptime:       humanize.Time(startTime),
		NumGoroutine: runtime.NumGoroutine(),
		MemAllocated: humanize.Bytes(m.Alloc),
		MemTotal:     humanize.Bytes(m.TotalAlloc),
		MemSys:       humanize.Bytes(m.Sys),
		Lookups:      m.Lookups,
		MemMallocs:   m.Mallocs,
		MemFrees:     m.Frees,
		HeapAlloc:    humanize.Bytes(m.HeapAlloc),
		HeapSys:      humanize.Bytes(m.HeapSys),
		HeapIdle:     humanize.Bytes(m.HeapIdle),
		HeapInuse:    humanize.Bytes(m.HeapInuse),
		HeapReleased: humanize.Bytes(m.HeapReleased),
		HeapObjects:  m.HeapObjects,
		StackInuse:   humanize.Bytes(m.StackInuse),
		StackSys:     humanize.Bytes(m.StackSys),
		MSpanInuse:   humanize.Bytes(m.MSpanInuse),
		MSpanSys:     humanize.Bytes(m.MSpanSys),
		MCacheInuse:  humanize.Bytes(m.MCacheInuse),
		MCacheSys:    humanize.Bytes(m.MCacheSys),
		BuckHashSys:  humanize.Bytes(m.BuckHashSys),
		GCSys:        humanize.Bytes(m.GCSys),
		OtherSys:     humanize.Bytes(m.OtherSys),
		NextGC:       humanize.Bytes(m.NextGC),
		LastGC:       fmt.Sprintf("%.1fs", float64(time.Now().UnixNano()-int64(m.LastGC))/1000/1000/1000),
		PauseTotalNs: fmt.Sprintf("%.1fs", float64(m.PauseTotalNs)/1000/1000/1000),
		PauseNs:      fmt.Sprintf("%.3fs", float64(m.PauseNs[(m.NumGC+255)%256])/1000/1000/1000),
		NumGC:        m.NumGC,
	}

	// Marshal the structs into JSON
	output, err := json.Marshal(stats)
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err).SetMeta("StatusController.Marshal")
		return
	}

	c.Data(200, "application/json", output)

	return

}
<commit_msg>add stats controller<commit_after>package status

import (
	"encoding/json"
	"fmt"
	"github.com/dustin/go-humanize"
	"github.com/gin-gonic/gin"
	"runtime"
	"time"

	e "github.com/eirka/eirka-libs/errors"
)

var (
	startTime = time.Now()
)

type Statistics struct {
	Uptime       string
	NumGoroutine int

	// General statistics.
	MemAllocated string // bytes allocated and still in use
	MemTotal     string // bytes allocated (even if freed)
	MemSys       string // bytes obtained from system (sum of XxxSys below)
	Lookups      uint64 // number of pointer lookups
	MemMallocs   uint64 // number of mallocs
	MemFrees     uint64 // number of frees

	// Main allocation heap statistics.
	HeapAlloc    string // bytes allocated and still in use
	HeapSys      string // bytes obtained from system
	HeapIdle     string // bytes in idle spans
	HeapInuse    string // bytes in non-idle span
	HeapReleased string // bytes released to the OS
	HeapObjects  uint64 // total number of allocated objects

	// Low-level fixed-size structure allocator statistics.
	//	Inuse is bytes used now.
	//	Sys is bytes obtained from system.
	StackInuse  string // bootstrap stacks
	StackSys    string
	MSpanInuse  string // mspan structures
	MSpanSys    string
	MCacheInuse string // mcache structures
	MCacheSys   string
	BuckHashSys string // profiling bucket hash table
	GCSys       string // GC metadata
	OtherSys    string // other system allocations

	// Garbage collector statistics.
	NextGC       string // next run in HeapAlloc time (bytes)
	LastGC       string // last run in absolute time (ns)
	PauseTotalNs string
	PauseNs      string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
	NumGC        uint32
}

func StatusController(c *gin.Context) {
	m := new(runtime.MemStats)
	runtime.ReadMemStats(m)

	stats := &Statistics{
		Uptime:       humanize.Time(startTime),
		NumGoroutine: runtime.NumGoroutine(),
		MemAllocated: humanize.Bytes(m.Alloc),
		MemTotal:     humanize.Bytes(m.TotalAlloc),
		MemSys:       humanize.Bytes(m.Sys),
		Lookups:      m.Lookups,
		MemMallocs:   m.Mallocs,
		MemFrees:     m.Frees,
		HeapAlloc:    humanize.Bytes(m.HeapAlloc),
		HeapSys:      humanize.Bytes(m.HeapSys),
		HeapIdle:     humanize.Bytes(m.HeapIdle),
		HeapInuse:    humanize.Bytes(m.HeapInuse),
		HeapReleased: humanize.Bytes(m.HeapReleased),
		HeapObjects:  m.HeapObjects,
		StackInuse:   humanize.Bytes(m.StackInuse),
		StackSys:     humanize.Bytes(m.StackSys),
		MSpanInuse:   humanize.Bytes(m.MSpanInuse),
		MSpanSys:     humanize.Bytes(m.MSpanSys),
		MCacheInuse:  humanize.Bytes(m.MCacheInuse),
		MCacheSys:    humanize.Bytes(m.MCacheSys),
		BuckHashSys:  humanize.Bytes(m.BuckHashSys),
		GCSys:        humanize.Bytes(m.GCSys),
		OtherSys:     humanize.Bytes(m.OtherSys),
		NextGC:       humanize.Bytes(m.NextGC),
		LastGC:       fmt.Sprintf("%.1fs", float64(time.Now().UnixNano()-int64(m.LastGC))/1000/1000/1000),
		PauseTotalNs: fmt.Sprintf("%.1fs", float64(m.PauseTotalNs)/1000/1000/1000),
		PauseNs:      fmt.Sprintf("%.3fs", float64(m.PauseNs[(m.NumGC+255)%256])/1000/1000/1000),
		NumGC:        m.NumGC,
	}

	// Marshal the structs into JSON
	output, err := json.MarshalIndent(stats, "", "  ")
	if err != nil {
		c.JSON(e.ErrorMessage(e.ErrInternalError))
		c.Error(err).SetMeta("StatusController.Marshal")
		return
	}

	c.Data(200, "application/json", output)

	return

}
<|endoftext|>


<commit_before>package protocols

import (
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/miekg/dns"
)

type DNSHeader struct {
	ID                 int           `json:"id"`
	Opcode             string        `json:"opcode"`
	Flags              []string      `json:"flags"`
	Rcode              string        `json:"rcode"`
	TotalQuestions     int           `json:"total_questions"`
	TotalAnswerRRS     int           `json:"total_answer_rrs"`
	TotalAuthorityRRS  int           `json:"total_authority_rrs"`
	TotalAdditionalRRS int           `json:"total_additional_rrs"`
	Questions          []interface{} `json:"questions"`
	AnswerRRS          []interface{} `json:"answer_rrs"`
	AuthorityRRS       []interface{} `json:"authority_rrs"`
	AdditionalRRS      []interface{} `json:"additional_rrs"`
}

type DNSQuestion struct {
	Name   string `json:"name"`
	Qtype  string `json:"type"`
	Qclass string `json:"class"`
}

type DNSRRHeader struct {
	Name     string      `json:"name"`
	Rrtype   string      `json:"type"`
	Class    string      `json:"class"`
	TTL      int         `json:"ttl"`
	Rdlength int         `json:"rdata_length"`
	Rdata    interface{} `json:"rdata"`
}

// DNSRRParser parses DNS Resource Records
func DNSRRParser(rr dns.RR) DNSRRHeader {
	rdata := make(map[string]interface{})

	switch rr := rr.(type) {
	case *dns.A:
		rdata["a"] = rr.A
	case *dns.AAAA:
		rdata["aaaa"] = rr.AAAA
	case *dns.AFSDB:
		rdata["subtype"] = rr.Subtype
		rdata["hostname"] = rr.Hostname
	case *dns.CAA:
		rdata["flag"] = rr.Flag
		rdata["tag"] = rr.Tag
		rdata["value"] = rr.Value
	case *dns.CDNSKEY:
		rdata["flags"] = rr.Flags
		rdata["protocol"] = rr.Protocol
		rdata["algorithm"] = rr.Algorithm
		rdata["public_key"] = rr.PublicKey
	case *dns.CDS:
		rdata["key_tag"] = rr.KeyTag
		rdata["algorithm"] = rr.Algorithm
		rdata["digest_type"] = rr.DigestType
		rdata["digest"] = rr.Digest
	case *dns.CERT:
		rdata["type"] = dns.CertTypeToString[rr.Type]
		rdata["keytag"] = rr.KeyTag
		rdata["algorithm"] = dns.AlgorithmToString[rr.Algorithm]
		rdata["certificate"] = rr.Certificate
	case *dns.CNAME:
		rdata["target"] = rr.Target
	case *dns.DHCID:
		rdata["digest"] = rr.Digest
	case *dns.DLV:
		rdata["key_tag"] = rr.KeyTag
		rdata["algorithm"] = rr.Algorithm
		rdata["digest_type"] = rr.DigestType
		rdata["digest"] = rr.Digest
	case *dns.DNAME:
		rdata["target"] = rr.Target
	case *dns.DNSKEY:
		rdata["flags"] = rr.Flags
		rdata["protocol"] = rr.Protocol
		rdata["algorithm"] = rr.Algorithm
		rdata["public_key"] = rr.PublicKey
	case *dns.DS:
		rdata["key_tag"] = rr.KeyTag
		rdata["algorithm"] = rr.Algorithm
		rdata["digest_type"] = rr.DigestType
		rdata["digest"] = rr.Digest
	case *dns.EID:
		rdata["endpoint"] = rr.Endpoint
	case *dns.EUI48:
		rdata["address"] = rr.Address
	case *dns.EUI64:
		rdata["address"] = rr.Address
	case *dns.GID:
		rdata["gid"] = rr.Gid
	case *dns.GPOS:
		rdata["longitude"] = rr.Longitude
		rdata["latitude"] = rr.Latitude
		rdata["altitude"] = rr.Altitude
	case *dns.HINFO:
		rdata["cpu"] = rr.Cpu
		rdata["os"] = rr.Os
	case *dns.HIP:
		rdata["hit_length"] = rr.HitLength
		rdata["public_key_algorithm"] = rr.PublicKeyAlgorithm
		rdata["public_key_length"] = rr.PublicKeyLength
		rdata["hit"] = rr.Hit
		rdata["public_key"] = rr.PublicKey
		rdata["rendezvous_servers"] = rr.RendezvousServers
	case *dns.IPSECKEY:
		rdata["precedence"] = rr.Precedence
		rdata["gateway_type"] = rr.GatewayType
		rdata["algorithm"] = rr.Algorithm
		rdata["gateway_a"] = rr.GatewayA
		rdata["gateway_aaaa"] = rr.GatewayAAAA
		rdata["gateway_name"] = rr.GatewayName
		rdata["public_key"] = rr.PublicKey
	case *dns.KEY:
		rdata["flags"] = rr.Flags
		rdata["protocol"] = rr.Protocol
		rdata["algorithm"] = rr.Algorithm
		rdata["public_key"] = rr.PublicKey
	case *dns.KX:
		rdata["preference"] = rr.Preference
		rdata["exchanger"] = rr.Exchanger
	case *dns.L32:
		rdata["preference"] = rr.Preference
		rdata["locator32"] = rr.Locator32
	case *dns.L64:
		rdata["preference"] = rr.Preference
		rdata["locator64"] = rr.Locator64
	case *dns.LOC:
		rdata["version"] = rr.Version
		rdata["size"] = rr.Size
		rdata["horiz_pre"] = rr.HorizPre
		rdata["vert_pre"] = rr.VertPre
		rdata["latitude"] = rr.Latitude
		rdata["longitude"] = rr.Longitude
		rdata["altitude"] = rr.Altitude
	case *dns.LP:
		rdata["preference"] = rr.Preference
		rdata["fqdn"] = rr.Fqdn
	case *dns.MB:
		rdata["mb"] = rr.Mb
	case *dns.MD:
		rdata["md"] = rr.Md
	case *dns.MF:
		rdata["mf"] = rr.Mf
	case *dns.MG:
		rdata["mg"] = rr.Mg
	case *dns.MINFO:
		rdata["rmail"] = rr.Rmail
		rdata["email"] = rr.Email
	case *dns.MR:
		rdata["mr"] = rr.Mr
	case *dns.MX:
		rdata["preference"] = rr.Preference
		rdata["mx"] = rr.Mx
	case *dns.NAPTR:
		rdata["order"] = rr.Order
		rdata["preference"] = rr.Preference
		rdata["flags"] = rr.Flags
		rdata["service"] = rr.Service
		rdata["regexp"] = rr.Regexp
		rdata["replacement"] = rr.Replacement
	case *dns.NID:
		rdata["preference"] = rr.Preference
		rdata["node_id"] = rr.NodeID
	case *dns.NIMLOC:
		rdata["locator"] = rr.Locator
	case *dns.NINFO:
		rdata["zs_data"] = rr.ZSData
	case *dns.NS:
		rdata["ns"] = rr.Ns
	case *dns.NSAPPTR:
		rdata["ptr"] = rr.Ptr
	case *dns.NSEC:
		rdata["next_domain"] = rr.NextDomain
		rdata["type_bitmap"] = rr.TypeBitMap
	case *dns.NSEC3:
		rdata["hash"] = rr.Hash
		rdata["flags"] = rr.Flags
		rdata["iterations"] = rr.Iterations
		rdata["salt_length"] = rr.SaltLength
		rdata["salt"] = rr.Salt
		rdata["hash_length"] = rr.HashLength
		rdata["next_domain"] = rr.NextDomain
		rdata["type_bitmap"] = rr.TypeBitMap
	case *dns.NSEC3PARAM:
		rdata["hash"] = rr.Hash
		rdata["flags"] = rr.Flags
		rdata["iterations"] = rr.Iterations
		rdata["salt_length"] = rr.SaltLength
		rdata["salt"] = rr.Salt
	case *dns.OPENPGPKEY:
		rdata["public_key"] = rr.PublicKey
	case *dns.PTR:
		rdata["ptr"] = rr.Ptr
	case *dns.PX:
		rdata["preference"] = rr.Preference
		rdata["map822"] = rr.Map822
		rdata["mapx400"] = rr.Mapx400
	case *dns.RKEY:
		rdata["flags"] = rr.Flags
		rdata["protocol"] = rr.Protocol
		rdata["algorithm"] = rr.Algorithm
		rdata["public_key"] = rr.PublicKey
	case *dns.RP:
		rdata["mbox"] = rr.Mbox
		rdata["txt"] = rr.Txt
	case *dns.RRSIG:
		rdata["type_covered"] = rr.TypeCovered
		rdata["algorithm"] = rr.Algorithm
		rdata["labels"] = rr.Labels
		rdata["orig_ttl"] = rr.OrigTtl
		rdata["expiration"] = rr.Expiration
		rdata["inception"] = rr.Inception
		rdata["key_tag"] = rr.KeyTag
		rdata["signer_name"] = rr.SignerName
		rdata["signature"] = rr.Signature
	case *dns.RT:
		rdata["preference"] = rr.Preference
		rdata["host"] = rr.Host
	case *dns.SIG:
		rdata["type_covered"] = rr.TypeCovered
		rdata["algorithm"] = rr.Algorithm
		rdata["labels"] = rr.Labels
		rdata["orig_ttl"] = rr.OrigTtl
		rdata["expiration"] = rr.Expiration
		rdata["inception"] = rr.Inception
		rdata["key_tag"] = rr.KeyTag
		rdata["signer_name"] = rr.SignerName
		rdata["signature"] = rr.Signature
	case *dns.SOA:
		rdata["ns"] = rr.Ns
		rdata["mbox"] = rr.Mbox
		rdata["serial"] = rr.Serial
		rdata["refresh"] = rr.Refresh
		rdata["retry"] = rr.Retry
		rdata["expire"] = rr.Expire
		rdata["mininum_ttl"] = rr.Minttl
	case *dns.SPF:
		rdata["txt"] = rr.Txt
	case *dns.SRV:
		rdata["priority"] = rr.Priority
		rdata["weight"] = rr.Weight
		rdata["port"] = rr.Port
		rdata["target"] = rr.Target
	case *dns.SSHFP:
		rdata["algorithm"] = rr.Algorithm
		rdata["type"] = rr.Type
		rdata["finger_print"] = rr.FingerPrint
	case *dns.TA:
		rdata["key_tag"] = rr.KeyTag
		rdata["algorithm"] = rr.Algorithm
		rdata["digest_type"] = rr.DigestType
		rdata["digest"] = rr.Digest
	case *dns.TALINK:
		rdata["previous_name"] = rr.PreviousName
		rdata["next_name"] = rr.NextName
	case *dns.TKEY:
		rdata["algorithm"] = rr.Algorithm
		rdata["inception"] = rr.Inception
		rdata["expiration"] = rr.Expiration
		rdata["mode"] = rr.Mode
		rdata["error"] = rr.Error
		rdata["key_size"] = rr.KeySize
		rdata["key"] = rr.Key
		rdata["other_len"] = rr.OtherLen
		rdata["other_data"] = rr.OtherData
	case *dns.TLSA:
		rdata["usage"] = rr.Usage
		rdata["selector"] = rr.Selector
		rdata["matching_type"] = rr.MatchingType
		rdata["certificate"] = rr.Certificate
	case *dns.TXT:
		rdata["txt"] = rr.Txt
	case *dns.UID:
		rdata["uid"] = rr.Uid
	case *dns.UINFO:
		rdata["uinfo"] = rr.Uinfo
	case *dns.URI:
		rdata["priority"] = rr.Priority
		rdata["weight"] = rr.Weight
		rdata["target"] = rr.Target
	case *dns.WKS:
		rdata["address"] = rr.Address
		rdata["protocol"] = rr.Protocol
		rdata["bitmap"] = rr.BitMap
	case *dns.X25:
		rdata["psdn_address"] = rr.PSDNAddress
	}

	header := DNSRRHeader{
		Name:     rr.Header().Name,
		Rrtype:   dns.TypeToString[rr.Header().Rrtype],
		Class:    dns.ClassToString[rr.Header().Class],
		TTL:      int(rr.Header().Ttl),
		Rdlength: int(rr.Header().Rdlength),
		Rdata:    rdata,
	}

	return header
}

// DNSParser parses a DNS header
func DNSParser(layer gopacket.Layer) DNSHeader {
	dnsFlags := make([]string, 0, 8)

	dnsLayer, _ := layer.(*layers.DNS)

	contents := dnsLayer.BaseLayer.LayerContents()

	dnsMsg := new(dns.Msg)
	dnsMsg.Unpack(contents)

	if !dnsMsg.MsgHdr.Response {
		dnsFlags = append(dnsFlags, "QR")
	}
	if dnsMsg.MsgHdr.Authoritative {
		dnsFlags = append(dnsFlags, "AA")
	}
	if dnsMsg.MsgHdr.Truncated {
		dnsFlags = append(dnsFlags, "TC")
	}
	if dnsMsg.MsgHdr.RecursionDesired {
		dnsFlags = append(dnsFlags, "RD")
	}
	if dnsMsg.MsgHdr.RecursionAvailable {
		dnsFlags = append(dnsFlags, "RA")
	}
	if dnsMsg.MsgHdr.Zero {
		dnsFlags = append(dnsFlags, "Z")
	}
	if dnsMsg.MsgHdr.AuthenticatedData {
		dnsFlags = append(dnsFlags, "AD")
	}
	if dnsMsg.MsgHdr.CheckingDisabled {
		dnsFlags = append(dnsFlags, "CD")
	}

	dnsTotalQuestions := len(dnsMsg.Question)
	dnsTotalAnswerRRS := len(dnsMsg.Answer)
	dnsTotalAuthorityRRS := len(dnsMsg.Ns)
	dnsTotalAdditionalRRS := len(dnsMsg.Extra)

	dnsQuestions := make([]interface{}, 0, dnsTotalQuestions)
	dnsAnswerRRS := make([]interface{}, 0, dnsTotalAnswerRRS)
	dnsAuthorityRRS := make([]interface{}, 0, dnsTotalAuthorityRRS)
	dnsAdditionalRRS := make([]interface{}, 0, dnsTotalAdditionalRRS)

	for _, question := range dnsMsg.Question {
		dnsQuestions = append(dnsQuestions, DNSQuestion{
			Name:   question.Name,
			Qtype:  dns.TypeToString[question.Qtype],
			Qclass: dns.ClassToString[question.Qclass],
		})
	}

	for _, answer := range dnsMsg.Answer {
		dnsAnswerRRS = append(dnsAnswerRRS, DNSRRParser(answer))
	}

	for _, authority := range dnsMsg.Ns {
		dnsAuthorityRRS = append(dnsAuthorityRRS, DNSRRParser(authority))
	}

	for _, additional := range dnsMsg.Extra {
		dnsAdditionalRRS = append(dnsAdditionalRRS, DNSRRParser(additional))
	}

	dnsHeader := DNSHeader{
		ID:                 int(dnsMsg.MsgHdr.Id),
		Opcode:             dns.OpcodeToString[dnsMsg.MsgHdr.Opcode],
		Flags:              dnsFlags,
		Rcode:              dns.RcodeToString[dnsMsg.MsgHdr.Rcode],
		TotalQuestions:     dnsTotalQuestions,
		TotalAnswerRRS:     dnsTotalAnswerRRS,
		TotalAuthorityRRS:  dnsTotalAuthorityRRS,
		TotalAdditionalRRS: dnsTotalAdditionalRRS,
		Questions:          dnsQuestions,
		AnswerRRS:          dnsAnswerRRS,
		AuthorityRRS:       dnsAuthorityRRS,
		AdditionalRRS:      dnsAdditionalRRS,
	}

	return dnsHeader
}
<commit_msg>Flatten rdata as a single string<commit_after>package protocols

import (
	"strconv"
	"strings"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/miekg/dns"
)

type DNSHeader struct {
	ID                 int           `json:"id"`
	Opcode             string        `json:"opcode"`
	Flags              []string      `json:"flags"`
	Rcode              string        `json:"rcode"`
	TotalQuestions     int           `json:"total_questions"`
	TotalAnswerRRS     int           `json:"total_answer_rrs"`
	TotalAuthorityRRS  int           `json:"total_authority_rrs"`
	TotalAdditionalRRS int           `json:"total_additional_rrs"`
	Questions          []interface{} `json:"questions"`
	AnswerRRS          []interface{} `json:"answer_rrs"`
	AuthorityRRS       []interface{} `json:"authority_rrs"`
	AdditionalRRS      []interface{} `json:"additional_rrs"`
}

type DNSQuestion struct {
	Name   string `json:"name"`
	Qtype  string `json:"type"`
	Qclass string `json:"class"`
}

type DNSRRHeader struct {
	Name     string `json:"name"`
	Rrtype   string `json:"type"`
	Class    string `json:"class"`
	TTL      int    `json:"ttl"`
	Rdlength int    `json:"rdata_length"`
	Rdata    string `json:"rdata"`
}

// DNSRRParser parses DNS Resource Records
func DNSRRParser(rr dns.RR) DNSRRHeader {
	rrHeader := strings.Split(rr.String(), "\t")
	name := strings.TrimPrefix(rrHeader[0], ";")
	rrType := rrHeader[3]
	class := rrHeader[2]
	rdLength := int(rr.Header().Rdlength)

	ttl, err := strconv.Atoi(rrHeader[1])
	if err != nil {
		//handle error
	}

	rdata := strings.Join(rrHeader[4:], " ")

	header := DNSRRHeader{
		Name:     name,
		Rrtype:   rrType,
		Class:    class,
		TTL:      ttl,
		Rdlength: rdLength,
		Rdata:    rdata,
	}

	return header
}

// DNSParser parses a DNS header
func DNSParser(layer gopacket.Layer) DNSHeader {
	dnsFlags := make([]string, 0, 8)

	dnsLayer, _ := layer.(*layers.DNS)

	contents := dnsLayer.BaseLayer.LayerContents()

	dnsMsg := new(dns.Msg)
	dnsMsg.Unpack(contents)

	if !dnsMsg.MsgHdr.Response {
		dnsFlags = append(dnsFlags, "QR")
	}
	if dnsMsg.MsgHdr.Authoritative {
		dnsFlags = append(dnsFlags, "AA")
	}
	if dnsMsg.MsgHdr.Truncated {
		dnsFlags = append(dnsFlags, "TC")
	}
	if dnsMsg.MsgHdr.RecursionDesired {
		dnsFlags = append(dnsFlags, "RD")
	}
	if dnsMsg.MsgHdr.RecursionAvailable {
		dnsFlags = append(dnsFlags, "RA")
	}
	if dnsMsg.MsgHdr.Zero {
		dnsFlags = append(dnsFlags, "Z")
	}
	if dnsMsg.MsgHdr.AuthenticatedData {
		dnsFlags = append(dnsFlags, "AD")
	}
	if dnsMsg.MsgHdr.CheckingDisabled {
		dnsFlags = append(dnsFlags, "CD")
	}

	dnsTotalQuestions := len(dnsMsg.Question)
	dnsTotalAnswerRRS := len(dnsMsg.Answer)
	dnsTotalAuthorityRRS := len(dnsMsg.Ns)
	dnsTotalAdditionalRRS := len(dnsMsg.Extra)

	dnsQuestions := make([]interface{}, 0, dnsTotalQuestions)
	dnsAnswerRRS := make([]interface{}, 0, dnsTotalAnswerRRS)
	dnsAuthorityRRS := make([]interface{}, 0, dnsTotalAuthorityRRS)
	dnsAdditionalRRS := make([]interface{}, 0, dnsTotalAdditionalRRS)

	for _, question := range dnsMsg.Question {
		dnsQuestions = append(dnsQuestions, DNSQuestion{
			Name:   question.Name,
			Qtype:  dns.TypeToString[question.Qtype],
			Qclass: dns.ClassToString[question.Qclass],
		})
	}

	for _, answer := range dnsMsg.Answer {
		dnsAnswerRRS = append(dnsAnswerRRS, DNSRRParser(answer))
	}

	for _, authority := range dnsMsg.Ns {
		dnsAuthorityRRS = append(dnsAuthorityRRS, DNSRRParser(authority))
	}

	for _, additional := range dnsMsg.Extra {
		dnsAdditionalRRS = append(dnsAdditionalRRS, DNSRRParser(additional))
	}

	dnsHeader := DNSHeader{
		ID:                 int(dnsMsg.MsgHdr.Id),
		Opcode:             dns.OpcodeToString[dnsMsg.MsgHdr.Opcode],
		Flags:              dnsFlags,
		Rcode:              dns.RcodeToString[dnsMsg.MsgHdr.Rcode],
		TotalQuestions:     dnsTotalQuestions,
		TotalAnswerRRS:     dnsTotalAnswerRRS,
		TotalAuthorityRRS:  dnsTotalAuthorityRRS,
		TotalAdditionalRRS: dnsTotalAdditionalRRS,
		Questions:          dnsQuestions,
		AnswerRRS:          dnsAnswerRRS,
		AuthorityRRS:       dnsAuthorityRRS,
		AdditionalRRS:      dnsAdditionalRRS,
	}

	return dnsHeader
}
<|endoftext|>


<commit_before>package layout

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/goccy/go-yaml"
	tele "gopkg.in/tucnak/telebot.v3"
)

type (
	Settings struct {
		URL     string
		Token   string
		Updates int

		LocalesDir string `json:"locales_dir"`
		TokenEnv   string `json:"token_env"`
		ParseMode  string `json:"parse_mode"`

		Webhook    *tele.Webhook    `json:"webhook"`
		LongPoller *tele.LongPoller `json:"long_poller"`
	}
)

func (lt *Layout) UnmarshalYAML(data []byte) error {
	var aux struct {
		Settings *Settings
		Config   map[string]interface{}
		Markups  yaml.MapSlice
		Locales  map[string]map[string]string
	}
	if err := yaml.Unmarshal(data, &aux); err != nil {
		return err
	}

	lt.Config = aux.Config

	if pref := aux.Settings; pref != nil {
		lt.pref = &tele.Settings{
			URL:       pref.URL,
			Token:     pref.Token,
			Updates:   pref.Updates,
			ParseMode: pref.ParseMode,
		}

		if pref.TokenEnv != "" {
			lt.pref.Token = os.Getenv(pref.TokenEnv)
		}

		if pref.Webhook != nil {
			lt.pref.Poller = pref.Webhook
		} else if pref.LongPoller != nil {
			lt.pref.Poller = pref.LongPoller
		}
	}

	lt.Markups = make(map[string]Markup, len(aux.Markups))
	for _, item := range aux.Markups {
		k, v := item.Key.(string), item.Value

		data, err := yaml.Marshal(v)
		if err != nil {
			return err
		}

		// 1. Normal markup.

		var markup struct {
			Markup `yaml:",inline"`
			Resize *bool `json:"resize_keyboard"`
		}
		if yaml.Unmarshal(data, &markup) == nil {
			data, err := yaml.Marshal(markup.ReplyKeyboard)
			if err != nil {
				return err
			}

			tmpl, err := template.New(k).Parse(string(data))
			if err != nil {
				return err
			}

			markup.Markup.Keyboard = tmpl
			markup.ResizeReplyKeyboard = markup.Resize == nil || *markup.Resize

			lt.Markups[k] = markup.Markup
		}

		// 2. Shortened reply markup.

		var embeddedMarkup [][]string
		if yaml.Unmarshal(data, &embeddedMarkup) == nil {
			kb := make([][]tele.ReplyButton, len(embeddedMarkup))
			for i, btns := range embeddedMarkup {
				row := make([]tele.ReplyButton, len(btns))
				for j, btn := range btns {
					row[j] = tele.ReplyButton{Text: btn}
				}
				kb[i] = row
			}

			data, err := yaml.Marshal(kb)
			if err != nil {
				return err
			}

			tmpl, err := template.New(k).Parse(string(data))
			if err != nil {
				return err
			}

			markup := Markup{Keyboard: tmpl}
			markup.ResizeReplyKeyboard = true
			lt.Markups[k] = markup
		}

		// 3. Shortened inline markup.

		if yaml.Unmarshal(data, &[][]tele.InlineButton{}) == nil {
			tmpl, err := template.New(k).Parse(string(data))
			if err != nil {
				return err
			}

			lt.Markups[k] = Markup{
				inline:   true,
				Keyboard: tmpl,
			}
		}
	}

	if aux.Locales == nil {
		if aux.Settings.LocalesDir == "" {
			aux.Settings.LocalesDir = "locales"
		}
		return lt.parseLocales(aux.Settings.LocalesDir)
	}

	return nil
}

func (lt *Layout) parseLocales(dir string) error {
	lt.Locales = make(map[string]*template.Template)

	return filepath.Walk(dir, func(path string, fi os.FileInfo, _ error) error {
		if fi == nil || fi.IsDir() {
			return nil
		}

		data, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}

		var texts map[string]string
		if err := yaml.Unmarshal(data, &texts); err != nil {
			return err
		}

		name := fi.Name()
		name = strings.TrimSuffix(name, filepath.Ext(name))

		tmpl := template.New(name)
		for _, text := range texts {
			t, err := tmpl.Parse(text)
			if err != nil {
				return err
			}
			tmpl = t
		}

		lt.Locales[name] = tmpl
		return nil
	})
}
<commit_msg>layout: fix templates parsing<commit_after>package layout

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/goccy/go-yaml"
	tele "gopkg.in/tucnak/telebot.v3"
)

type (
	Settings struct {
		URL     string
		Token   string
		Updates int

		LocalesDir string `json:"locales_dir"`
		TokenEnv   string `json:"token_env"`
		ParseMode  string `json:"parse_mode"`

		Webhook    *tele.Webhook    `json:"webhook"`
		LongPoller *tele.LongPoller `json:"long_poller"`
	}
)

func (lt *Layout) UnmarshalYAML(data []byte) error {
	var aux struct {
		Settings *Settings
		Config   map[string]interface{}
		Markups  yaml.MapSlice
		Locales  map[string]map[string]string
	}
	if err := yaml.Unmarshal(data, &aux); err != nil {
		return err
	}

	lt.Config = aux.Config

	if pref := aux.Settings; pref != nil {
		lt.pref = &tele.Settings{
			URL:       pref.URL,
			Token:     pref.Token,
			Updates:   pref.Updates,
			ParseMode: pref.ParseMode,
		}

		if pref.TokenEnv != "" {
			lt.pref.Token = os.Getenv(pref.TokenEnv)
		}

		if pref.Webhook != nil {
			lt.pref.Poller = pref.Webhook
		} else if pref.LongPoller != nil {
			lt.pref.Poller = pref.LongPoller
		}
	}

	lt.Markups = make(map[string]Markup, len(aux.Markups))
	for _, item := range aux.Markups {
		k, v := item.Key.(string), item.Value

		data, err := yaml.Marshal(v)
		if err != nil {
			return err
		}

		// 1. Normal markup.

		var markup struct {
			Markup `yaml:",inline"`
			Resize *bool `json:"resize_keyboard"`
		}
		if yaml.Unmarshal(data, &markup) == nil {
			data, err := yaml.Marshal(markup.ReplyKeyboard)
			if err != nil {
				return err
			}

			tmpl, err := template.New(k).Parse(string(data))
			if err != nil {
				return err
			}

			markup.Markup.Keyboard = tmpl
			markup.ResizeReplyKeyboard = markup.Resize == nil || *markup.Resize

			lt.Markups[k] = markup.Markup
		}

		// 2. Shortened reply markup.

		var embeddedMarkup [][]string
		if yaml.Unmarshal(data, &embeddedMarkup) == nil {
			kb := make([][]tele.ReplyButton, len(embeddedMarkup))
			for i, btns := range embeddedMarkup {
				row := make([]tele.ReplyButton, len(btns))
				for j, btn := range btns {
					row[j] = tele.ReplyButton{Text: btn}
				}
				kb[i] = row
			}

			data, err := yaml.Marshal(kb)
			if err != nil {
				return err
			}

			tmpl, err := template.New(k).Parse(string(data))
			if err != nil {
				return err
			}

			markup := Markup{Keyboard: tmpl}
			markup.ResizeReplyKeyboard = true
			lt.Markups[k] = markup
		}

		// 3. Shortened inline markup.

		if yaml.Unmarshal(data, &[][]tele.InlineButton{}) == nil {
			tmpl, err := template.New(k).Parse(string(data))
			if err != nil {
				return err
			}

			lt.Markups[k] = Markup{
				inline:   true,
				Keyboard: tmpl,
			}
		}
	}

	if aux.Locales == nil {
		if aux.Settings.LocalesDir == "" {
			aux.Settings.LocalesDir = "locales"
		}
		return lt.parseLocales(aux.Settings.LocalesDir)
	}

	return nil
}

func (lt *Layout) parseLocales(dir string) error {
	lt.Locales = make(map[string]*template.Template)

	return filepath.Walk(dir, func(path string, fi os.FileInfo, _ error) error {
		if fi == nil || fi.IsDir() {
			return nil
		}

		data, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}

		var texts map[string]string
		if err := yaml.Unmarshal(data, &texts); err != nil {
			return err
		}

		name := fi.Name()
		name = strings.TrimSuffix(name, filepath.Ext(name))

		tmpl := template.New(name)
		for key, text := range texts {
			text = strings.Trim(text, "\r\n")
			tmpl, err = tmpl.New(key).Parse(text)
			if err != nil {
				return err
			}
		}

		lt.Locales[name] = tmpl
		return nil
	})
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/PuerkitoBio/goquery"
	"log"
	"net/http"
	"regexp"
	"net/smtp"
	"io/ioutil"
	"strconv"
	"strings"
)

type ParsedResponse struct {
	Success bool     `json:"success"`
	Links   []string `json:"links"`
}

type EmailUser struct {
	Username	string
	Password	string
	EmailServer	string
	Port		int
}

var emailUser EmailUser

func connectToSmtpServer(emailUser *EmailUser) {
	smtpConf, err := ioutil.ReadFile("../conf/smtp.json")
	if err != nil {
		log.Print("error reading smtp config file ", err)
	}
	err = json.Unmarshal(smtpConf, emailUser)
	if err != nil {
		log.Print("error unmarshalling config ", err)
	}
	auth := smtp.PlainAuth("", emailUser.Username, emailUser.Password, emailUser.EmailServer)
	log.Print("first arg for SendMail is ", emailUser.EmailServer + ":" + strconv.Itoa(emailUser.Port))
	log.Print(emailUser)
	msg := `From: Check For Broken Links
To: Nathan LeClaire
Subject: This Is A Test

	Please do not panic, it is only a test.
	`
	err = smtp.SendMail(emailUser.EmailServer + ":" + strconv.Itoa(emailUser.Port),
						 auth,
						 emailUser.Username,
						 []string{"nathanleclaire@gmail.com"},
					     []byte(msg))
	if err != nil {
		log.Print("ERROR: attempting to send a mail ", err)
	}
}

func getFailedSlurpResponse() []byte {
	failResponse := &ParsedResponse{false, nil}
	failResponseJSON, err := json.Marshal(failResponse)
	if err != nil {
		log.Print("something went really weird in attempt to marshal a fail json ", err)
		failResponseJSON, _ = json.Marshal(nil)
	}
	return failResponseJSON
}

func slurpHandler(w http.ResponseWriter, r *http.Request) {
	url_to_scrape := strings.ToLower( r.URL.Query().Get("url_to_scrape") )

	var doc *goquery.Document
	var e error
	var parsedResponseJSON []byte

	links := []string{}

	if doc, e = goquery.NewDocument(url_to_scrape); e != nil {
		log.Print("error querying for document: ", url_to_scrape, "err : ", e)
		parsedResponseJSON = getFailedSlurpResponse()
	} else {
		crossDomainRegex, err := regexp.Compile(`^http`)
		if err != nil {
			log.Printf("issue compiling regular expression to validate cross domain URLs")
		}

		doc.Find("a").Each(func(i int, s *goquery.Selection) {
			href, exists := s.Attr("href")
			if exists != true {
				log.Print("href does not exist for: ", s)
			} else {
				// TODO:  Implement handling of same domain links
				if crossDomainRegex.Match([]byte(href)) {
					links = append(links, href)
				}
			}
		})

		parsedResponse := &ParsedResponse{true, links}
		parsedResponseJSON, err = json.Marshal(parsedResponse)

		if err != nil {
			parsedResponseJSON = getFailedSlurpResponse()
		}

	}

	w.Write(parsedResponseJSON)

}

func checkHandler(w http.ResponseWriter, r *http.Request) {
	url_to_check := r.URL.Query().Get("url_to_check")
	externalServerResponse, err := http.Get(url_to_check)
	if err != nil {
		log.Print("error getting in checkHandler ", url_to_check)
	}

	response := map[string]interface{}{
		"status":     externalServerResponse.Status,
		"statusCode": externalServerResponse.StatusCode,
	}

	responseJSON, err := json.Marshal(response)
	if err != nil {
		log.Print("error Marshalling check response json: ", err)
	}
	w.Write(responseJSON)
}

func emailHandler(w http.ResponseWriter, r *http.Request) {
	// decode Gmail settings from encrypted config file
	// connect to Gmail STMP server
}

func main() {
	connectToSmtpServer(&emailUser)
	http.HandleFunc("/slurp", slurpHandler)
	http.HandleFunc("/check", checkHandler)
	http.HandleFunc("/email", emailHandler)
	http.Handle("/", http.FileServer(http.Dir("..")))
	http.Handle("/css/", http.FileServer(http.Dir("..")))
	http.Handle("/img/", http.FileServer(http.Dir("..")))
	http.Handle("/lib/", http.FileServer(http.Dir("..")))
	http.Handle("/partials/", http.FileServer(http.Dir("..")))
	http.Handle("/js/", http.FileServer(http.Dir("..")))
	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>create send email function<commit_after>package main

import (
	"encoding/json"
	"github.com/PuerkitoBio/goquery"
	"log"
	"net/http"
	"regexp"
	"net/smtp"
	"io/ioutil"
	"strconv"
	"strings"
	"text/template"
	"bytes"
)

type ParsedResponse struct {
	Success bool     `json:"success"`
	Links   []string `json:"links"`
}

type EmailUser struct {
	Username	string
	Password	string
	EmailServer	string
	Port		int
}

type SmtpTemplateData struct {
	From string
	To string
	Subject string
	Body string
}

var emailUser EmailUser
var auth smtp.Auth

func sendMail(from string, to string, subject string, body string) error {
	const emailTemplate = `From: {{.From}}
To: {{.To}}
Subject: {{.Subject}}

{{.Body}}`
	var err error
	var doc bytes.Buffer
	log.Print("emailUser ", emailUser)
	context := &SmtpTemplateData{from, to, subject, body}
	log.Print(context)
	t := template.New("emailTemplate")
	t, err = t.Parse(emailTemplate)
	if err != nil {
		log.Print("error trying to parse mail template ", err)
	}
	err = t.Execute(&doc, context)
	if err != nil {
		log.Print("error trying to execute mail template ", err)
	}
	log.Print(doc.String())
	err = smtp.SendMail(emailUser.EmailServer + ":" + strconv.Itoa(emailUser.Port),
						 auth,
						 emailUser.Username,
						 []string{"nathanleclaire@gmail.com"},
					     doc.Bytes())
	if err != nil {
		log.Print("ERROR: attempting to send a mail ", err)
	}

	return nil
}

func connectToSmtpServer(emailUser *EmailUser) {
	smtpConf, err := ioutil.ReadFile("../conf/smtp.json")
	if err != nil {
		log.Print("error reading smtp config file ", err)
	}
	err = json.Unmarshal(smtpConf, emailUser)
	if err != nil {
		log.Print("error unmarshalling config ", err)
	}
	auth = smtp.PlainAuth("", emailUser.Username, emailUser.Password, emailUser.EmailServer)
}

func getFailedSlurpResponse() []byte {
	failResponse := &ParsedResponse{false, nil}
	failResponseJSON, err := json.Marshal(failResponse)
	if err != nil {
		log.Print("something went really weird in attempt to marshal a fail json ", err)
		failResponseJSON, _ = json.Marshal(nil)
	}
	return failResponseJSON
}

func slurpHandler(w http.ResponseWriter, r *http.Request) {
	url_to_scrape := strings.ToLower( r.URL.Query().Get("url_to_scrape") )

	var doc *goquery.Document
	var e error
	var parsedResponseJSON []byte

	links := []string{}

	if doc, e = goquery.NewDocument(url_to_scrape); e != nil {
		log.Print("error querying for document: ", url_to_scrape, "err : ", e)
		parsedResponseJSON = getFailedSlurpResponse()
	} else {
		crossDomainRegex, err := regexp.Compile(`^http`)
		if err != nil {
			log.Printf("issue compiling regular expression to validate cross domain URLs")
		}

		doc.Find("a").Each(func(i int, s *goquery.Selection) {
			href, exists := s.Attr("href")
			if exists != true {
				log.Print("href does not exist for: ", s)
			} else {
				// TODO:  Implement handling of same domain links
				if crossDomainRegex.Match([]byte(href)) {
					links = append(links, href)
				}
			}
		})

		parsedResponse := &ParsedResponse{true, links}
		parsedResponseJSON, err = json.Marshal(parsedResponse)

		if err != nil {
			parsedResponseJSON = getFailedSlurpResponse()
		}

	}

	w.Write(parsedResponseJSON)

}

func checkHandler(w http.ResponseWriter, r *http.Request) {
	url_to_check := r.URL.Query().Get("url_to_check")
	externalServerResponse, err := http.Get(url_to_check)
	if err != nil {
		log.Print("error getting in checkHandler ", url_to_check)
	}

	response := map[string]interface{}{
		"status":     externalServerResponse.Status,
		"statusCode": externalServerResponse.StatusCode,
	}

	responseJSON, err := json.Marshal(response)
	if err != nil {
		log.Print("error Marshalling check response json: ", err)
	}
	w.Write(responseJSON)
}

func emailHandler(w http.ResponseWriter, r *http.Request) {
	// decode Gmail settings from encrypted config file
	// connect to Gmail STMP server

}

func main() {
	connectToSmtpServer(&emailUser)
	err := sendMail("CheckForBrokenLinks", "Nathan LeClaire", "Don't Panic!!", "This is only a test.")
	if err != nil {
		log.Print("issue calling sendMail in main function . . . ", err)
	}
	http.HandleFunc("/slurp", slurpHandler)
	http.HandleFunc("/check", checkHandler)
	http.HandleFunc("/email", emailHandler)
	http.Handle("/", http.FileServer(http.Dir("..")))
	http.Handle("/css/", http.FileServer(http.Dir("..")))
	http.Handle("/img/", http.FileServer(http.Dir("..")))
	http.Handle("/lib/", http.FileServer(http.Dir("..")))
	http.Handle("/partials/", http.FileServer(http.Dir("..")))
	http.Handle("/js/", http.FileServer(http.Dir("..")))
	err = http.ListenAndServe(":8000", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package repo

import (
	"time"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/context"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/setting"
	api "code.gitea.io/gitea/modules/structs"
)

// GetSingleCommit get a commit via
func GetSingleCommit(ctx *context.APIContext) {
	// swagger:operation GET /repos/{owner}/{repo}/git/commits/{sha} repository repoGetSingleCommit
	// ---
	// summary: Get a single commit from a repository
	// produces:
	// - application/json
	// parameters:
	// - name: owner
	//   in: path
	//   description: owner of the repo
	//   type: string
	//   required: true
	// - name: repo
	//   in: path
	//   description: name of the repo
	//   type: string
	//   required: true
	// - name: sha
	//   in: path
	//   description: the commit hash
	//   type: string
	//   required: true
	// responses:
	//   "200":
	//     "$ref": "#/responses/Commit"
	//   "404":
	//     "$ref": "#/responses/notFound"

	gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
	if err != nil {
		ctx.ServerError("OpenRepository", err)
		return
	}
	commit, err := gitRepo.GetCommit(ctx.Params(":sha"))
	if err != nil {
		ctx.NotFoundOrServerError("GetCommit", git.IsErrNotExist, err)
		return
	}

	// Retrieve author and committer information
	var apiAuthor, apiCommitter *api.User
	author, err := models.GetUserByEmail(commit.Author.Email)
	if err != nil && !models.IsErrUserNotExist(err) {
		ctx.ServerError("Get user by author email", err)
		return
	} else if err == nil {
		apiAuthor = author.APIFormat()
	}
	// Save one query if the author is also the committer
	if commit.Committer.Email == commit.Author.Email {
		apiCommitter = apiAuthor
	} else {
		committer, err := models.GetUserByEmail(commit.Committer.Email)
		if err != nil && !models.IsErrUserNotExist(err) {
			ctx.ServerError("Get user by committer email", err)
			return
		} else if err == nil {
			apiCommitter = committer.APIFormat()
		}
	}

	// Retrieve parent(s) of the commit
	apiParents := make([]*api.CommitMeta, commit.ParentCount())
	for i := 0; i < commit.ParentCount(); i++ {
		sha, _ := commit.ParentID(i)
		apiParents[i] = &api.CommitMeta{
			URL: ctx.Repo.Repository.APIURL() + "/git/commits/" + sha.String(),
			SHA: sha.String(),
		}
	}

	ctx.JSON(200, &api.Commit{
		CommitMeta: &api.CommitMeta{
			URL: setting.AppURL + ctx.Link[1:],
			SHA: commit.ID.String(),
		},
		HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commits/" + commit.ID.String(),
		RepoCommit: &api.RepoCommit{
			URL: setting.AppURL + ctx.Link[1:],
			Author: &api.CommitUser{
				Identity: api.Identity{
					Name:  commit.Author.Name,
					Email: commit.Author.Email,
				},
				Date: commit.Author.When.Format(time.RFC3339),
			},
			Committer: &api.CommitUser{
				Identity: api.Identity{
					Name:  commit.Committer.Name,
					Email: commit.Committer.Email,
				},
				Date: commit.Committer.When.Format(time.RFC3339),
			},
			Message: commit.Message(),
			Tree: &api.CommitMeta{
				URL: ctx.Repo.Repository.APIURL() + "/trees/" + commit.ID.String(),
				SHA: commit.ID.String(),
			},
		},
		Author:    apiAuthor,
		Committer: apiCommitter,
		Parents:   apiParents,
	})
}
<commit_msg>Fixes #7564 - Malformed URLs in API git/commits response (#7565)<commit_after>// Copyright 2018 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package repo

import (
	"time"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/context"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/setting"
	api "code.gitea.io/gitea/modules/structs"
)

// GetSingleCommit get a commit via
func GetSingleCommit(ctx *context.APIContext) {
	// swagger:operation GET /repos/{owner}/{repo}/git/commits/{sha} repository repoGetSingleCommit
	// ---
	// summary: Get a single commit from a repository
	// produces:
	// - application/json
	// parameters:
	// - name: owner
	//   in: path
	//   description: owner of the repo
	//   type: string
	//   required: true
	// - name: repo
	//   in: path
	//   description: name of the repo
	//   type: string
	//   required: true
	// - name: sha
	//   in: path
	//   description: the commit hash
	//   type: string
	//   required: true
	// responses:
	//   "200":
	//     "$ref": "#/responses/Commit"
	//   "404":
	//     "$ref": "#/responses/notFound"

	gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
	if err != nil {
		ctx.ServerError("OpenRepository", err)
		return
	}
	commit, err := gitRepo.GetCommit(ctx.Params(":sha"))
	if err != nil {
		ctx.NotFoundOrServerError("GetCommit", git.IsErrNotExist, err)
		return
	}

	// Retrieve author and committer information
	var apiAuthor, apiCommitter *api.User
	author, err := models.GetUserByEmail(commit.Author.Email)
	if err != nil && !models.IsErrUserNotExist(err) {
		ctx.ServerError("Get user by author email", err)
		return
	} else if err == nil {
		apiAuthor = author.APIFormat()
	}
	// Save one query if the author is also the committer
	if commit.Committer.Email == commit.Author.Email {
		apiCommitter = apiAuthor
	} else {
		committer, err := models.GetUserByEmail(commit.Committer.Email)
		if err != nil && !models.IsErrUserNotExist(err) {
			ctx.ServerError("Get user by committer email", err)
			return
		} else if err == nil {
			apiCommitter = committer.APIFormat()
		}
	}

	// Retrieve parent(s) of the commit
	apiParents := make([]*api.CommitMeta, commit.ParentCount())
	for i := 0; i < commit.ParentCount(); i++ {
		sha, _ := commit.ParentID(i)
		apiParents[i] = &api.CommitMeta{
			URL: ctx.Repo.Repository.APIURL() + "/git/commits/" + sha.String(),
			SHA: sha.String(),
		}
	}

	ctx.JSON(200, &api.Commit{
		CommitMeta: &api.CommitMeta{
			URL: setting.AppURL + ctx.Link[1:],
			SHA: commit.ID.String(),
		},
		HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
		RepoCommit: &api.RepoCommit{
			URL: setting.AppURL + ctx.Link[1:],
			Author: &api.CommitUser{
				Identity: api.Identity{
					Name:  commit.Author.Name,
					Email: commit.Author.Email,
				},
				Date: commit.Author.When.Format(time.RFC3339),
			},
			Committer: &api.CommitUser{
				Identity: api.Identity{
					Name:  commit.Committer.Name,
					Email: commit.Committer.Email,
				},
				Date: commit.Committer.When.Format(time.RFC3339),
			},
			Message: commit.Message(),
			Tree: &api.CommitMeta{
				URL: ctx.Repo.Repository.APIURL() + "/git/trees/" + commit.ID.String(),
				SHA: commit.ID.String(),
			},
		},
		Author:    apiAuthor,
		Committer: apiCommitter,
		Parents:   apiParents,
	})
}
<|endoftext|>


<commit_before>package fetcher

import "os"

// FileReseter implements WriteReseter for an *os.File instance
type FileReseter struct {
	*os.File
}

// Reset will truncate the file and seek to the beginning.
func (f *FileReseter) Reset() error {
	err := f.Truncate(0)
	if err != nil {
		return err
	}
	_, err = f.Seek(0, 0)
	return err
}
<commit_msg>Define interface wrapping io.File for FileReseter<commit_after>package fetcher

import "io"

// File interface as implemented by *os.File
type File interface {
	Truncate(size int64) error
	io.Seeker
	io.Writer
}

// FileReseter implements WriteReseter for an *os.File instance
type FileReseter struct {
	File
}

// Reset will truncate the file and seek to the beginning.
func (f *FileReseter) Reset() error {
	err := f.Truncate(0)
	if err != nil {
		return err
	}
	_, err = f.Seek(0, 0)
	return err
}
<|endoftext|>


<commit_before>package triangle

/*
#include "triangle.h"
#include <stdlib.h>
*/
import "C"
import "unsafe"

type triangulateIO struct {
	ct *C.struct_triangulateio
}

func NewTriangulateIO() *triangulateIO {
	t := triangulateIO{}
	t.ct = (*C.struct_triangulateio)(C.malloc(C.sizeof_struct_triangulateio))
	if t.ct == nil {
		panic("Unable to allocate memory")
	}
	t.ct.edgelist = nil
	t.ct.edgemarkerlist = nil
	t.ct.holelist = nil
	t.ct.neighborlist = nil
	t.ct.normlist = nil
	t.ct.numberofcorners = 0
	t.ct.numberofedges = 0
	t.ct.numberofholes = 0
	t.ct.numberofpointattributes = 0
	t.ct.numberofpoints = 0
	t.ct.numberofregions = 0
	t.ct.numberofsegments = 0
	t.ct.numberoftriangleattributes = 0
	t.ct.numberoftriangles = 0
	t.ct.pointattributelist = nil
	t.ct.pointlist = nil
	t.ct.pointmarkerlist = nil
	t.ct.regionlist = nil
	t.ct.segmentlist = nil
	t.ct.segmentmarkerlist = nil
	t.ct.trianglearealist = nil
	t.ct.triangleattributelist = nil
	t.ct.trianglelist = nil
	return &t
}

func FreeTriangulateIO(t *triangulateIO) {
	C.free(unsafe.Pointer(t.ct))
}

func (t *triangulateIO) NumberOfEdges() int {
	return int(t.ct.numberofedges)
}

func (t *triangulateIO) NumberOfHoles() int {
	return int(t.ct.numberofholes)
}

func (t *triangulateIO) NumberOfPoints() int {
	return int(t.ct.numberofpoints)
}

func (t *triangulateIO) NumberOfSegments() int {
	return int(t.ct.numberofsegments)
}

func (t *triangulateIO) NumberOfTriangles() int {
	return int(t.ct.numberoftriangles)
}

func (t *triangulateIO) Normals() [][2]float64 {
	return cArrToFlt64Slice2D(unsafe.Pointer(t.ct.normlist), t.NumberOfEdges())
}

func (t *triangulateIO) Edges() [][2]int32 {
	return cArrToIntSlice2D(unsafe.Pointer(t.ct.edgelist), t.NumberOfEdges())
}

func (t *triangulateIO) Points() [][2]float64 {
	return cArrToFlt64Slice2D(unsafe.Pointer(t.ct.pointlist), t.NumberOfPoints())
}

func (t *triangulateIO) PointMarkers() []int32 {
	return cArrToIntSlice(unsafe.Pointer(t.ct.pointmarkerlist), t.NumberOfPoints())
}

func (t *triangulateIO) Segments() [][2]int32 {
	return cArrToIntSlice2D(unsafe.Pointer(t.ct.segmentlist), t.NumberOfSegments())
}

func (t *triangulateIO) SetEdges(edges [][2]int32) {
	t.ct.edgelist = (*C.int)(unsafe.Pointer(&edges[0][0]))
	t.ct.numberofedges = C.int(len(edges))
}

func (t *triangulateIO) SetPoints(pts [][2]float64) {
	t.ct.pointlist = (*C.double)(unsafe.Pointer(&pts[0]))
	t.ct.numberofpoints = C.int(len(pts))
}

func (t *triangulateIO) SetPointMarkers(markers []int32) {
	t.ct.pointmarkerlist = (*C.int)(unsafe.Pointer(&markers[0]))
}

func (t *triangulateIO) SetSegments(segments [][2]int32) {
	t.ct.segmentlist = (*C.int)(unsafe.Pointer(&segments[0][0]))
	t.ct.numberofsegments = C.int(len(segments))
}

func (t *triangulateIO) SetSegmentMarkers(markers []int32) {
	t.ct.segmentmarkerlist = (*C.int)(unsafe.Pointer(&markers[0]))
}

func (t *triangulateIO) SetTriangles(tri [][3]int32) {
	t.ct.trianglelist = (*C.int)(unsafe.Pointer(&tri[0][0]))
}

func (t *triangulateIO) SetTriangleAreas(areas []float64) {
	t.ct.trianglearealist = (*C.double)(unsafe.Pointer(&areas[0]))
}

func (t *triangulateIO) SetHoles(holes [][2]float64) {
	t.ct.holelist = (*C.double)(unsafe.Pointer(&holes[0][0]))
	t.ct.numberofholes = C.int(len(holes))
}

func (t *triangulateIO) Triangles() [][3]int32 {
	return cArrToIntSlice3D(unsafe.Pointer(t.ct.trianglelist), t.NumberOfTriangles())
}

func triang(opt string, in, out, vorout *triangulateIO) {
	copt := C.CString(opt)
	defer C.free(unsafe.Pointer(copt))
	if vorout == nil {
		C.triangulate(copt, in.ct, out.ct, nil)
	} else {
		C.triangulate(copt, in.ct, out.ct, vorout.ct)
	}
}

func cArrToIntSlice(ptr unsafe.Pointer, length int) []int32 {
	slice := (*[1 << 30]C.int)(ptr)[:length:length]
	result := make([]int32, length)
	for i := 0; i < length; i++ {
		result[i] = int32(slice[i])
	}
	return result
}

func cArrToIntSlice2D(ptr unsafe.Pointer, length int) [][2]int32 {
	sz := length * 2
	slice := (*[1 << 30]C.int)(ptr)[:sz:sz]
	result := make([][2]int32, length)
	for i := 0; i < length; i++ {
		j := i * 2
		result[i] = [2]int32{int32(slice[j]), int32(slice[j+1])}
	}
	return result
}

func cArrToIntSlice3D(ptr unsafe.Pointer, length int) [][3]int32 {
	sz := length * 3
	slice := (*[1 << 30]C.int)(ptr)[:sz:sz]
	result := make([][3]int32, length)
	for i := 0; i < length; i++ {
		j := i * 3
		result[i] = [3]int32{int32(slice[j]), int32(slice[j+1]), int32(slice[j+2])}
	}
	return result
}

func cArrToFlt64Slice(ptr unsafe.Pointer, length int) []float64 {
	slice := (*[1 << 30]C.double)(ptr)[:length:length]
	result := make([]float64, length)
	for i := 0; i < length; i++ {
		result[i] = float64(slice[i])
	}
	return result
}

func cArrToFlt64Slice2D(ptr unsafe.Pointer, length int) [][2]float64 {
	sz := length * 2
	slice := (*[1 << 30]C.double)(ptr)[:sz:sz]
	result := make([][2]float64, length)
	for i := 0; i < length; i++ {
		j := i * 2
		result[i] = [2]float64{float64(slice[j]), float64(slice[j+1])}
	}
	return result
}
<commit_msg>fix for underfined references<commit_after>package triangle

/*
#include "triangle.h"
#include <stdlib.h>
*/
// #cgo LDFLAGS: -lm
import "C"
import "unsafe"

type triangulateIO struct {
	ct *C.struct_triangulateio
}

func NewTriangulateIO() *triangulateIO {
	t := triangulateIO{}
	t.ct = (*C.struct_triangulateio)(C.malloc(C.sizeof_struct_triangulateio))
	if t.ct == nil {
		panic("Unable to allocate memory")
	}
	t.ct.edgelist = nil
	t.ct.edgemarkerlist = nil
	t.ct.holelist = nil
	t.ct.neighborlist = nil
	t.ct.normlist = nil
	t.ct.numberofcorners = 0
	t.ct.numberofedges = 0
	t.ct.numberofholes = 0
	t.ct.numberofpointattributes = 0
	t.ct.numberofpoints = 0
	t.ct.numberofregions = 0
	t.ct.numberofsegments = 0
	t.ct.numberoftriangleattributes = 0
	t.ct.numberoftriangles = 0
	t.ct.pointattributelist = nil
	t.ct.pointlist = nil
	t.ct.pointmarkerlist = nil
	t.ct.regionlist = nil
	t.ct.segmentlist = nil
	t.ct.segmentmarkerlist = nil
	t.ct.trianglearealist = nil
	t.ct.triangleattributelist = nil
	t.ct.trianglelist = nil
	return &t
}

func FreeTriangulateIO(t *triangulateIO) {
	C.free(unsafe.Pointer(t.ct))
}

func (t *triangulateIO) NumberOfEdges() int {
	return int(t.ct.numberofedges)
}

func (t *triangulateIO) NumberOfHoles() int {
	return int(t.ct.numberofholes)
}

func (t *triangulateIO) NumberOfPoints() int {
	return int(t.ct.numberofpoints)
}

func (t *triangulateIO) NumberOfSegments() int {
	return int(t.ct.numberofsegments)
}

func (t *triangulateIO) NumberOfTriangles() int {
	return int(t.ct.numberoftriangles)
}

func (t *triangulateIO) Normals() [][2]float64 {
	return cArrToFlt64Slice2D(unsafe.Pointer(t.ct.normlist), t.NumberOfEdges())
}

func (t *triangulateIO) Edges() [][2]int32 {
	return cArrToIntSlice2D(unsafe.Pointer(t.ct.edgelist), t.NumberOfEdges())
}

func (t *triangulateIO) Points() [][2]float64 {
	return cArrToFlt64Slice2D(unsafe.Pointer(t.ct.pointlist), t.NumberOfPoints())
}

func (t *triangulateIO) PointMarkers() []int32 {
	return cArrToIntSlice(unsafe.Pointer(t.ct.pointmarkerlist), t.NumberOfPoints())
}

func (t *triangulateIO) Segments() [][2]int32 {
	return cArrToIntSlice2D(unsafe.Pointer(t.ct.segmentlist), t.NumberOfSegments())
}

func (t *triangulateIO) SetEdges(edges [][2]int32) {
	t.ct.edgelist = (*C.int)(unsafe.Pointer(&edges[0][0]))
	t.ct.numberofedges = C.int(len(edges))
}

func (t *triangulateIO) SetPoints(pts [][2]float64) {
	t.ct.pointlist = (*C.double)(unsafe.Pointer(&pts[0]))
	t.ct.numberofpoints = C.int(len(pts))
}

func (t *triangulateIO) SetPointMarkers(markers []int32) {
	t.ct.pointmarkerlist = (*C.int)(unsafe.Pointer(&markers[0]))
}

func (t *triangulateIO) SetSegments(segments [][2]int32) {
	t.ct.segmentlist = (*C.int)(unsafe.Pointer(&segments[0][0]))
	t.ct.numberofsegments = C.int(len(segments))
}

func (t *triangulateIO) SetSegmentMarkers(markers []int32) {
	t.ct.segmentmarkerlist = (*C.int)(unsafe.Pointer(&markers[0]))
}

func (t *triangulateIO) SetTriangles(tri [][3]int32) {
	t.ct.trianglelist = (*C.int)(unsafe.Pointer(&tri[0][0]))
}

func (t *triangulateIO) SetTriangleAreas(areas []float64) {
	t.ct.trianglearealist = (*C.double)(unsafe.Pointer(&areas[0]))
}

func (t *triangulateIO) SetHoles(holes [][2]float64) {
	t.ct.holelist = (*C.double)(unsafe.Pointer(&holes[0][0]))
	t.ct.numberofholes = C.int(len(holes))
}

func (t *triangulateIO) Triangles() [][3]int32 {
	return cArrToIntSlice3D(unsafe.Pointer(t.ct.trianglelist), t.NumberOfTriangles())
}

func triang(opt string, in, out, vorout *triangulateIO) {
	copt := C.CString(opt)
	defer C.free(unsafe.Pointer(copt))
	if vorout == nil {
		C.triangulate(copt, in.ct, out.ct, nil)
	} else {
		C.triangulate(copt, in.ct, out.ct, vorout.ct)
	}
}

func cArrToIntSlice(ptr unsafe.Pointer, length int) []int32 {
	slice := (*[1 << 30]C.int)(ptr)[:length:length]
	result := make([]int32, length)
	for i := 0; i < length; i++ {
		result[i] = int32(slice[i])
	}
	return result
}

func cArrToIntSlice2D(ptr unsafe.Pointer, length int) [][2]int32 {
	sz := length * 2
	slice := (*[1 << 30]C.int)(ptr)[:sz:sz]
	result := make([][2]int32, length)
	for i := 0; i < length; i++ {
		j := i * 2
		result[i] = [2]int32{int32(slice[j]), int32(slice[j+1])}
	}
	return result
}

func cArrToIntSlice3D(ptr unsafe.Pointer, length int) [][3]int32 {
	sz := length * 3
	slice := (*[1 << 30]C.int)(ptr)[:sz:sz]
	result := make([][3]int32, length)
	for i := 0; i < length; i++ {
		j := i * 3
		result[i] = [3]int32{int32(slice[j]), int32(slice[j+1]), int32(slice[j+2])}
	}
	return result
}

func cArrToFlt64Slice(ptr unsafe.Pointer, length int) []float64 {
	slice := (*[1 << 30]C.double)(ptr)[:length:length]
	result := make([]float64, length)
	for i := 0; i < length; i++ {
		result[i] = float64(slice[i])
	}
	return result
}

func cArrToFlt64Slice2D(ptr unsafe.Pointer, length int) [][2]float64 {
	sz := length * 2
	slice := (*[1 << 30]C.double)(ptr)[:sz:sz]
	result := make([][2]float64, length)
	for i := 0; i < length; i++ {
		j := i * 2
		result[i] = [2]float64{float64(slice[j]), float64(slice[j+1])}
	}
	return result
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

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

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

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

*/

package echo

import (
	"fmt"
	"net/http"
)

// WrapHandler wrap `interface{}` into `echo.Handler`.
func WrapHandler(h interface{}) Handler {
	if v, ok := h.(HandlerFunc); ok {
		return v
	}
	if v, ok := h.(Handler); ok {
		return v
	}
	if v, ok := h.(func(Context) error); ok {
		return HandlerFunc(v)
	}
	if v, ok := h.(http.Handler); ok {
		return HandlerFunc(func(ctx Context) error {
			v.ServeHTTP(
				ctx.Response().StdResponseWriter(),
				ctx.Request().StdRequest().WithContext(ctx),
			)
			return nil
		})
	}
	if v, ok := h.(func(http.ResponseWriter, *http.Request)); ok {
		return HandlerFunc(func(ctx Context) error {
			v(
				ctx.Response().StdResponseWriter(),
				ctx.Request().StdRequest().WithContext(ctx),
			)
			return nil
		})
	}
	if v, ok := h.(func(http.ResponseWriter, *http.Request) error); ok {
		return HandlerFunc(func(ctx Context) error {
			return v(
				ctx.Response().StdResponseWriter(),
				ctx.Request().StdRequest().WithContext(ctx),
			)
		})
	}
	panic(fmt.Sprintf(`unknown handler: %T`, h))
}

// WrapMiddleware wrap `interface{}` into `echo.Middleware`.
func WrapMiddleware(m interface{}) Middleware {
	if h, ok := m.(MiddlewareFunc); ok {
		return h
	}
	if h, ok := m.(MiddlewareFuncd); ok {
		return h
	}
	if h, ok := m.(Middleware); ok {
		return h
	}
	if h, ok := m.(HandlerFunc); ok {
		return WrapMiddlewareFromHandler(h)
	}
	if h, ok := m.(func(Context) error); ok {
		return WrapMiddlewareFromHandler(HandlerFunc(h))
	}
	if h, ok := m.(func(Handler) func(Context) error); ok {
		return MiddlewareFunc(func(next Handler) Handler {
			return HandlerFunc(h(next))
		})
	}
	if h, ok := m.(func(Handler) HandlerFunc); ok {
		return MiddlewareFunc(func(next Handler) Handler {
			return h(next)
		})
	}
	if h, ok := m.(func(HandlerFunc) HandlerFunc); ok {
		return MiddlewareFunc(func(next Handler) Handler {
			return h(next.Handle)
		})
	}
	if h, ok := m.(func(Handler) Handler); ok {
		return MiddlewareFunc(h)
	}
	if h, ok := m.(func(func(Context) error) func(Context) error); ok {
		return MiddlewareFunc(func(next Handler) Handler {
			return HandlerFunc(h(next.Handle))
		})
	}
	if v, ok := m.(http.Handler); ok {
		return WrapMiddlewareFromStdHandler(v)
	}
	if v, ok := m.(func(http.ResponseWriter, *http.Request)); ok {
		return WrapMiddlewareFromStdHandleFunc(v)
	}
	if v, ok := m.(func(http.ResponseWriter, *http.Request) error); ok {
		return WrapMiddlewareFromStdHandleFuncd(v)
	}
	panic(fmt.Sprintf(`unknown middleware: %T`, m))
}

// WrapMiddlewareFromHandler wrap `echo.HandlerFunc` into `echo.Middleware`.
func WrapMiddlewareFromHandler(h HandlerFunc) Middleware {
	return MiddlewareFunc(func(next Handler) Handler {
		return HandlerFunc(func(c Context) error {
			if err := h.Handle(c); err != nil {
				return err
			}
			return next.Handle(c)
		})
	})
}

// WrapMiddlewareFromStdHandler wrap `http.HandlerFunc` into `echo.Middleware`.
func WrapMiddlewareFromStdHandler(h http.Handler) Middleware {
	return MiddlewareFunc(func(next Handler) Handler {
		return HandlerFunc(func(c Context) error {
			h.ServeHTTP(
				c.Response().StdResponseWriter(),
				c.Request().StdRequest().WithContext(c),
			)
			if c.Response().Committed() {
				return nil
			}
			return next.Handle(c)
		})
	})
}

// WrapMiddlewareFromStdHandleFunc wrap `func(http.ResponseWriter, *http.Request)` into `echo.Middleware`.
func WrapMiddlewareFromStdHandleFunc(h func(http.ResponseWriter, *http.Request)) Middleware {
	return MiddlewareFunc(func(next Handler) Handler {
		return HandlerFunc(func(c Context) error {
			h(
				c.Response().StdResponseWriter(),
				c.Request().StdRequest().WithContext(c),
			)
			if c.Response().Committed() {
				return nil
			}
			return next.Handle(c)
		})
	})
}

// WrapMiddlewareFromStdHandleFuncd wrap `func(http.ResponseWriter, *http.Request)` into `echo.Middleware`.
func WrapMiddlewareFromStdHandleFuncd(h func(http.ResponseWriter, *http.Request) error) Middleware {
	return MiddlewareFunc(func(next Handler) Handler {
		return HandlerFunc(func(c Context) error {
			if err := h(
				c.Response().StdResponseWriter(),
				c.Request().StdRequest().WithContext(c),
			); err != nil {
				return err
			}
			if c.Response().Committed() {
				return nil
			}
			return next.Handle(c)
		})
	})
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

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

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

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

*/

package echo

import (
	"fmt"
	"net/http"
)

// WrapHandler wrap `interface{}` into `echo.Handler`.
func WrapHandler(h interface{}) Handler {
	switch v := h.(type) {
	case HandlerFunc:
		return v
	case Handler:
		return v
	case func(Context) error:
		return HandlerFunc(v)
	case http.Handler:
		return HandlerFunc(func(ctx Context) error {
			v.ServeHTTP(
				ctx.Response().StdResponseWriter(),
				ctx.Request().StdRequest().WithContext(ctx),
			)
			return nil
		})
	case func(http.ResponseWriter, *http.Request):
		return HandlerFunc(func(ctx Context) error {
			v(
				ctx.Response().StdResponseWriter(),
				ctx.Request().StdRequest().WithContext(ctx),
			)
			return nil
		})
	case func(http.ResponseWriter, *http.Request) error:
		return HandlerFunc(func(ctx Context) error {
			return v(
				ctx.Response().StdResponseWriter(),
				ctx.Request().StdRequest().WithContext(ctx),
			)
		})

	// lazyload
	case func() HandlerFunc:
		return v()
	case func() func(Context) error:
		return HandlerFunc(v())

	default:
		panic(fmt.Sprintf(`unknown handler: %T`, h))
	}
}

// WrapMiddleware wrap `interface{}` into `echo.Middleware`.
func WrapMiddleware(m interface{}) Middleware {
	switch h := m.(type) {
	case MiddlewareFunc:
		return h
	case MiddlewareFuncd:
		return h
	case Middleware:
		return h
	case HandlerFunc:
		return WrapMiddlewareFromHandler(h)
	case func(Context) error:
		return WrapMiddlewareFromHandler(HandlerFunc(h))
	case func(Handler) func(Context) error:
		return MiddlewareFunc(func(next Handler) Handler {
			return HandlerFunc(h(next))
		})
	case func(Handler) HandlerFunc:
		return MiddlewareFunc(func(next Handler) Handler {
			return h(next)
		})
	case func(HandlerFunc) HandlerFunc:
		return MiddlewareFunc(func(next Handler) Handler {
			return h(next.Handle)
		})
	case func(Handler) Handler:
		return MiddlewareFunc(h)
	case func(func(Context) error) func(Context) error:
		return MiddlewareFunc(func(next Handler) Handler {
			return HandlerFunc(h(next.Handle))
		})
	case http.Handler:
		return WrapMiddlewareFromStdHandler(h)
	case func(http.ResponseWriter, *http.Request):
		return WrapMiddlewareFromStdHandleFunc(h)
	case func(http.ResponseWriter, *http.Request) error:
		return WrapMiddlewareFromStdHandleFuncd(h)

	// lazyload
	case func() MiddlewareFunc:
		return h()
	case func() MiddlewareFuncd:
		return h()
	case func() HandlerFunc:
		return WrapMiddlewareFromHandler(h())
	case func() func(Context) error:
		return WrapMiddlewareFromHandler(HandlerFunc(h()))

	default:
		panic(fmt.Sprintf(`unknown middleware: %T`, m))
	}
}

// WrapMiddlewareFromHandler wrap `echo.HandlerFunc` into `echo.Middleware`.
func WrapMiddlewareFromHandler(h HandlerFunc) Middleware {
	return MiddlewareFunc(func(next Handler) Handler {
		return HandlerFunc(func(c Context) error {
			if err := h.Handle(c); err != nil {
				return err
			}
			return next.Handle(c)
		})
	})
}

// WrapMiddlewareFromStdHandler wrap `http.HandlerFunc` into `echo.Middleware`.
func WrapMiddlewareFromStdHandler(h http.Handler) Middleware {
	return MiddlewareFunc(func(next Handler) Handler {
		return HandlerFunc(func(c Context) error {
			h.ServeHTTP(
				c.Response().StdResponseWriter(),
				c.Request().StdRequest().WithContext(c),
			)
			if c.Response().Committed() {
				return nil
			}
			return next.Handle(c)
		})
	})
}

// WrapMiddlewareFromStdHandleFunc wrap `func(http.ResponseWriter, *http.Request)` into `echo.Middleware`.
func WrapMiddlewareFromStdHandleFunc(h func(http.ResponseWriter, *http.Request)) Middleware {
	return MiddlewareFunc(func(next Handler) Handler {
		return HandlerFunc(func(c Context) error {
			h(
				c.Response().StdResponseWriter(),
				c.Request().StdRequest().WithContext(c),
			)
			if c.Response().Committed() {
				return nil
			}
			return next.Handle(c)
		})
	})
}

// WrapMiddlewareFromStdHandleFuncd wrap `func(http.ResponseWriter, *http.Request)` into `echo.Middleware`.
func WrapMiddlewareFromStdHandleFuncd(h func(http.ResponseWriter, *http.Request) error) Middleware {
	return MiddlewareFunc(func(next Handler) Handler {
		return HandlerFunc(func(c Context) error {
			if err := h(
				c.Response().StdResponseWriter(),
				c.Request().StdRequest().WithContext(c),
			); err != nil {
				return err
			}
			if c.Response().Committed() {
				return nil
			}
			return next.Handle(c)
		})
	})
}
<|endoftext|>