<commit_before>// Copyright The OpenTelemetry Authors
//
// 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 trace

import (
	"context"
	"errors"
	"log"
	"sync"
	"sync/atomic"
	"time"

	export "go.opentelemetry.io/otel/sdk/export/trace"
)

const (
	defaultMaxQueueSize       = 2048
	defaultScheduledDelay     = 5000 * time.Millisecond
	defaultMaxExportBatchSize = 512
)

var (
	errNilExporter = errors.New("exporter is nil")
)

type BatchSpanProcessorOption func(o *BatchSpanProcessorOptions)

type BatchSpanProcessorOptions struct {
	// MaxQueueSize is the maximum queue size to buffer spans for delayed processing. If the
	// queue gets full it drops the spans. Use BlockOnQueueFull to change this behavior.
	// The default value of MaxQueueSize is 2048.
	MaxQueueSize int

	// ScheduledDelayMillis is the delay interval in milliseconds between two consecutive
	// processing of batches.
	// The default value of ScheduledDelayMillis is 5000 msec.
	ScheduledDelayMillis time.Duration

	// MaxExportBatchSize is the maximum number of spans to process in a single batch.
	// If there are more than one batch worth of spans then it processes multiple batches
	// of spans one batch after the other without any delay.
	// The default value of MaxExportBatchSize is 512.
	MaxExportBatchSize int

	// BlockOnQueueFull blocks onEnd() and onStart() method if the queue is full
	// AND if BlockOnQueueFull is set to true.
	// Blocking option should be used carefully as it can severely affect the performance of an
	// application.
	BlockOnQueueFull bool
}

// BatchSpanProcessor implements SpanProcessor interfaces. It is used by
// exporters to receive export.SpanData asynchronously.
// Use BatchSpanProcessorOptions to change the behavior of the processor.
type BatchSpanProcessor struct {
	e export.SpanBatcher
	o BatchSpanProcessorOptions

	queue   chan *export.SpanData
	dropped uint32

	enqueueWait sync.WaitGroup
	stopWait    sync.WaitGroup
	stopOnce    sync.Once
	stopCh      chan struct{}
}

var _ SpanProcessor = (*BatchSpanProcessor)(nil)

// NewBatchSpanProcessor creates a new instance of BatchSpanProcessor
// for a given export. It returns an error if exporter is nil.
// The newly created BatchSpanProcessor should then be registered with sdk
// using RegisterSpanProcessor.
func NewBatchSpanProcessor(e export.SpanBatcher, opts ...BatchSpanProcessorOption) (*BatchSpanProcessor, error) {
	if e == nil {
		return nil, errNilExporter
	}

	o := BatchSpanProcessorOptions{
		ScheduledDelayMillis: defaultScheduledDelay,
		MaxQueueSize:         defaultMaxQueueSize,
		MaxExportBatchSize:   defaultMaxExportBatchSize,
	}
	for _, opt := range opts {
		opt(&o)
	}
	bsp := &BatchSpanProcessor{
		e: e,
		o: o,
	}

	bsp.queue = make(chan *export.SpanData, bsp.o.MaxQueueSize)

	bsp.stopCh = make(chan struct{})

	bsp.stopWait.Add(1)
	go func() {
		defer bsp.stopWait.Done()
		bsp.processQueue()
	}()

	return bsp, nil
}

// OnStart method does nothing.
func (bsp *BatchSpanProcessor) OnStart(sd *export.SpanData) {
}

// OnEnd method enqueues export.SpanData for later processing.
func (bsp *BatchSpanProcessor) OnEnd(sd *export.SpanData) {
	bsp.enqueue(sd)
}

// Shutdown flushes the queue and waits until all spans are processed.
// It only executes once. Subsequent call does nothing.
func (bsp *BatchSpanProcessor) Shutdown() {
	bsp.stopOnce.Do(func() {
		close(bsp.stopCh)
		bsp.stopWait.Wait()
	})
}

func WithMaxQueueSize(size int) BatchSpanProcessorOption {
	return func(o *BatchSpanProcessorOptions) {
		o.MaxQueueSize = size
	}
}

func WithMaxExportBatchSize(size int) BatchSpanProcessorOption {
	return func(o *BatchSpanProcessorOptions) {
		o.MaxExportBatchSize = size
	}
}

func WithScheduleDelayMillis(delay time.Duration) BatchSpanProcessorOption {
	return func(o *BatchSpanProcessorOptions) {
		o.ScheduledDelayMillis = delay
	}
}

func WithBlocking() BatchSpanProcessorOption {
	return func(o *BatchSpanProcessorOptions) {
		o.BlockOnQueueFull = true
	}
}

// processQueue removes spans from the `queue` channel until processor
// is shut down. It calls the exporter in batches of up to MaxExportBatchSize
// waiting up to ScheduledDelayMillis to form a batch.
func (bsp *BatchSpanProcessor) processQueue() {
	timer := time.NewTimer(bsp.o.ScheduledDelayMillis)
	defer timer.Stop()

	batch := make([]*export.SpanData, 0, bsp.o.MaxExportBatchSize)

	exportSpans := func() {
		if !timer.Stop() {
			<-timer.C
		}
		timer.Reset(bsp.o.ScheduledDelayMillis)

		if len(batch) > 0 {
			bsp.e.ExportSpans(context.Background(), batch)
			batch = batch[:0]
		}
	}

loop:
	for {
		select {
		case <-bsp.stopCh:
			break loop
		case <-timer.C:
			exportSpans()
		case sd := <-bsp.queue:
			batch = append(batch, sd)
			if len(batch) == bsp.o.MaxExportBatchSize {
				exportSpans()
			}
		}
	}

	go func() {
		bsp.enqueueWait.Wait()
		close(bsp.queue)
	}()

	for {
		if !timer.Stop() {
			<-timer.C
		}
		const waitTimeout = 30 * time.Second
		timer.Reset(waitTimeout)

		select {
		case sd := <-bsp.queue:
			if sd == nil {
				exportSpans()
				return
			}

			batch = append(batch, sd)
			if len(batch) == bsp.o.MaxExportBatchSize {
				exportSpans()
			}
		case <-timer.C:
			//TODO: use error callback - see issue #174
			log.Println("bsp.enqueueWait timeout")
			exportSpans()
			return
		}
	}
}

func (bsp *BatchSpanProcessor) enqueue(sd *export.SpanData) {
	if !sd.SpanContext.IsSampled() {
		return
	}

	bsp.enqueueWait.Add(1)

	select {
	case <-bsp.stopCh:
		bsp.enqueueWait.Done()
		return
	default:
	}

	if bsp.o.BlockOnQueueFull {
		bsp.queue <- sd
	} else {
		select {
		case bsp.queue <- sd:
		default:
			atomic.AddUint32(&bsp.dropped, 1)
		}
	}

	bsp.enqueueWait.Done()
}
<commit_msg>Add a comment<commit_after>// Copyright The OpenTelemetry Authors
//
// 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 trace

import (
	"context"
	"errors"
	"log"
	"sync"
	"sync/atomic"
	"time"

	export "go.opentelemetry.io/otel/sdk/export/trace"
)

const (
	defaultMaxQueueSize       = 2048
	defaultScheduledDelay     = 5000 * time.Millisecond
	defaultMaxExportBatchSize = 512
)

var (
	errNilExporter = errors.New("exporter is nil")
)

type BatchSpanProcessorOption func(o *BatchSpanProcessorOptions)

type BatchSpanProcessorOptions struct {
	// MaxQueueSize is the maximum queue size to buffer spans for delayed processing. If the
	// queue gets full it drops the spans. Use BlockOnQueueFull to change this behavior.
	// The default value of MaxQueueSize is 2048.
	MaxQueueSize int

	// ScheduledDelayMillis is the delay interval in milliseconds between two consecutive
	// processing of batches.
	// The default value of ScheduledDelayMillis is 5000 msec.
	ScheduledDelayMillis time.Duration

	// MaxExportBatchSize is the maximum number of spans to process in a single batch.
	// If there are more than one batch worth of spans then it processes multiple batches
	// of spans one batch after the other without any delay.
	// The default value of MaxExportBatchSize is 512.
	MaxExportBatchSize int

	// BlockOnQueueFull blocks onEnd() and onStart() method if the queue is full
	// AND if BlockOnQueueFull is set to true.
	// Blocking option should be used carefully as it can severely affect the performance of an
	// application.
	BlockOnQueueFull bool
}

// BatchSpanProcessor implements SpanProcessor interfaces. It is used by
// exporters to receive export.SpanData asynchronously.
// Use BatchSpanProcessorOptions to change the behavior of the processor.
type BatchSpanProcessor struct {
	e export.SpanBatcher
	o BatchSpanProcessorOptions

	queue   chan *export.SpanData
	dropped uint32

	enqueueWait sync.WaitGroup
	stopWait    sync.WaitGroup
	stopOnce    sync.Once
	stopCh      chan struct{}
}

var _ SpanProcessor = (*BatchSpanProcessor)(nil)

// NewBatchSpanProcessor creates a new instance of BatchSpanProcessor
// for a given export. It returns an error if exporter is nil.
// The newly created BatchSpanProcessor should then be registered with sdk
// using RegisterSpanProcessor.
func NewBatchSpanProcessor(e export.SpanBatcher, opts ...BatchSpanProcessorOption) (*BatchSpanProcessor, error) {
	if e == nil {
		return nil, errNilExporter
	}

	o := BatchSpanProcessorOptions{
		ScheduledDelayMillis: defaultScheduledDelay,
		MaxQueueSize:         defaultMaxQueueSize,
		MaxExportBatchSize:   defaultMaxExportBatchSize,
	}
	for _, opt := range opts {
		opt(&o)
	}
	bsp := &BatchSpanProcessor{
		e: e,
		o: o,
	}

	bsp.queue = make(chan *export.SpanData, bsp.o.MaxQueueSize)

	bsp.stopCh = make(chan struct{})

	bsp.stopWait.Add(1)
	go func() {
		defer bsp.stopWait.Done()
		bsp.processQueue()
	}()

	return bsp, nil
}

// OnStart method does nothing.
func (bsp *BatchSpanProcessor) OnStart(sd *export.SpanData) {
}

// OnEnd method enqueues export.SpanData for later processing.
func (bsp *BatchSpanProcessor) OnEnd(sd *export.SpanData) {
	bsp.enqueue(sd)
}

// Shutdown flushes the queue and waits until all spans are processed.
// It only executes once. Subsequent call does nothing.
func (bsp *BatchSpanProcessor) Shutdown() {
	bsp.stopOnce.Do(func() {
		close(bsp.stopCh)
		bsp.stopWait.Wait()
	})
}

func WithMaxQueueSize(size int) BatchSpanProcessorOption {
	return func(o *BatchSpanProcessorOptions) {
		o.MaxQueueSize = size
	}
}

func WithMaxExportBatchSize(size int) BatchSpanProcessorOption {
	return func(o *BatchSpanProcessorOptions) {
		o.MaxExportBatchSize = size
	}
}

func WithScheduleDelayMillis(delay time.Duration) BatchSpanProcessorOption {
	return func(o *BatchSpanProcessorOptions) {
		o.ScheduledDelayMillis = delay
	}
}

func WithBlocking() BatchSpanProcessorOption {
	return func(o *BatchSpanProcessorOptions) {
		o.BlockOnQueueFull = true
	}
}

// processQueue removes spans from the `queue` channel until processor
// is shut down. It calls the exporter in batches of up to MaxExportBatchSize
// waiting up to ScheduledDelayMillis to form a batch.
func (bsp *BatchSpanProcessor) processQueue() {
	timer := time.NewTimer(bsp.o.ScheduledDelayMillis)
	defer timer.Stop()

	batch := make([]*export.SpanData, 0, bsp.o.MaxExportBatchSize)

	exportSpans := func() {
		if !timer.Stop() {
			<-timer.C
		}
		timer.Reset(bsp.o.ScheduledDelayMillis)

		if len(batch) > 0 {
			bsp.e.ExportSpans(context.Background(), batch)
			batch = batch[:0]
		}
	}

loop:
	for {
		select {
		case <-bsp.stopCh:
			break loop
		case <-timer.C:
			exportSpans()
		case sd := <-bsp.queue:
			batch = append(batch, sd)
			if len(batch) == bsp.o.MaxExportBatchSize {
				exportSpans()
			}
		}
	}

	go func() {
		bsp.enqueueWait.Wait()
		close(bsp.queue)
	}()

	for {
		if !timer.Stop() {
			<-timer.C
		}
		// This is not needed normally, but use some timeout so we are not stuck
		// waiting for enqueueWait forever.
		const waitTimeout = 30 * time.Second
		timer.Reset(waitTimeout)

		select {
		case sd := <-bsp.queue:
			if sd == nil {
				exportSpans()
				return
			}

			batch = append(batch, sd)
			if len(batch) == bsp.o.MaxExportBatchSize {
				exportSpans()
			}
		case <-timer.C:
			//TODO: use error callback - see issue #174
			log.Println("bsp.enqueueWait timeout")
			exportSpans()
			return
		}
	}
}

func (bsp *BatchSpanProcessor) enqueue(sd *export.SpanData) {
	if !sd.SpanContext.IsSampled() {
		return
	}

	bsp.enqueueWait.Add(1)

	select {
	case <-bsp.stopCh:
		bsp.enqueueWait.Done()
		return
	default:
	}

	if bsp.o.BlockOnQueueFull {
		bsp.queue <- sd
	} else {
		select {
		case bsp.queue <- sd:
		default:
			atomic.AddUint32(&bsp.dropped, 1)
		}
	}

	bsp.enqueueWait.Done()
}
<|endoftext|>


<commit_before>package dajarep

import (
	"regexp"
	"strings"

	ipa "github.com/ikawaha/kagome-dict/ipa"
	"github.com/ikawaha/kagome/v2/tokenizer"
)

//単語
type word struct {
	str   string
	kana  string
	wtype string
}

//文章
type sentence struct {
	str   string
	kana  string
	yomi  string
	words []word
}

//Dajarep :駄洒落を返す
func Dajarep(text string) (dajares []string, debugStrs []string) {
	sentences := getSentences(text)
	for i := 0; i < len(sentences); i++ {
		if ok, kana := isDajare(sentences[i]); ok == true {
			dajares = append(dajares, sentences[i].str)
			debugStrs = append(debugStrs, kana)
		}
	}
	return dajares, debugStrs
}

//駄洒落かどうかを評価する。
func isDajare(sen sentence) (bool, string) {
	words := sen.words
	for i := 0; i < len(words); i++ {
		w := words[i]
		if w.wtype == "名詞" && len([]rune(w.kana)) > 1 {
			rStr := regexp.MustCompile(w.str)
			rKana := regexp.MustCompile(fixWord(w.kana))
			hitStr := rStr.FindAllString(sen.str, -1)
			hitKana1 := rKana.FindAllString(sen.kana, -1)
			hitKana2 := rKana.FindAllString(fixSentence(sen.kana), -1)
			hitKana3 := rKana.FindAllString(sen.yomi, -1)
			hitKana4 := rKana.FindAllString(fixSentence(sen.yomi), -1)

			//ある単語における　原文の一致文字列数<フリガナでの一致文字列数　→　駄洒落の読みが存在
			if len(hitStr) < most(len(hitKana1), len(hitKana2), len(hitKana3), len(hitKana4)) {
				return true, w.kana
			}
		}
	}
	return false, ""
}

//置き換え可能な文字を考慮した正規表現を返す。
func fixWord(text string) string {
	text = strings.Replace(text, "ッ", "[ツッ]?", -1)
	text = strings.Replace(text, "ァ", "[アァ]?", -1)
	text = strings.Replace(text, "ィ", "[イィ]?", -1)
	text = strings.Replace(text, "ゥ", "[ウゥ]?", -1)
	text = strings.Replace(text, "ェ", "[エェ]?", -1)
	text = strings.Replace(text, "ォ", "[オォ]?", -1)
	text = strings.Replace(text, "ズ", "[スズヅ]", -1)
	text = strings.Replace(text, "ヅ", "[ツズヅ]", -1)
	text = strings.Replace(text, "ヂ", "[チジヂ]", -1)
	text = strings.Replace(text, "ジ", "[シジヂ]", -1)
	text = strings.Replace(text, "ガ", "[カガ]", -1)
	text = strings.Replace(text, "ギ", "[キギ]", -1)
	text = strings.Replace(text, "グ", "[クグ]", -1)
	text = strings.Replace(text, "ゲ", "[ケゲ]", -1)
	text = strings.Replace(text, "ゴ", "[コゴ]", -1)
	text = strings.Replace(text, "ザ", "[サザ]", -1)
	text = strings.Replace(text, "ゼ", "[セゼ]", -1)
	text = strings.Replace(text, "ゾ", "[ソゾ]", -1)
	text = strings.Replace(text, "ダ", "[タダ]", -1)
	text = strings.Replace(text, "デ", "[テデ]", -1)
	text = strings.Replace(text, "ド", "[トド]", -1)
	text = strings.Replace(text, "バ", "[ハバパ]", -1)
	text = strings.Replace(text, "ビ", "[ヒビピ]", -1)
	text = strings.Replace(text, "ブ", "[フブプ]", -1)
	text = strings.Replace(text, "ベ", "[ヘベペ]", -1)
	text = strings.Replace(text, "ボ", "[ホボポ]", -1)
	text = strings.Replace(text, "パ", "[ハバパ]", -1)
	text = strings.Replace(text, "ピ", "[ヒビピ]", -1)
	text = strings.Replace(text, "プ", "[フブプ]", -1)
	text = strings.Replace(text, "ペ", "[ヘベペ]", -1)
	text = strings.Replace(text, "ポ", "[ホボポ]", -1)
	re := regexp.MustCompile("([アカサタナハマヤラワャ])ー")
	text = re.ReplaceAllString(text, "$1[アァ]?")
	re = regexp.MustCompile("([イキシチニヒミリ])ー")
	text = re.ReplaceAllString(text, "$1[イィ]?")
	re = regexp.MustCompile("([ウクスツヌフムユルュ])ー")
	text = re.ReplaceAllString(text, "$1[ウゥ]?")
	re = regexp.MustCompile("([エケセテネへメレ])ー")
	text = re.ReplaceAllString(text, "$1[イィエェ]?")
	re = regexp.MustCompile("([オコソトノホモヨロヲョ])ー")
	text = re.ReplaceAllString(text, "$1[ウゥオォ]?")
	text = strings.Replace(text, "ャ", "[ヤャ]", -1)
	text = strings.Replace(text, "ュ", "[ユュ]", -1)
	text = strings.Replace(text, "ョ", "[ヨョ]", -1)
	text = strings.Replace(text, "ー", "[ー]?", -1)
	return text
}

//本文から省略可能文字を消したパターンを返す。
func fixSentence(text string) string {
	text = strings.Replace(text, "ッ", "", -1)
	text = strings.Replace(text, "ー", "", -1)
	text = strings.Replace(text, "、", "", -1)
	text = strings.Replace(text, ",", "", -1)
	text = strings.Replace(text, "　", "", -1)
	text = strings.Replace(text, " ", "", -1)
	return text
}

//テキストからsentenceオブジェクトを作る。
func getSentences(text string) []sentence {
	var sentences []sentence
	t, err := tokenizer.New(ipa.Dict())
	if err != nil {
		panic(err)
	}

	text = strings.Replace(text, "。", "\n", -1)
	text = strings.Replace(text, ".", "\n", -1)
	text = strings.Replace(text, "?", "?\n", -1)
	text = strings.Replace(text, "!", "!\n", -1)
	text = strings.Replace(text, "？", "？\n", -1)
	text = strings.Replace(text, "！", "！\n", -1)
	senstr := strings.Split(text, "\n")

	for i := 0; i < len(senstr); i++ {
		tokens := t.Tokenize(senstr[i])
		var words []word
		var kana string
		var yomi string

		for j := 0; j < len(tokens); j++ {
			tk := tokens[j]
			ft := tk.Features()
			if len(ft) > 7 {
				w := word{str: ft[6],
					kana:  ft[7],
					wtype: ft[0],
				}
				words = append(words, w)
				kana += ft[7]
				yomi += ft[8]
			}
		}
		sentences = append(sentences,
			sentence{
				str:   senstr[i],
				words: words,
				kana:  kana,
				yomi:  yomi,
			})
	}
	return sentences
}

func most(num ...int) int {
	i := 0
	for _, n := range num {
		if n > i {
			i = n
		}
	}
	return i
}
<commit_msg>バ行パ行の変換を修正<commit_after>package dajarep

import (
	"regexp"
	"strings"

	ipa "github.com/ikawaha/kagome-dict/ipa"
	"github.com/ikawaha/kagome/v2/tokenizer"
)

//単語
type word struct {
	str   string
	kana  string
	wtype string
}

//文章
type sentence struct {
	str   string
	kana  string
	yomi  string
	words []word
}

//Dajarep :駄洒落を返す
func Dajarep(text string) (dajares []string, debugStrs []string) {
	sentences := getSentences(text)
	for i := 0; i < len(sentences); i++ {
		if ok, kana := isDajare(sentences[i]); ok == true {
			dajares = append(dajares, sentences[i].str)
			debugStrs = append(debugStrs, kana)
		}
	}
	return dajares, debugStrs
}

//駄洒落かどうかを評価する。
func isDajare(sen sentence) (bool, string) {
	words := sen.words
	for i := 0; i < len(words); i++ {
		w := words[i]
		if w.wtype == "名詞" && len([]rune(w.kana)) > 1 {
			rStr := regexp.MustCompile(w.str)
			rKana := regexp.MustCompile(fixWord(w.kana))
			hitStr := rStr.FindAllString(sen.str, -1)
			hitKana1 := rKana.FindAllString(sen.kana, -1)
			hitKana2 := rKana.FindAllString(fixSentence(sen.kana), -1)
			hitKana3 := rKana.FindAllString(sen.yomi, -1)
			hitKana4 := rKana.FindAllString(fixSentence(sen.yomi), -1)

			//ある単語における　原文の一致文字列数<フリガナでの一致文字列数　→　駄洒落の読みが存在
			if len(hitStr) < most(len(hitKana1), len(hitKana2), len(hitKana3), len(hitKana4)) {
				return true, w.kana
			}
		}
	}
	return false, ""
}

//置き換え可能な文字を考慮した正規表現を返す。
func fixWord(text string) string {
	text = strings.Replace(text, "ッ", "[ツッ]?", -1)
	text = strings.Replace(text, "ァ", "[アァ]?", -1)
	text = strings.Replace(text, "ィ", "[イィ]?", -1)
	text = strings.Replace(text, "ゥ", "[ウゥ]?", -1)
	text = strings.Replace(text, "ェ", "[エェ]?", -1)
	text = strings.Replace(text, "ォ", "[オォ]?", -1)
	text = strings.Replace(text, "ズ", "[スズヅ]", -1)
	text = strings.Replace(text, "ヅ", "[ツズヅ]", -1)
	text = strings.Replace(text, "ヂ", "[チジヂ]", -1)
	text = strings.Replace(text, "ジ", "[シジヂ]", -1)
	text = strings.Replace(text, "ガ", "[カガ]", -1)
	text = strings.Replace(text, "ギ", "[キギ]", -1)
	text = strings.Replace(text, "グ", "[クグ]", -1)
	text = strings.Replace(text, "ゲ", "[ケゲ]", -1)
	text = strings.Replace(text, "ゴ", "[コゴ]", -1)
	text = strings.Replace(text, "ザ", "[サザ]", -1)
	text = strings.Replace(text, "ゼ", "[セゼ]", -1)
	text = strings.Replace(text, "ゾ", "[ソゾ]", -1)
	text = strings.Replace(text, "ダ", "[タダ]", -1)
	text = strings.Replace(text, "デ", "[テデ]", -1)
	text = strings.Replace(text, "ド", "[トド]", -1)
	re := regexp.MustCompile("[ハバパ]")
	text = re.ReplaceAllString(text, "[ハバパ]")
	re = regexp.MustCompile("[ヒビピ]")
	text = re.ReplaceAllString(text, "[ヒビピ]")
	re = regexp.MustCompile("[フブプ]")
	text = re.ReplaceAllString(text, "[フブプ]")
	re = regexp.MustCompile("[ヘベペ]")
	text = re.ReplaceAllString(text, "[ヘベペ]")
	re = regexp.MustCompile("[ホボポ]")
	text = re.ReplaceAllString(text, "[ホボポ]")
	re = regexp.MustCompile("([アカサタナハマヤラワャ])ー")
	text = re.ReplaceAllString(text, "$1[アァ]?")
	re = regexp.MustCompile("([イキシチニヒミリ])ー")
	text = re.ReplaceAllString(text, "$1[イィ]?")
	re = regexp.MustCompile("([ウクスツヌフムユルュ])ー")
	text = re.ReplaceAllString(text, "$1[ウゥ]?")
	re = regexp.MustCompile("([エケセテネへメレ])ー")
	text = re.ReplaceAllString(text, "$1[イィエェ]?")
	re = regexp.MustCompile("([オコソトノホモヨロヲョ])ー")
	text = re.ReplaceAllString(text, "$1[ウゥオォ]?")
	text = strings.Replace(text, "ャ", "[ヤャ]", -1)
	text = strings.Replace(text, "ュ", "[ユュ]", -1)
	text = strings.Replace(text, "ョ", "[ヨョ]", -1)
	text = strings.Replace(text, "ー", "[ー]?", -1)
	return text
}

//本文から省略可能文字を消したパターンを返す。
func fixSentence(text string) string {
	text = strings.Replace(text, "ッ", "", -1)
	text = strings.Replace(text, "ー", "", -1)
	text = strings.Replace(text, "、", "", -1)
	text = strings.Replace(text, ",", "", -1)
	text = strings.Replace(text, "　", "", -1)
	text = strings.Replace(text, " ", "", -1)
	return text
}

//テキストからsentenceオブジェクトを作る。
func getSentences(text string) []sentence {
	var sentences []sentence
	t, err := tokenizer.New(ipa.Dict())
	if err != nil {
		panic(err)
	}

	text = strings.Replace(text, "。", "\n", -1)
	text = strings.Replace(text, ".", "\n", -1)
	text = strings.Replace(text, "?", "?\n", -1)
	text = strings.Replace(text, "!", "!\n", -1)
	text = strings.Replace(text, "？", "？\n", -1)
	text = strings.Replace(text, "！", "！\n", -1)
	senstr := strings.Split(text, "\n")

	for i := 0; i < len(senstr); i++ {
		tokens := t.Tokenize(senstr[i])
		var words []word
		var kana string
		var yomi string

		for j := 0; j < len(tokens); j++ {
			tk := tokens[j]
			ft := tk.Features()
			if len(ft) > 7 {
				w := word{str: ft[6],
					kana:  ft[7],
					wtype: ft[0],
				}
				words = append(words, w)
				kana += ft[7]
				yomi += ft[8]
			}
		}
		sentences = append(sentences,
			sentence{
				str:   senstr[i],
				words: words,
				kana:  kana,
				yomi:  yomi,
			})
	}
	return sentences
}

func most(num ...int) int {
	i := 0
	for _, n := range num {
		if n > i {
			i = n
		}
	}
	return i
}
<|endoftext|>


<commit_before>// Copyright 2015 Robert S. Gerus. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package bot

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/cloudflare/gokabinet/kt"

	cfg "github.com/arachnist/gorepost/config"
	"github.com/arachnist/gorepost/irc"
)

var k *kt.Conn

type value struct {
	Network string
	Target  string
	Action  string
	Time    int64 // .Now().UnixNano()
	Text    string
}

func seenrecord(output chan irc.Message, msg irc.Message) {
	v := value{
		Network: msg.Context["Network"],
		Target:  msg.Params[0],
		Action:  msg.Command,
		Time:    time.Now().UnixNano(),
		Text:    msg.Trailing,
	}

	b, err := json.Marshal(v)
	if err != nil {
		log.Println("Context:", msg.Context, "json marshal of seen record failed:", err)
		return
	}

	err = k.Set("seen/"+msg.Prefix.Name, b)
	if err != nil {
		log.Println("Context:", msg.Context, "error recording seen record:", err)
	}
}

func seen(output chan irc.Message, msg irc.Message) {
	var v value

	args := strings.Split(msg.Trailing, " ")

	if args[0] != ":seen" {
		return
	}
	if len(args) < 2 {
		return
	}

	b, err := k.GetBytes("seen/" + args[1])
	if err == kt.ErrNotFound {
		output <- reply(msg, cfg.LookupString(msg.Context, "NotSeenMessage"))
		return
	} else if err != nil {
		output <- reply(msg, fmt.Sprint("error getting record for", args[1], err))
		return
	}

	err = json.Unmarshal(b, &v)
	if err != nil {
		output <- reply(msg, fmt.Sprint("error unmarshaling record for", args[1], err))
		return
	}

	output <- reply(msg, fmt.Sprintf("%+v", v))
}

func init() {
	var err error
	var ktHost = "127.0.0.1"
	var ktPort = 1337

	log.Println("SEEN: connecting to KT")
	k, err = kt.NewConn(ktHost, ktPort, 4, 2*time.Second)
	if err != nil {
		log.Println("error connecting to kyoto tycoon", err)
		return
	}

	log.Println("Registering callbacks")
	addCallback("PRIVMSG", "seen", seen)
	addCallback("PRIVMSG", "seenrecord", seenrecord)
	addCallback("JOIN", "seenrecord", seenrecord)
	addCallback("PART", "seenrecord", seenrecord)
	addCallback("QUIT", "seenrecord", seenrecord)
	addCallback("NOTICE", "seenrecord", seenrecord)
}
<commit_msg>Added formatting.<commit_after>// Copyright 2015 Robert S. Gerus. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package bot

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/cloudflare/gokabinet/kt"

	cfg "github.com/arachnist/gorepost/config"
	"github.com/arachnist/gorepost/irc"
)

var k *kt.Conn

type seenRecord struct {
	Network string
	Target  string
	Action  string
	Time    time.Time
	Text    string
}

func seenrecord(output chan irc.Message, msg irc.Message) {
	v := seenRecord{
		Network: msg.Context["Network"],
		Target:  msg.Params[0],
		Action:  msg.Command,
		Time:    time.Now(),
		Text:    msg.Trailing,
	}

	b, err := json.Marshal(v)
	if err != nil {
		log.Println("Context:", msg.Context, "json marshal of seen record failed:", err)
		return
	}

	err = k.Set("seen/"+msg.Prefix.Name, b)
	if err != nil {
		log.Println("Context:", msg.Context, "error recording seen record:", err)
	}
}

func seen(output chan irc.Message, msg irc.Message) {
	var v seenRecord
	var r string

	args := strings.Split(msg.Trailing, " ")

	if args[0] != ":seen" {
		return
	}
	if len(args) < 2 {
		return
	}

	b, err := k.GetBytes("seen/" + args[1])
	if err == kt.ErrNotFound {
		output <- reply(msg, cfg.LookupString(msg.Context, "NotSeenMessage"))
		return
	} else if err != nil {
		output <- reply(msg, fmt.Sprint("error getting record for", args[1], err))
		return
	}

	err = json.Unmarshal(b, &v)
	if err != nil {
		output <- reply(msg, fmt.Sprint("error unmarshaling record for", args[1], err))
		return
	}

	r = fmt.Sprintf("Last seen %s on %s/%s at %v ", args[1], v.Network, v.Target, v.Time.Round(time.Minute))

	switch v.Action {
	case "JOIN":
		r += "joining"
	case "PART":
		r += fmt.Sprint("leaving: ", v.Text)
	case "QUIT":
		r += fmt.Sprint("quitting with reasson: ", v.Text)
	case "PRIVMSG":
		r += fmt.Sprint("saying: ", v.Text)
	}

	output <- reply(msg, r)
}

func init() {
	var err error
	var ktHost = "127.0.0.1"
	var ktPort = 1337

	log.Println("SEEN: connecting to KT")
	k, err = kt.NewConn(ktHost, ktPort, 4, 2*time.Second)
	if err != nil {
		log.Println("error connecting to kyoto tycoon", err)
		return
	}

	log.Println("Registering callbacks")
	addCallback("PRIVMSG", "seen", seen)
	addCallback("PRIVMSG", "seenrecord", seenrecord)
	addCallback("JOIN", "seenrecord", seenrecord)
	addCallback("PART", "seenrecord", seenrecord)
	addCallback("QUIT", "seenrecord", seenrecord)
	addCallback("NOTICE", "seenrecord", seenrecord)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/cespare/asrt"
)

func init() { log.SetOutput(ioutil.Discard) }

func TestDB(t *testing.T) {
	tempdir, err := ioutil.TempDir(".", "kvcache-test-")
	asrt.Equal(t, err, nil)
	defer os.RemoveAll(tempdir)
	dir := filepath.Join(tempdir, "db")

	var now time.Time

	// See log_test for info about the test data

	db, err := NewDB(50, 10*time.Second, dir)
	asrt.Equal(t, err, nil)
	db.now = func() time.Time { return now }
	db.since = func(t time.Time) time.Duration { return now.Sub(t) }

	// Put/Get some values in the first chunk. Values come out of cache.
	now = ts("2014-09-21T00:00:00Z")
	rotated, err := db.Put(testRecords[0].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, false)

	v, cached, err := db.Get(testRecords[0].key)
	asrt.Equal(t, err, nil)
	asrt.Equal(t, cached, true)
	asrt.Assert(t, bytes.Equal(v, []byte(testVal)))

	now = ts("2014-09-21T00:00:01Z")
	rotated, err = db.Put(testRecords[1].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, false)

	v, cached, err = db.Get(testRecords[1].key)
	asrt.Equal(t, err, nil)
	asrt.Equal(t, cached, true)
	asrt.Assert(t, bytes.Equal(v, []byte(testVal)))

	for _, record := range testRecords[:2] {
		_, err = db.Put(record.key, []byte("asdf"))
		asrt.Equal(t, err, ErrKeyExist)
	}

	asrt.DeepEqual(t, lsDir(dir), []string{"chunk0000000000.idx", "chunk0000000000.log"})

	// Rotate
	now = ts("2014-09-21T00:00:02Z")
	rotated, err = db.Put(testRecords[2].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, true)

	v, cached, err = db.Get(testRecords[0].key)
	asrt.Equal(t, err, nil)
	asrt.Equal(t, cached, false)
	asrt.Assert(t, bytes.Equal(v, []byte(testVal)))

	v, cached, err = db.Get(testRecords[2].key)
	asrt.Equal(t, err, nil)
	asrt.Equal(t, cached, true)
	asrt.Assert(t, bytes.Equal(v, []byte(testVal)))

	asrt.DeepEqual(t, lsDir(dir),
		[]string{"chunk0000000000.idx", "chunk0000000000.log", "chunk0000000001.idx", "chunk0000000001.log"})

	now = ts("2014-09-21T00:00:03Z")
	rotated, err = db.Put(testRecords[3].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, false)

	// Rotate again
	now = ts("2014-09-21T00:00:04Z")
	rotated, err = db.Put(testRecords[4].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, true)

	for i, record := range testRecords {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, nil)
		asrt.Equal(t, cached, i == 4)
		asrt.Assert(t, bytes.Equal(v, []byte(testVal)))
	}

	// Close and check the data
	err = db.Close()
	asrt.Equal(t, err, nil)

	files := []string{"chunk0000000000.idx", "chunk0000000000.log", "chunk0000000001.idx",
		"chunk0000000001.log", "chunk0000000002.idx", "chunk0000000002.log"}
	asrt.DeepEqual(t, lsDir(dir), files)
	for i, want := range []string{testLog1, testLog2, testLog3} {
		got, err := ioutil.ReadFile(filepath.Join(dir, files[i*2+1]))
		asrt.Equal(t, err, nil)
		asrt.Equal(t, string(got), want)
	}

	// Reopen the DB
	db, err = OpenDB(50, 10*time.Second, dir)
	asrt.Equal(t, err, nil)
	db.now = func() time.Time { return now }
	db.since = func(t time.Time) time.Duration { return now.Sub(t) }

	for _, record := range testRecords {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, nil)
		asrt.Equal(t, cached, false)
		asrt.Assert(t, bytes.Equal(v, []byte(testVal)))
	}

	// "Expire" everything older than 2014-09-21T00:00:03Z
	now = ts("2014-09-21T00:00:13Z")

	for _, record := range testRecords[:3] {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, ErrKeyNotExist)
	}

	for _, record := range testRecords[3:] {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, nil)
	}

	// Rotate and ensure the same key/vals are visible, and that the
	// fully expired block was deleted.
	err = db.Rotate()
	asrt.Equal(t, err, nil)

	for _, record := range testRecords[:3] {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, ErrKeyNotExist)
	}

	for _, record := range testRecords[3:] {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, nil)
	}

	// Two new (empty) chunks were added: one was the new write chunk created on OpenDB;
	// the other was made on rotation.
	files = []string{"chunk0000000001.idx", "chunk0000000001.log", "chunk0000000002.idx", "chunk0000000002.log",
		"chunk0000000003.idx", "chunk0000000003.log", "chunk0000000004.idx", "chunk0000000004.log"}
	asrt.DeepEqual(t, lsDir(dir), files)

	err = db.Close()
	asrt.Equal(t, err, nil)
	asrt.DeepEqual(t, lsDir(dir), files)
}
<commit_msg>Rename test data dir<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/cespare/asrt"
)

func init() { log.SetOutput(ioutil.Discard) }

func TestDB(t *testing.T) {
	tempdir, err := ioutil.TempDir(".", "testdata-")
	asrt.Equal(t, err, nil)
	defer os.RemoveAll(tempdir)
	dir := filepath.Join(tempdir, "db")

	var now time.Time

	// See log_test for info about the test data

	db, err := NewDB(50, 10*time.Second, dir)
	asrt.Equal(t, err, nil)
	db.now = func() time.Time { return now }
	db.since = func(t time.Time) time.Duration { return now.Sub(t) }

	// Put/Get some values in the first chunk. Values come out of cache.
	now = ts("2014-09-21T00:00:00Z")
	rotated, err := db.Put(testRecords[0].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, false)

	v, cached, err := db.Get(testRecords[0].key)
	asrt.Equal(t, err, nil)
	asrt.Equal(t, cached, true)
	asrt.Assert(t, bytes.Equal(v, []byte(testVal)))

	now = ts("2014-09-21T00:00:01Z")
	rotated, err = db.Put(testRecords[1].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, false)

	v, cached, err = db.Get(testRecords[1].key)
	asrt.Equal(t, err, nil)
	asrt.Equal(t, cached, true)
	asrt.Assert(t, bytes.Equal(v, []byte(testVal)))

	for _, record := range testRecords[:2] {
		_, err = db.Put(record.key, []byte("asdf"))
		asrt.Equal(t, err, ErrKeyExist)
	}

	asrt.DeepEqual(t, lsDir(dir), []string{"chunk0000000000.idx", "chunk0000000000.log"})

	// Rotate
	now = ts("2014-09-21T00:00:02Z")
	rotated, err = db.Put(testRecords[2].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, true)

	v, cached, err = db.Get(testRecords[0].key)
	asrt.Equal(t, err, nil)
	asrt.Equal(t, cached, false)
	asrt.Assert(t, bytes.Equal(v, []byte(testVal)))

	v, cached, err = db.Get(testRecords[2].key)
	asrt.Equal(t, err, nil)
	asrt.Equal(t, cached, true)
	asrt.Assert(t, bytes.Equal(v, []byte(testVal)))

	asrt.DeepEqual(t, lsDir(dir),
		[]string{"chunk0000000000.idx", "chunk0000000000.log", "chunk0000000001.idx", "chunk0000000001.log"})

	now = ts("2014-09-21T00:00:03Z")
	rotated, err = db.Put(testRecords[3].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, false)

	// Rotate again
	now = ts("2014-09-21T00:00:04Z")
	rotated, err = db.Put(testRecords[4].key, []byte(testVal))
	asrt.Equal(t, err, nil)
	asrt.Equal(t, rotated, true)

	for i, record := range testRecords {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, nil)
		asrt.Equal(t, cached, i == 4)
		asrt.Assert(t, bytes.Equal(v, []byte(testVal)))
	}

	// Close and check the data
	err = db.Close()
	asrt.Equal(t, err, nil)

	files := []string{"chunk0000000000.idx", "chunk0000000000.log", "chunk0000000001.idx",
		"chunk0000000001.log", "chunk0000000002.idx", "chunk0000000002.log"}
	asrt.DeepEqual(t, lsDir(dir), files)
	for i, want := range []string{testLog1, testLog2, testLog3} {
		got, err := ioutil.ReadFile(filepath.Join(dir, files[i*2+1]))
		asrt.Equal(t, err, nil)
		asrt.Equal(t, string(got), want)
	}

	// Reopen the DB
	db, err = OpenDB(50, 10*time.Second, dir)
	asrt.Equal(t, err, nil)
	db.now = func() time.Time { return now }
	db.since = func(t time.Time) time.Duration { return now.Sub(t) }

	for _, record := range testRecords {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, nil)
		asrt.Equal(t, cached, false)
		asrt.Assert(t, bytes.Equal(v, []byte(testVal)))
	}

	// "Expire" everything older than 2014-09-21T00:00:03Z
	now = ts("2014-09-21T00:00:13Z")

	for _, record := range testRecords[:3] {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, ErrKeyNotExist)
	}

	for _, record := range testRecords[3:] {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, nil)
	}

	// Rotate and ensure the same key/vals are visible, and that the
	// fully expired block was deleted.
	err = db.Rotate()
	asrt.Equal(t, err, nil)

	for _, record := range testRecords[:3] {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, ErrKeyNotExist)
	}

	for _, record := range testRecords[3:] {
		v, cached, err = db.Get(record.key)
		asrt.Equal(t, err, nil)
	}

	// Two new (empty) chunks were added: one was the new write chunk created on OpenDB;
	// the other was made on rotation.
	files = []string{"chunk0000000001.idx", "chunk0000000001.log", "chunk0000000002.idx", "chunk0000000002.log",
		"chunk0000000003.idx", "chunk0000000003.log", "chunk0000000004.idx", "chunk0000000004.log"}
	asrt.DeepEqual(t, lsDir(dir), files)

	err = db.Close()
	asrt.Equal(t, err, nil)
	asrt.DeepEqual(t, lsDir(dir), files)
}
<|endoftext|>


<commit_before>package cpu

import (
	"io/ioutil"
	"strings"
	"regexp"
)

type Cpu struct{}

func (self *Cpu) Collect() (result map[string]map[string]string, err error) {
	cpuinfo, err := getCpuInfo()
	return map[string]map[string]string{
		"cpu": cpuinfo,
	}, err
}

func getCpuInfo() (cpuinfo map[string]string, err error) {
	contents, err := ioutil.ReadFile("/proc/cpuinfo")
	if err != nil {
		return
	}

	lines := strings.Split(string(contents), "\n")

	cpuinfo = make(map[string]string)

	for _, line := range(lines) {
		fields := regSplit(line, "\t+: ")
		switch fields[0] {
		case "model name": cpuinfo["model_name"] = fields[1]
		}
	}
	return
}

func regSplit(text string, delimeter string) []string {
	reg := regexp.MustCompile(delimeter)
	indexes := reg.FindAllStringIndex(text, -1)
	laststart := 0
	result := make([]string, len(indexes) + 1)
	for i, element := range indexes {
		result[i] = text[laststart:element[0]]
		laststart = element[1]
	}
	result[len(indexes)] = text[laststart:len(text)]
	return result
}
<commit_msg>Add more info of CPU<commit_after>package cpu

import (
	"io/ioutil"
	"regexp"
	"strings"
)

type Cpu struct{}

func (self *Cpu) Collect() (result map[string]map[string]string, err error) {
	cpuinfo, err := getCpuInfo()

	return map[string]map[string]string{
		"cpu": cpuinfo,
	}, err
}

func getCpuInfo() (cpuinfo map[string]string, err error) {
	contents, err := ioutil.ReadFile("/proc/cpuinfo")

	if err != nil {
		return
	}

	cpuinfo = make(map[string]string)
    count := 0

	lines := strings.Split(string(contents), "\n")

	for _, line := range lines {
		fields := regSplit(line, "\t+: ")
		switch fields[0] {
		case "processor":
			cpuinfo["processor"] = fields[1]
			count += 1
		case "vendor_id":
			cpuinfo["vendor_id"] = fields[1]
		case "family":
			cpuinfo["family"] = fields[1]
		case "model":
			cpuinfo["model"] = fields[1]
		case "model name":
			cpuinfo["model_name"] = fields[1]
		case "stepping":
			cpuinfo["stepping"] = fields[1]
		case "physical id":
			cpuinfo["physical_id"] = fields[1]
		case "core id":
			cpuinfo["physical_id"] = fields[1]
		case "cpu cores":
			cpuinfo["cpu cores"] = fields[1]
		case "cpu MHz":
			cpuinfo["mhz"] = fields[1]
		case "cache size":
			cpuinfo["cache_size"] = fields[1]
		case "flags":
			cpuinfo["flags"] = fields[1]
		}
	}

	cpuinfo["total"] = string(count)
	return
}

func regSplit(text string, delimeter string) []string {
	reg := regexp.MustCompile(delimeter)
	indexes := reg.FindAllStringIndex(text, -1)
	laststart := 0
	result := make([]string, len(indexes)+1)

	for i, element := range indexes {
		result[i] = text[laststart:element[0]]
		laststart = element[1]
	}

	result[len(indexes)] = text[laststart:len(text)]
	return result
}
<|endoftext|>


<commit_before>// Brunobot notifies a Discord channel when Professional Dota 2 games are live.
// This should be run via cron every minute to ensure only one notification.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

type payload struct {
	Content string `json:"content"`
}

type configuration struct {
	Teams     []string
	Webhook   string
	Whitelist bool
}

type api struct {
	Matches []struct {
		Team1 struct {
			TeamName string `json:"team_name"`
		} `json:"team1"`
		Link          string `json:"link"`
		StarttimeUnix string `json:"starttime_unix"`
		Team2         struct {
			TeamName string `json:"team_name"`
		} `json:"team2"`
	} `json:"matches"`
}

func getMatches(url string, target interface{}) error {
	req, err := http.NewRequest("GET", url, nil)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	return json.NewDecoder(resp.Body).Decode(target)
}

func sendNotification(text string, webhook string) {
	payload := payload{text}
	blob, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}
	req, err := http.NewRequest("POST", webhook, bytes.NewBuffer(blob))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
}

func usage() {
	fmt.Println("Usage: brunobot --config=/path/to/config.json")
	os.Exit(1)
}

func whitelisted(team1 string, team2 string, whitelist []string) bool {
	a := strings.ToLower(team1)
	b := strings.ToLower(team2)
	for _, team := range whitelist {
		team = strings.ToLower(team)
		if a == team || b == team {
			return true
		}
	}
	return false
}

// Webhook must be set in configuration
func parseConfiguration(path string) (config configuration, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}

	if config.Webhook == "" {
		err = fmt.Errorf("Webhook is not set")
		return
	}

	return
}

func main() {
	configFile := flag.String("config", "", "Configuration file")
	flag.Parse()
	if *configFile == "" {
		fmt.Println("Configuration file not found.. exiting")
		usage()
	}

	// parse configuration
	configuration, err := parseConfiguration(*configFile)
	if err != nil {
		fmt.Println(err)
		usage()
	}

	api := new(api)
	getMatches("http://dailydota2.com/match-api", api)
	if len(api.Matches) != 0 {
		for _, match := range api.Matches {
			team1 := match.Team1.TeamName
			team2 := match.Team2.TeamName
			send := false

			if configuration.Whitelist {
				send = whitelisted(team1, team2, configuration.Teams)
			} else {
				send = true
			}

			// Prevent multiple notifications by checking time difference
			startTime, _ := strconv.Atoi(match.StarttimeUnix)
			delta := time.Now().Unix() - int64(startTime)
			if send && delta <= 60 {
				// Link points to stream but the stats page is nicer, so replace
				// with the stats URL instead
				url := strings.Replace(match.Link, "match", "stats", 1)
				notification := fmt.Sprintf("%s vs %s :: %s", team1, team2, url)
				sendNotification(notification, configuration.Webhook)
			}
		}
	}
}
<commit_msg>Return Matches From getMatches Function<commit_after>// Brunobot notifies a Discord channel when Professional Dota 2 games are live.
// This should be run via cron every minute to ensure only one notification.
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

const API_URL = "http://dailydota2.com/match-api"

type payload struct {
	Content string `json:"content"`
}

type configuration struct {
	Teams     []string
	Webhook   string
	Whitelist bool
}

type apiResponse struct {
	Matches   []match `json:"matches"`
	Timestamp int     `json:"timestamp"`
}

type match struct {
	Team1 struct {
		TeamName string `json:"team_name"`
	} `json:"team1"`
	Team2 struct {
		TeamName string `json:"team_name"`
	} `json:"team2"`
	Link          string `json:"link"`
	StarttimeUnix string `json:"starttime_unix"`
}

func getMatches(url string) (matches []match, err error) {
	req, err := http.NewRequest("GET", url, nil)
	req.Header.Set("Accept", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()

	var r apiResponse
	decoder := json.NewDecoder(resp.Body)
	err = decoder.Decode(&r)
	if err != nil {
		return
	}

	matches = r.Matches

	return
}

func sendNotification(text string, webhook string) {
	payload := payload{text}
	blob, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}
	req, err := http.NewRequest("POST", webhook, bytes.NewBuffer(blob))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
}

func usage() {
	fmt.Println("Usage: brunobot --config=/path/to/config.json")
	os.Exit(1)
}

func whitelisted(team1 string, team2 string, whitelist []string) bool {
	a := strings.ToLower(team1)
	b := strings.ToLower(team2)
	for _, team := range whitelist {
		team = strings.ToLower(team)
		if a == team || b == team {
			return true
		}
	}
	return false
}

// Webhook must be set in configuration
func parseConfiguration(path string) (config configuration, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}

	if config.Webhook == "" {
		err = fmt.Errorf("Webhook is not set")
		return
	}

	return
}

func main() {
	configFile := flag.String("config", "", "Configuration file")
	flag.Parse()
	if *configFile == "" {
		fmt.Println("Configuration file not found.. exiting")
		usage()
	}

	// parse configuration
	configuration, err := parseConfiguration(*configFile)
	if err != nil {
		fmt.Println(err)
		usage()
	}

	// get current matches
	matches, err := getMatches(API_URL)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if len(matches) != 0 {
		for _, match := range matches {
			team1 := match.Team1.TeamName
			team2 := match.Team2.TeamName
			send := false

			if configuration.Whitelist {
				send = whitelisted(team1, team2, configuration.Teams)
			} else {
				send = true
			}

			// Prevent multiple notifications by checking time difference
			startTime, _ := strconv.Atoi(match.StarttimeUnix)
			delta := time.Now().Unix() - int64(startTime)
			if send && delta <= 60 {
				// Link points to stream but the stats page is nicer, so replace
				// with the stats URL instead
				url := strings.Replace(match.Link, "match", "stats", 1)
				notification := fmt.Sprintf("%s vs %s :: %s", team1, team2, url)
				sendNotification(notification, configuration.Webhook)
			}
		}
	}
}
<|endoftext|>


<commit_before>package shell

import (
	"context"
	"flag"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)

func init() {
	Commands = append(Commands, &commandS3BucketCreate{})
}

type commandS3BucketCreate struct {
}

func (c *commandS3BucketCreate) Name() string {
	return "s3.bucket.create"
}

func (c *commandS3BucketCreate) Help() string {
	return `create a bucket with a given name

	Example:
		s3.bucket.create -name <bucket_name> -replication 001
`
}

func (c *commandS3BucketCreate) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) {

	bucketCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
	bucketName := bucketCommand.String("name", "", "bucket name")
	replication := bucketCommand.String("replication", "", "replication setting for the bucket, if not set it will honor the setting defined by the filer or master")
	if err = bucketCommand.Parse(args); err != nil {
		return nil
	}

	if *bucketName == "" {
		return fmt.Errorf("empty bucket name")
	}

	err = commandEnv.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		resp, err := client.GetFilerConfiguration(context.Background(), &filer_pb.GetFilerConfigurationRequest{})
		if err != nil {
			return fmt.Errorf("get filer configuration: %v", err)
		}
		filerBucketsPath := resp.DirBuckets

		println("create bucket under", filerBucketsPath)

		entry := &filer_pb.Entry{
			Name:        *bucketName,
			IsDirectory: true,
			Attributes: &filer_pb.FuseAttributes{
				Mtime:       time.Now().Unix(),
				Crtime:      time.Now().Unix(),
				FileMode:    uint32(0777 | os.ModeDir),
				Collection:  *bucketName,
				Replication: *replication,
			},
		}

		if err := filer_pb.CreateEntry(client, &filer_pb.CreateEntryRequest{
			Directory: filerBucketsPath,
			Entry:     entry,
		}); err != nil {
			return err
		}

		println("created bucket", *bucketName)

		return nil

	})

	return err

}
<commit_msg>[shell] Clarify bucket replication setting order<commit_after>package shell

import (
	"context"
	"flag"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)

func init() {
	Commands = append(Commands, &commandS3BucketCreate{})
}

type commandS3BucketCreate struct {
}

func (c *commandS3BucketCreate) Name() string {
	return "s3.bucket.create"
}

func (c *commandS3BucketCreate) Help() string {
	return `create a bucket with a given name

	Example:
		s3.bucket.create -name <bucket_name> -replication 001
`
}

func (c *commandS3BucketCreate) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) {

	bucketCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
	bucketName := bucketCommand.String("name", "", "bucket name")
	replication := bucketCommand.String("replication", "", "replication setting for the bucket, if not set "+
		"it will honor the value defined by the filer if it exists, "+
		"else it will honor the value defined on the master")
	if err = bucketCommand.Parse(args); err != nil {
		return nil
	}

	if *bucketName == "" {
		return fmt.Errorf("empty bucket name")
	}

	err = commandEnv.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		resp, err := client.GetFilerConfiguration(context.Background(), &filer_pb.GetFilerConfigurationRequest{})
		if err != nil {
			return fmt.Errorf("get filer configuration: %v", err)
		}
		filerBucketsPath := resp.DirBuckets

		println("create bucket under", filerBucketsPath)

		entry := &filer_pb.Entry{
			Name:        *bucketName,
			IsDirectory: true,
			Attributes: &filer_pb.FuseAttributes{
				Mtime:       time.Now().Unix(),
				Crtime:      time.Now().Unix(),
				FileMode:    uint32(0777 | os.ModeDir),
				Collection:  *bucketName,
				Replication: *replication,
			},
		}

		if err := filer_pb.CreateEntry(client, &filer_pb.CreateEntryRequest{
			Directory: filerBucketsPath,
			Entry:     entry,
		}); err != nil {
			return err
		}

		println("created bucket", *bucketName)

		return nil

	})

	return err

}
<|endoftext|>


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

package syntax

// ----------------------------------------------------------------------------
// Nodes

type Node interface {
	Line() uint32
	aNode()
	init(p *parser)
}

type node struct {
	doc  *Comment // nil means no comment(s) attached
	pos  uint32
	line uint32
}

func (*node) aNode() {}

func (n *node) Line() uint32 {
	return n.line
}

func (n *node) init(p *parser) {
	n.pos = uint32(p.pos)
	n.line = uint32(p.line)
}

// ----------------------------------------------------------------------------
// Files

type File struct {
	PkgName  *Name
	DeclList []Decl
	Lines    int
	node
}

// ----------------------------------------------------------------------------
// Declarations

type (
	Decl interface {
		Node
		aDecl()
	}

	ImportDecl struct {
		LocalPkgName *Name // including "."; nil means no rename present
		Path         *BasicLit
		Group        *Group // nil means not part of a group
		decl
	}

	ConstDecl struct {
		NameList []*Name
		Type     Expr   // nil means no type
		Values   Expr   // nil means no values
		Group    *Group // nil means not part of a group
		decl
	}

	TypeDecl struct {
		Name   *Name
		Type   Expr
		Group  *Group // nil means not part of a group
		Pragma Pragma
		decl
	}

	VarDecl struct {
		NameList []*Name
		Type     Expr   // nil means no type
		Values   Expr   // nil means no values
		Group    *Group // nil means not part of a group
		decl
	}

	FuncDecl struct {
		Attr    map[string]bool // go:attr map
		Recv    *Field          // nil means regular function
		Name    *Name
		Type    *FuncType
		Body    []Stmt // nil means no body (forward declaration)
		Pragma  Pragma // TODO(mdempsky): Cleaner solution.
		EndLine uint32 // TODO(mdempsky): Cleaner solution.
		decl
	}
)

type decl struct{ node }

func (*decl) aDecl() {}

// All declarations belonging to the same group point to the same Group node.
type Group struct {
	dummy int // not empty so we are guaranteed different Group instances
}

// ----------------------------------------------------------------------------
// Expressions

type (
	Expr interface {
		Node
		aExpr()
	}

	// Value
	Name struct {
		Value string
		expr
	}

	// Value
	BasicLit struct {
		Value string
		Kind  LitKind
		expr
	}

	// Type { ElemList[0], ElemList[1], ... }
	CompositeLit struct {
		Type     Expr // nil means no literal type
		ElemList []Expr
		NKeys    int    // number of elements with keys
		EndLine  uint32 // TODO(mdempsky): Cleaner solution.
		expr
	}

	// Key: Value
	KeyValueExpr struct {
		Key, Value Expr
		expr
	}

	// func Type { Body }
	FuncLit struct {
		Type    *FuncType
		Body    []Stmt
		EndLine uint32 // TODO(mdempsky): Cleaner solution.
		expr
	}

	// (X)
	ParenExpr struct {
		X Expr
		expr
	}

	// X.Sel
	SelectorExpr struct {
		X   Expr
		Sel *Name
		expr
	}

	// X[Index]
	IndexExpr struct {
		X     Expr
		Index Expr
		expr
	}

	// X[Index[0] : Index[1] : Index[2]]
	SliceExpr struct {
		X     Expr
		Index [3]Expr
		// Full indicates whether this is a simple or full slice expression.
		// In a valid AST, this is equivalent to Index[2] != nil.
		// TODO(mdempsky): This is only needed to report the "3-index
		// slice of string" error when Index[2] is missing.
		Full bool
		expr
	}

	// X.(Type)
	AssertExpr struct {
		X Expr
		// TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
		Type Expr
		expr
	}

	Operation struct {
		Op   Operator
		X, Y Expr // Y == nil means unary expression
		expr
	}

	// Fun(ArgList[0], ArgList[1], ...)
	CallExpr struct {
		Fun     Expr
		ArgList []Expr
		HasDots bool // last argument is followed by ...
		expr
	}

	// ElemList[0], ElemList[1], ...
	ListExpr struct {
		ElemList []Expr
		expr
	}

	// [Len]Elem
	ArrayType struct {
		// TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
		Len  Expr // nil means Len is ...
		Elem Expr
		expr
	}

	// []Elem
	SliceType struct {
		Elem Expr
		expr
	}

	// ...Elem
	DotsType struct {
		Elem Expr
		expr
	}

	// struct { FieldList[0] TagList[0]; FieldList[1] TagList[1]; ... }
	StructType struct {
		FieldList []*Field
		TagList   []*BasicLit // i >= len(TagList) || TagList[i] == nil means no tag for field i
		expr
	}

	// Name Type
	//      Type
	Field struct {
		Name *Name // nil means anonymous field/parameter (structs/parameters), or embedded interface (interfaces)
		Type Expr  // field names declared in a list share the same Type (identical pointers)
		node
	}

	// interface { MethodList[0]; MethodList[1]; ... }
	InterfaceType struct {
		MethodList []*Field
		expr
	}

	FuncType struct {
		ParamList  []*Field
		ResultList []*Field
		expr
	}

	// map[Key]Value
	MapType struct {
		Key   Expr
		Value Expr
		expr
	}

	//   chan Elem
	// <-chan Elem
	// chan<- Elem
	ChanType struct {
		Dir  ChanDir // 0 means no direction
		Elem Expr
		expr
	}
)

type expr struct{ node }

func (*expr) aExpr() {}

type ChanDir uint

const (
	_ ChanDir = iota
	SendOnly
	RecvOnly
)

// ----------------------------------------------------------------------------
// Statements

type (
	Stmt interface {
		Node
		aStmt()
	}

	SimpleStmt interface {
		Stmt
		aSimpleStmt()
	}

	EmptyStmt struct {
		simpleStmt
	}

	LabeledStmt struct {
		Label *Name
		Stmt  Stmt
		stmt
	}

	BlockStmt struct {
		Body []Stmt
		stmt
	}

	ExprStmt struct {
		X Expr
		simpleStmt
	}

	SendStmt struct {
		Chan, Value Expr // Chan <- Value
		simpleStmt
	}

	DeclStmt struct {
		DeclList []Decl
		stmt
	}

	AssignStmt struct {
		Op       Operator // 0 means no operation
		Lhs, Rhs Expr     // Rhs == ImplicitOne means Lhs++ (Op == Add) or Lhs-- (Op == Sub)
		simpleStmt
	}

	BranchStmt struct {
		Tok   token // Break, Continue, Fallthrough, or Goto
		Label *Name
		stmt
	}

	CallStmt struct {
		Tok  token // Go or Defer
		Call *CallExpr
		stmt
	}

	ReturnStmt struct {
		Results Expr // nil means no explicit return values
		stmt
	}

	IfStmt struct {
		Init SimpleStmt
		Cond Expr
		Then []Stmt
		Else Stmt // either *IfStmt or *BlockStmt
		stmt
	}

	ForStmt struct {
		Init SimpleStmt // incl. *RangeClause
		Cond Expr
		Post SimpleStmt
		Body []Stmt
		stmt
	}

	SwitchStmt struct {
		Init SimpleStmt
		Tag  Expr
		Body []*CaseClause
		stmt
	}

	SelectStmt struct {
		Body []*CommClause
		stmt
	}
)

type (
	RangeClause struct {
		Lhs Expr // nil means no Lhs = or Lhs :=
		Def bool // means :=
		X   Expr // range X
		simpleStmt
	}

	TypeSwitchGuard struct {
		// TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
		Lhs *Name // nil means no Lhs :=
		X   Expr  // X.(type)
		expr
	}

	CaseClause struct {
		Cases Expr // nil means default clause
		Body  []Stmt
		node
	}

	CommClause struct {
		Comm SimpleStmt // send or receive stmt; nil means default clause
		Body []Stmt
		node
	}
)

type stmt struct{ node }

func (stmt) aStmt() {}

type simpleStmt struct {
	stmt
}

func (simpleStmt) aSimpleStmt() {}

// ----------------------------------------------------------------------------
// Comments

type CommentKind uint

const (
	Above CommentKind = iota
	Below
	Left
	Right
)

type Comment struct {
	Kind CommentKind
	Text string
	Next *Comment
}
<commit_msg>cmd/go/internal/syntax: reintroduce reverted comments<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package syntax

// ----------------------------------------------------------------------------
// Nodes

type Node interface {
	Line() uint32
	aNode()
	init(p *parser)
}

type node struct {
	doc  *Comment // nil means no comment(s) attached
	pos  uint32
	line uint32
}

func (*node) aNode() {}

func (n *node) Line() uint32 {
	return n.line
}

func (n *node) init(p *parser) {
	n.pos = uint32(p.pos)
	n.line = uint32(p.line)
}

// ----------------------------------------------------------------------------
// Files

// package PkgName; DeclList[0], DeclList[1], ...
type File struct {
	PkgName  *Name
	DeclList []Decl
	Lines    int
	node
}

// ----------------------------------------------------------------------------
// Declarations

type (
	Decl interface {
		Node
		aDecl()
	}

	//              Path
	// LocalPkgName Path
	ImportDecl struct {
		LocalPkgName *Name // including "."; nil means no rename present
		Path         *BasicLit
		Group        *Group // nil means not part of a group
		decl
	}

	// NameList
	// NameList      = Values
	// NameList Type = Values
	ConstDecl struct {
		NameList []*Name
		Type     Expr   // nil means no type
		Values   Expr   // nil means no values
		Group    *Group // nil means not part of a group
		decl
	}

	// Name Type
	TypeDecl struct {
		Name   *Name
		Type   Expr
		Group  *Group // nil means not part of a group
		Pragma Pragma
		decl
	}

	// NameList Type
	// NameList Type = Values
	// NameList      = Values
	VarDecl struct {
		NameList []*Name
		Type     Expr   // nil means no type
		Values   Expr   // nil means no values
		Group    *Group // nil means not part of a group
		decl
	}

	// func          Name Type { Body }
	// func          Name Type
	// func Receiver Name Type { Body }
	// func Receiver Name Type
	FuncDecl struct {
		Attr    map[string]bool // go:attr map
		Recv    *Field          // nil means regular function
		Name    *Name
		Type    *FuncType
		Body    []Stmt // nil means no body (forward declaration)
		Pragma  Pragma // TODO(mdempsky): Cleaner solution.
		EndLine uint32 // TODO(mdempsky): Cleaner solution.
		decl
	}
)

type decl struct{ node }

func (*decl) aDecl() {}

// All declarations belonging to the same group point to the same Group node.
type Group struct {
	dummy int // not empty so we are guaranteed different Group instances
}

// ----------------------------------------------------------------------------
// Expressions

type (
	Expr interface {
		Node
		aExpr()
	}

	// Value
	Name struct {
		Value string
		expr
	}

	// Value
	BasicLit struct {
		Value string
		Kind  LitKind
		expr
	}

	// Type { ElemList[0], ElemList[1], ... }
	CompositeLit struct {
		Type     Expr // nil means no literal type
		ElemList []Expr
		NKeys    int    // number of elements with keys
		EndLine  uint32 // TODO(mdempsky): Cleaner solution.
		expr
	}

	// Key: Value
	KeyValueExpr struct {
		Key, Value Expr
		expr
	}

	// func Type { Body }
	FuncLit struct {
		Type    *FuncType
		Body    []Stmt
		EndLine uint32 // TODO(mdempsky): Cleaner solution.
		expr
	}

	// (X)
	ParenExpr struct {
		X Expr
		expr
	}

	// X.Sel
	SelectorExpr struct {
		X   Expr
		Sel *Name
		expr
	}

	// X[Index]
	IndexExpr struct {
		X     Expr
		Index Expr
		expr
	}

	// X[Index[0] : Index[1] : Index[2]]
	SliceExpr struct {
		X     Expr
		Index [3]Expr
		// Full indicates whether this is a simple or full slice expression.
		// In a valid AST, this is equivalent to Index[2] != nil.
		// TODO(mdempsky): This is only needed to report the "3-index
		// slice of string" error when Index[2] is missing.
		Full bool
		expr
	}

	// X.(Type)
	AssertExpr struct {
		X Expr
		// TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
		Type Expr
		expr
	}

	Operation struct {
		Op   Operator
		X, Y Expr // Y == nil means unary expression
		expr
	}

	// Fun(ArgList[0], ArgList[1], ...)
	CallExpr struct {
		Fun     Expr
		ArgList []Expr
		HasDots bool // last argument is followed by ...
		expr
	}

	// ElemList[0], ElemList[1], ...
	ListExpr struct {
		ElemList []Expr
		expr
	}

	// [Len]Elem
	ArrayType struct {
		// TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
		Len  Expr // nil means Len is ...
		Elem Expr
		expr
	}

	// []Elem
	SliceType struct {
		Elem Expr
		expr
	}

	// ...Elem
	DotsType struct {
		Elem Expr
		expr
	}

	// struct { FieldList[0] TagList[0]; FieldList[1] TagList[1]; ... }
	StructType struct {
		FieldList []*Field
		TagList   []*BasicLit // i >= len(TagList) || TagList[i] == nil means no tag for field i
		expr
	}

	// Name Type
	//      Type
	Field struct {
		Name *Name // nil means anonymous field/parameter (structs/parameters), or embedded interface (interfaces)
		Type Expr  // field names declared in a list share the same Type (identical pointers)
		node
	}

	// interface { MethodList[0]; MethodList[1]; ... }
	InterfaceType struct {
		MethodList []*Field
		expr
	}

	FuncType struct {
		ParamList  []*Field
		ResultList []*Field
		expr
	}

	// map[Key]Value
	MapType struct {
		Key   Expr
		Value Expr
		expr
	}

	//   chan Elem
	// <-chan Elem
	// chan<- Elem
	ChanType struct {
		Dir  ChanDir // 0 means no direction
		Elem Expr
		expr
	}
)

type expr struct{ node }

func (*expr) aExpr() {}

type ChanDir uint

const (
	_ ChanDir = iota
	SendOnly
	RecvOnly
)

// ----------------------------------------------------------------------------
// Statements

type (
	Stmt interface {
		Node
		aStmt()
	}

	SimpleStmt interface {
		Stmt
		aSimpleStmt()
	}

	EmptyStmt struct {
		simpleStmt
	}

	LabeledStmt struct {
		Label *Name
		Stmt  Stmt
		stmt
	}

	BlockStmt struct {
		Body []Stmt
		stmt
	}

	ExprStmt struct {
		X Expr
		simpleStmt
	}

	SendStmt struct {
		Chan, Value Expr // Chan <- Value
		simpleStmt
	}

	DeclStmt struct {
		DeclList []Decl
		stmt
	}

	AssignStmt struct {
		Op       Operator // 0 means no operation
		Lhs, Rhs Expr     // Rhs == ImplicitOne means Lhs++ (Op == Add) or Lhs-- (Op == Sub)
		simpleStmt
	}

	BranchStmt struct {
		Tok   token // Break, Continue, Fallthrough, or Goto
		Label *Name
		stmt
	}

	CallStmt struct {
		Tok  token // Go or Defer
		Call *CallExpr
		stmt
	}

	ReturnStmt struct {
		Results Expr // nil means no explicit return values
		stmt
	}

	IfStmt struct {
		Init SimpleStmt
		Cond Expr
		Then []Stmt
		Else Stmt // either *IfStmt or *BlockStmt
		stmt
	}

	ForStmt struct {
		Init SimpleStmt // incl. *RangeClause
		Cond Expr
		Post SimpleStmt
		Body []Stmt
		stmt
	}

	SwitchStmt struct {
		Init SimpleStmt
		Tag  Expr
		Body []*CaseClause
		stmt
	}

	SelectStmt struct {
		Body []*CommClause
		stmt
	}
)

type (
	RangeClause struct {
		Lhs Expr // nil means no Lhs = or Lhs :=
		Def bool // means :=
		X   Expr // range X
		simpleStmt
	}

	TypeSwitchGuard struct {
		// TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
		Lhs *Name // nil means no Lhs :=
		X   Expr  // X.(type)
		expr
	}

	CaseClause struct {
		Cases Expr // nil means default clause
		Body  []Stmt
		node
	}

	CommClause struct {
		Comm SimpleStmt // send or receive stmt; nil means default clause
		Body []Stmt
		node
	}
)

type stmt struct{ node }

func (stmt) aStmt() {}

type simpleStmt struct {
	stmt
}

func (simpleStmt) aSimpleStmt() {}

// ----------------------------------------------------------------------------
// Comments

// TODO(gri) Consider renaming to CommentPos, CommentPlacement, etc.
//           Kind = Above doesn't make much sense.
type CommentKind uint

const (
	Above CommentKind = iota
	Below
	Left
	Right
)

type Comment struct {
	Kind CommentKind
	Text string
	Next *Comment
}
<|endoftext|>


<commit_before>package common

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ssm"
	"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
	"github.com/hashicorp/packer/common/retry"
	"github.com/mitchellh/iochan"
)

const (
	sessionManagerPluginName string = "session-manager-plugin"

	//sessionCommand is the AWS-SDK equivalent to the command you would specify to `aws ssm ...`
	sessionCommand string = "StartSession"
)

type SSMDriverConfig struct {
	SvcClient   ssmiface.SSMAPI
	Region      string
	ProfileName string
	SvcEndpoint string
}

type SSMDriver struct {
	SSMDriverConfig
	session       *ssm.StartSessionOutput
	sessionParams ssm.StartSessionInput
	pluginCmdFunc func(context.Context) error

	retryConnection chan bool
	wg              sync.WaitGroup
}

func NewSSMDriver(config SSMDriverConfig) *SSMDriver {
	d := SSMDriver{SSMDriverConfig: config}
	return &d
}

// StartSession starts an interactive Systems Manager session with a remote instance via the AWS session-manager-plugin
// This ssm.StartSessionOutput returned by this function can be used for terminating the session manually. If you do
// not wish to manage the session manually calling StopSession on a instance of this driver will terminate the active session
// created from calling StartSession.
func (d *SSMDriver) StartSession(ctx context.Context, input ssm.StartSessionInput) (*ssm.StartSessionOutput, error) {
	d.wg.Add(1)
	defer d.wg.Done()
	log.Printf("Starting PortForwarding session to instance %q", aws.StringValue(input.Target))

	var output *ssm.StartSessionOutput
	err := retry.Config{
		ShouldRetry: func(err error) bool { return IsAWSErr(err, "TargetNotConnected", "") },
		RetryDelay:  (&retry.Backoff{InitialBackoff: 200 * time.Millisecond, MaxBackoff: 60 * time.Second, Multiplier: 2}).Linear,
	}.Run(ctx, func(ctx context.Context) (err error) {
		output, err = d.SvcClient.StartSessionWithContext(ctx, &input)
		return err
	})
	if err != nil {
		return nil, fmt.Errorf("error encountered in starting session for instance %q: %s", aws.StringValue(input.Target), err)
	}

	d.retryConnection = make(chan bool, 1)
	// Starts go routine that will keep listening to a retry channel and retry the session creation when needed.
	// The log loop will add data to the retry channel whenever a retryable error happens to session.
	// TODO @sylviamoss add max retry attempts
	// TODO @sylviamoss zero retry times
	go func(ctx context.Context, driver *SSMDriver, input ssm.StartSessionInput) {
		retryTimes := 0
		for {
			select {
			case <-ctx.Done():
				return
			case <-driver.retryConnection:
				if retryTimes <= 11 {
					retryTimes++
					d.wg.Wait()
					_, err := driver.StartSession(ctx, input)
					if err != nil {
						return
					}
				}
			}
		}
	}(ctx, d, input)

	d.session = output
	d.sessionParams = input

	if d.pluginCmdFunc == nil {
		d.pluginCmdFunc = d.openTunnelForSession
	}

	if err := d.pluginCmdFunc(ctx); err != nil {
		return nil, fmt.Errorf("error encountered in starting session for instance %q: %s", aws.StringValue(input.Target), err)
	}

	return d.session, nil
}

func (d *SSMDriver) openTunnelForSession(ctx context.Context) error {
	args, err := d.Args()
	if err != nil {
		return fmt.Errorf("error encountered validating session details: %s", err)
	}

	cmd := exec.CommandContext(ctx, sessionManagerPluginName, args...)

	// Let's build up our logging
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	// Create the channels we'll use for data
	stdoutCh := iochan.DelimReader(stdout, '\n')
	stderrCh := iochan.DelimReader(stderr, '\n')

	/* Loop and get all our output
	This particular logger will continue to run through an entire Packer run.
	The decision to continue logging is due to the fact that session-manager-plugin
	doesn't give a good way of knowing if the command failed or was successful other
	than looking at the logs. Seeing as the plugin is updated frequently and that the
	log information is a bit sparse this logger will indefinitely relying on other
	steps to fail if the tunnel is unable to be created. If successful then the user
	will get more information on the tunnel connection when running in a debug mode.
	*/
	go func(ctx context.Context, prefix string) {
		for {
			select {
			case <-ctx.Done():
				return
			case output, ok := <-stderrCh:
				if !ok {
					stderrCh = nil
					break
				}

				if output != "" {
					log.Printf("[ERROR] %s: %s", prefix, output)
					if isRetryableError(output) {
						d.retryConnection <- true
					}
				}
			case output, ok := <-stdoutCh:
				if !ok {
					stdoutCh = nil
					break
				}

				if output != "" {
					log.Printf("[DEBUG] %s: %s", prefix, output)
				}
			}

			if stdoutCh == nil && stderrCh == nil {
				log.Printf("[DEBUG] %s: %s", prefix, "active session has been terminated; stopping all log polling processes.")
				return
			}
		}
	}(ctx, sessionManagerPluginName)

	log.Printf("[DEBUG %s] opening session tunnel to instance %q for session %q", sessionManagerPluginName,
		aws.StringValue(d.sessionParams.Target),
		aws.StringValue(d.session.SessionId),
	)

	if err := cmd.Start(); err != nil {
		err = fmt.Errorf("error encountered when calling %s: %s\n", sessionManagerPluginName, err)
		return err
	}

	return nil
}

func isRetryableError(output string) bool {
	retryableError := []string{
		"Unable to connect to specified port",
	}

	for _, err := range retryableError {
		if strings.Contains(output, err) {
			return true
		}
	}
	return false
}

// StopSession terminates an active Session Manager session
func (d *SSMDriver) StopSession() error {
	d.wg.Add(1)
	defer d.wg.Done()

	if d.retryConnection != nil {
		close(d.retryConnection)
	}

	if d.session == nil || d.session.SessionId == nil {
		return fmt.Errorf("Unable to find a valid session to instance %q; skipping the termination step",
			aws.StringValue(d.sessionParams.Target))
	}

	_, err := d.SvcClient.TerminateSession(&ssm.TerminateSessionInput{SessionId: d.session.SessionId})
	if err != nil {
		err = fmt.Errorf("Error terminating SSM Session %q. Please terminate the session manually: %s", aws.StringValue(d.session.SessionId), err)
	}
	return err
}

// Args validates the driver inputs before returning an ordered set of arguments to pass to the driver command.
func (d *SSMDriver) Args() ([]string, error) {
	if d.session == nil {
		return nil, fmt.Errorf("an active Amazon SSM Session is required before trying to open a session tunnel")
	}

	// AWS session-manager-plugin requires a valid session be passed in JSON.
	sessionDetails, err := json.Marshal(d.session)
	if err != nil {
		return nil, fmt.Errorf("error encountered in reading session details %s", err)
	}

	// AWS session-manager-plugin requires the parameters used in the session to be passed in JSON as well.
	sessionParameters, err := json.Marshal(d.sessionParams)
	if err != nil {
		return nil, fmt.Errorf("error encountered in reading session parameter details %s", err)
	}

	// Args must be in this order
	args := []string{
		string(sessionDetails),
		d.Region,
		sessionCommand,
		d.ProfileName,
		string(sessionParameters),
		d.SvcEndpoint,
	}

	return args, nil
}
<commit_msg>improve logs<commit_after>package common

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ssm"
	"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
	"github.com/hashicorp/packer/common/retry"
	"github.com/mitchellh/iochan"
)

const (
	sessionManagerPluginName string = "session-manager-plugin"

	//sessionCommand is the AWS-SDK equivalent to the command you would specify to `aws ssm ...`
	sessionCommand string = "StartSession"
)

type SSMDriverConfig struct {
	SvcClient   ssmiface.SSMAPI
	Region      string
	ProfileName string
	SvcEndpoint string
}

type SSMDriver struct {
	SSMDriverConfig
	session       *ssm.StartSessionOutput
	sessionParams ssm.StartSessionInput
	pluginCmdFunc func(context.Context) error

	retryConnection chan bool
	wg              sync.WaitGroup
}

func NewSSMDriver(config SSMDriverConfig) *SSMDriver {
	d := SSMDriver{SSMDriverConfig: config}
	return &d
}

// StartSession starts an interactive Systems Manager session with a remote instance via the AWS session-manager-plugin
// This ssm.StartSessionOutput returned by this function can be used for terminating the session manually. If you do
// not wish to manage the session manually calling StopSession on a instance of this driver will terminate the active session
// created from calling StartSession.
func (d *SSMDriver) StartSession(ctx context.Context, input ssm.StartSessionInput) (*ssm.StartSessionOutput, error) {
	d.wg.Add(1)
	defer d.wg.Done()
	log.Printf("Starting PortForwarding session to instance %q", aws.StringValue(input.Target))

	var output *ssm.StartSessionOutput
	err := retry.Config{
		ShouldRetry: func(err error) bool { return IsAWSErr(err, "TargetNotConnected", "") },
		RetryDelay:  (&retry.Backoff{InitialBackoff: 200 * time.Millisecond, MaxBackoff: 60 * time.Second, Multiplier: 2}).Linear,
	}.Run(ctx, func(ctx context.Context) (err error) {
		output, err = d.SvcClient.StartSessionWithContext(ctx, &input)
		return err
	})
	if err != nil {
		return nil, fmt.Errorf("error encountered in starting session for instance %q: %s", aws.StringValue(input.Target), err)
	}

	d.retryConnection = make(chan bool, 1)
	// Starts go routine that will keep listening to a retry channel and retry the session creation when needed.
	// The log loop will add data to the retry channel whenever a retryable error happens to session.
	go func(ctx context.Context, driver *SSMDriver, input ssm.StartSessionInput) {
		for {
			select {
			case <-ctx.Done():
				return
			case <-driver.retryConnection:
				d.wg.Wait()
				log.Printf("[DEBUG] Retrying to establish SSM connection")
				_, err := driver.StartSession(ctx, input)
				if err != nil {
					return
				}
			}
		}
	}(ctx, d, input)

	d.session = output
	d.sessionParams = input

	if d.pluginCmdFunc == nil {
		d.pluginCmdFunc = d.openTunnelForSession
	}

	if err := d.pluginCmdFunc(ctx); err != nil {
		return nil, fmt.Errorf("error encountered in starting session for instance %q: %s", aws.StringValue(input.Target), err)
	}

	return d.session, nil
}

func (d *SSMDriver) openTunnelForSession(ctx context.Context) error {
	args, err := d.Args()
	if err != nil {
		return fmt.Errorf("error encountered validating session details: %s", err)
	}

	cmd := exec.CommandContext(ctx, sessionManagerPluginName, args...)

	// Let's build up our logging
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	// Create the channels we'll use for data
	stdoutCh := iochan.DelimReader(stdout, '\n')
	stderrCh := iochan.DelimReader(stderr, '\n')

	/* Loop and get all our output
	This particular logger will continue to run through an entire Packer run.
	The decision to continue logging is due to the fact that session-manager-plugin
	doesn't give a good way of knowing if the command failed or was successful other
	than looking at the logs. Seeing as the plugin is updated frequently and that the
	log information is a bit sparse this logger will indefinitely relying on other
	steps to fail if the tunnel is unable to be created. If successful then the user
	will get more information on the tunnel connection when running in a debug mode.
	*/
	go func(ctx context.Context, prefix string) {
		for {
			select {
			case <-ctx.Done():
				return
			case output, ok := <-stderrCh:
				if !ok {
					stderrCh = nil
					break
				}

				if output != "" {
					if isRetryableError(output) {
						log.Printf("[ERROR] Retryable error - %s: %s", prefix, output)
						d.retryConnection <- true
					} else {
						log.Printf("[ERROR] %s: %s", prefix, output)
					}
				}
			case output, ok := <-stdoutCh:
				if !ok {
					stdoutCh = nil
					break
				}

				if output != "" {
					log.Printf("[DEBUG] %s: %s", prefix, output)
				}
			}

			if stdoutCh == nil && stderrCh == nil {
				log.Printf("[DEBUG] %s: %s", prefix, "active session has been terminated; stopping all log polling processes.")
				return
			}
		}
	}(ctx, sessionManagerPluginName)

	log.Printf("[DEBUG %s] opening session tunnel to instance %q for session %q", sessionManagerPluginName,
		aws.StringValue(d.sessionParams.Target),
		aws.StringValue(d.session.SessionId),
	)

	if err := cmd.Start(); err != nil {
		err = fmt.Errorf("error encountered when calling %s: %s\n", sessionManagerPluginName, err)
		return err
	}

	return nil
}

func isRetryableError(output string) bool {
	retryableError := []string{
		"connection refused",
	}
	for _, err := range retryableError {
		if strings.Contains(output, err) {
			return true
		}
	}
	return false
}

// StopSession terminates an active Session Manager session
func (d *SSMDriver) StopSession() error {
	d.wg.Add(1)
	defer d.wg.Done()

	if d.retryConnection != nil {
		close(d.retryConnection)
	}

	if d.session == nil || d.session.SessionId == nil {
		return fmt.Errorf("Unable to find a valid session to instance %q; skipping the termination step",
			aws.StringValue(d.sessionParams.Target))
	}

	_, err := d.SvcClient.TerminateSession(&ssm.TerminateSessionInput{SessionId: d.session.SessionId})
	if err != nil {
		err = fmt.Errorf("Error terminating SSM Session %q. Please terminate the session manually: %s", aws.StringValue(d.session.SessionId), err)
	}
	return err
}

// Args validates the driver inputs before returning an ordered set of arguments to pass to the driver command.
func (d *SSMDriver) Args() ([]string, error) {
	if d.session == nil {
		return nil, fmt.Errorf("an active Amazon SSM Session is required before trying to open a session tunnel")
	}

	// AWS session-manager-plugin requires a valid session be passed in JSON.
	sessionDetails, err := json.Marshal(d.session)
	if err != nil {
		return nil, fmt.Errorf("error encountered in reading session details %s", err)
	}

	// AWS session-manager-plugin requires the parameters used in the session to be passed in JSON as well.
	sessionParameters, err := json.Marshal(d.sessionParams)
	if err != nil {
		return nil, fmt.Errorf("error encountered in reading session parameter details %s", err)
	}

	// Args must be in this order
	args := []string{
		string(sessionDetails),
		d.Region,
		sessionCommand,
		d.ProfileName,
		string(sessionParameters),
		d.SvcEndpoint,
	}

	return args, nil
}
<|endoftext|>


<commit_before>// The bsusurrogate package contains a packer.Builder implementation that
// builds a new EBS-backed OMI using an ephemeral instance.
package bsusurrogate

import (
	"errors"
	"fmt"
	"log"

	osccommon "github.com/hashicorp/packer/builder/osc/common"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
)

const BuilderId = "digitalonus.osc.bsusurrogate"

type Config struct {
	common.PackerConfig    `mapstructure:",squash"`
	osccommon.AccessConfig `mapstructure:",squash"`
	osccommon.RunConfig    `mapstructure:",squash"`
	osccommon.BlockDevices `mapstructure:",squash"`
	osccommon.OMIConfig    `mapstructure:",squash"`

	RootDevice    RootBlockDevice  `mapstructure:"ami_root_device"`
	VolumeRunTags osccommon.TagMap `mapstructure:"run_volume_tags"`

	ctx interpolate.Context
}

type Builder struct {
	config Config
	runner multistep.Runner
}

func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
	b.config.ctx.Funcs = osccommon.TemplateFuncs

	err := config.Decode(&b.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &b.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"omi_description",
				"run_tags",
				"run_volume_tags",
				"snapshot_tags",
				"spot_tags",
				"tags",
			},
		},
	}, raws...)
	if err != nil {
		return nil, err
	}

	if b.config.PackerConfig.PackerForce {
		b.config.OMIForceDeregister = true
	}

	// Accumulate any errors
	var errs *packer.MultiError
	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs,
		b.config.OMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.RootDevice.Prepare(&b.config.ctx)...)

	if b.config.OMIVirtType == "" {
		errs = packer.MultiErrorAppend(errs, errors.New("ami_virtualization_type is required."))
	}

	foundRootVolume := false
	for _, launchDevice := range b.config.BlockDevices.LaunchMappings {
		if launchDevice.DeviceName == b.config.RootDevice.SourceDeviceName {
			foundRootVolume = true
		}
	}

	if !foundRootVolume {
		errs = packer.MultiErrorAppend(errs, fmt.Errorf("no volume with name '%s' is found", b.config.RootDevice.SourceDeviceName))
	}

	//TODO: Chek if this is necessary
	if b.config.IsSpotVm() && ((b.config.OMIENASupport != nil && *b.config.OMIENASupport) || b.config.OMISriovNetSupport) {
		errs = packer.MultiErrorAppend(errs,
			fmt.Errorf("Spot instances do not support modification, which is required "+
				"when either `ena_support` or `sriov_support` are set. Please ensure "+
				"you use an OMI that already has either SR-IOV or ENA enabled."))
	}

	if errs != nil && len(errs.Errors) > 0 {
		return nil, errs
	}

	packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
	return nil, nil

}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	log.Println("Running Outscale Builder...")
	return nil, nil
}

func (b *Builder) Cancel() {
	if b.runner != nil {
		log.Println("Cancelling the step runner...")
		b.runner.Cancel()
	}
}
<commit_msg>chore: add Bsusurrogate Run function skeleton<commit_after>// The bsusurrogate package contains a packer.Builder implementation that
// builds a new EBS-backed OMI using an ephemeral instance.
package bsusurrogate

import (
	"crypto/tls"
	"errors"
	"fmt"
	"log"
	"net/http"

	osccommon "github.com/hashicorp/packer/builder/osc/common"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/outscale/osc-go/oapi"
)

const BuilderId = "digitalonus.osc.bsusurrogate"

type Config struct {
	common.PackerConfig    `mapstructure:",squash"`
	osccommon.AccessConfig `mapstructure:",squash"`
	osccommon.RunConfig    `mapstructure:",squash"`
	osccommon.BlockDevices `mapstructure:",squash"`
	osccommon.OMIConfig    `mapstructure:",squash"`

	RootDevice    RootBlockDevice  `mapstructure:"ami_root_device"`
	VolumeRunTags osccommon.TagMap `mapstructure:"run_volume_tags"`

	ctx interpolate.Context
}

type Builder struct {
	config Config
	runner multistep.Runner
}

func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
	b.config.ctx.Funcs = osccommon.TemplateFuncs

	err := config.Decode(&b.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &b.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"omi_description",
				"run_tags",
				"run_volume_tags",
				"snapshot_tags",
				"spot_tags",
				"tags",
			},
		},
	}, raws...)
	if err != nil {
		return nil, err
	}

	if b.config.PackerConfig.PackerForce {
		b.config.OMIForceDeregister = true
	}

	// Accumulate any errors
	var errs *packer.MultiError
	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs,
		b.config.OMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.RootDevice.Prepare(&b.config.ctx)...)

	if b.config.OMIVirtType == "" {
		errs = packer.MultiErrorAppend(errs, errors.New("ami_virtualization_type is required."))
	}

	foundRootVolume := false
	for _, launchDevice := range b.config.BlockDevices.LaunchMappings {
		if launchDevice.DeviceName == b.config.RootDevice.SourceDeviceName {
			foundRootVolume = true
		}
	}

	if !foundRootVolume {
		errs = packer.MultiErrorAppend(errs, fmt.Errorf("no volume with name '%s' is found", b.config.RootDevice.SourceDeviceName))
	}

	//TODO: Chek if this is necessary
	if b.config.IsSpotVm() && ((b.config.OMIENASupport != nil && *b.config.OMIENASupport) || b.config.OMISriovNetSupport) {
		errs = packer.MultiErrorAppend(errs,
			fmt.Errorf("Spot instances do not support modification, which is required "+
				"when either `ena_support` or `sriov_support` are set. Please ensure "+
				"you use an OMI that already has either SR-IOV or ENA enabled."))
	}

	if errs != nil && len(errs.Errors) > 0 {
		return nil, errs
	}

	packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
	return nil, nil

}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	clientConfig, err := b.config.Config()
	if err != nil {
		return nil, err
	}

	skipClient := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	oapiconn := oapi.NewClient(clientConfig, skipClient)

	// Setup the state bag and initial state for the steps
	state := new(multistep.BasicStateBag)
	state.Put("config", &b.config)
	state.Put("oapi", oapiconn)
	state.Put("clientConfig", clientConfig)
	state.Put("hook", hook)
	state.Put("ui", ui)

	steps := []multistep.Step{}

	b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
	b.runner.Run(state)

	return nil, nil
}

func (b *Builder) Cancel() {
	if b.runner != nil {
		log.Println("Cancelling the step runner...")
		b.runner.Cancel()
	}
}
<|endoftext|>


<commit_before>package vm

import (
	"fmt"
	"math/big"
)

func newstack() *stack {
	return &stack{}
}

type stack struct {
	data []*big.Int
	ptr  int
}

func (st *stack) Data() []*big.Int {
	return st.data
}

func (st *stack) push(d *big.Int) {
	// NOTE push limit (1024) is checked in baseCheck
	stackItem := new(big.Int).Set(d)
	if len(st.data) > st.ptr {
		st.data[st.ptr] = stackItem
	} else {
		st.data = append(st.data, stackItem)
	}
	st.ptr++
}

func (st *stack) pop() (ret *big.Int) {
	st.ptr--
	ret = st.data[st.ptr]
	return
}

func (st *stack) len() int {
	return st.ptr
}

func (st *stack) swap(n int) {
	st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]
}

func (st *stack) dup(n int) {
	st.push(st.data[st.len()-n])
}

func (st *stack) peek() *big.Int {
	return st.data[st.len()-1]
}

func (st *stack) require(n int) error {
	if st.len() < n {
		return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
	}
	return nil
}

func (st *stack) Print() {
	fmt.Println("### stack ###")
	if len(st.data) > 0 {
		for i, val := range st.data {
			fmt.Printf("%-3d  %v\n", i, val)
		}
	} else {
		fmt.Println("-- empty --")
	}
	fmt.Println("#############")
}
<commit_msg>core/vm: fixed a bug where `Data` ignored the stack ptr<commit_after>package vm

import (
	"fmt"
	"math/big"
)

func newstack() *stack {
	return &stack{}
}

type stack struct {
	data []*big.Int
	ptr  int
}

func (st *stack) Data() []*big.Int {
	return st.data[:st.ptr]
}

func (st *stack) push(d *big.Int) {
	// NOTE push limit (1024) is checked in baseCheck
	stackItem := new(big.Int).Set(d)
	if len(st.data) > st.ptr {
		st.data[st.ptr] = stackItem
	} else {
		st.data = append(st.data, stackItem)
	}
	st.ptr++
}

func (st *stack) pop() (ret *big.Int) {
	st.ptr--
	ret = st.data[st.ptr]
	return
}

func (st *stack) len() int {
	return st.ptr
}

func (st *stack) swap(n int) {
	st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]
}

func (st *stack) dup(n int) {
	st.push(st.data[st.len()-n])
}

func (st *stack) peek() *big.Int {
	return st.data[st.len()-1]
}

func (st *stack) require(n int) error {
	if st.len() < n {
		return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
	}
	return nil
}

func (st *stack) Print() {
	fmt.Println("### stack ###")
	if len(st.data) > 0 {
		for i, val := range st.data {
			fmt.Printf("%-3d  %v\n", i, val)
		}
	} else {
		fmt.Println("-- empty --")
	}
	fmt.Println("#############")
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"net"
	"time"

	"github.com/ncodes/cocoon/core/config"
	"github.com/ncodes/cocoon/core/connector/connector"
	"github.com/ncodes/cocoon/core/connector/server/handlers"
	"github.com/ncodes/cocoon/core/connector/server/proto_connector"
	logging "github.com/op/go-logging"
	context "golang.org/x/net/context"
	"google.golang.org/grpc"
)

var log *logging.Logger

// RPC defines a grpc server for
// invoking a cocoon code
type RPC struct {
	server        *grpc.Server
	connector     *connector.Connector
	ledgerOps     *handlers.LedgerOperations
	cocoonCodeOps *handlers.CocoonCodeOperations
	lockOps       *handlers.LockOperations
}

// NewRPC creates a new grpc API server
func NewRPC(connector *connector.Connector) *RPC {
	log = config.MakeLogger("connector.rpc", "")
	server := new(RPC)
	server.connector = connector
	server.ledgerOps = handlers.NewLedgerOperationHandler(log, connector)
	server.cocoonCodeOps = handlers.NewCocoonCodeHandler("127.0.0.1" + connector.GetCocoonCodeRPCAddr())
	server.lockOps = handlers.NewLockOperationHandler(log, connector)
	return server
}

// GetConnector returns the connector
func (rpc *RPC) GetConnector() *connector.Connector {
	return rpc.connector
}

// Start starts the API service
func (rpc *RPC) Start(addr string, startedCh chan bool) {

	_, port, _ := net.SplitHostPort(addr)

	lis, err := net.Listen("tcp", fmt.Sprintf("%s", addr))
	if err != nil {
		log.Fatalf("failed to listen on port=%s. Err: %s", port, err)
	}

	time.AfterFunc(2*time.Second, func() {
		log.Infof("Started GRPC API server @ %s", addr)
		startedCh <- true
		time.Sleep(1 * time.Second)
	})

	rpc.server = grpc.NewServer()
	proto_connector.RegisterConnectorServer(rpc.server, rpc)
	rpc.server.Serve(lis)
}

// Stop stops the server
func (rpc *RPC) Stop() {
	if rpc.server != nil {
		rpc.server.Stop()
	}
}

// Transact handles cocoon code or ledger bound transactions.
func (rpc *RPC) Transact(ctx context.Context, req *proto_connector.Request) (*proto_connector.Response, error) {
	switch req.OpType {
	case proto_connector.OpType_LedgerOp:
		return rpc.ledgerOps.Handle(ctx, req.LedgerOp)
	case proto_connector.OpType_LockOp:
		return rpc.lockOps.Handle(ctx, req.LockOp)
	default:
		return nil, fmt.Errorf("unsupported operation type")
	}
}
<commit_msg>Remove loopback<commit_after>package server

import (
	"fmt"
	"net"
	"time"

	"github.com/ncodes/cocoon/core/config"
	"github.com/ncodes/cocoon/core/connector/connector"
	"github.com/ncodes/cocoon/core/connector/server/handlers"
	"github.com/ncodes/cocoon/core/connector/server/proto_connector"
	logging "github.com/op/go-logging"
	context "golang.org/x/net/context"
	"google.golang.org/grpc"
)

var log *logging.Logger

// RPC defines a grpc server for
// invoking a cocoon code
type RPC struct {
	server        *grpc.Server
	connector     *connector.Connector
	ledgerOps     *handlers.LedgerOperations
	cocoonCodeOps *handlers.CocoonCodeOperations
	lockOps       *handlers.LockOperations
}

// NewRPC creates a new grpc API server
func NewRPC(connector *connector.Connector) *RPC {
	log = config.MakeLogger("connector.rpc", "")
	server := new(RPC)
	server.connector = connector
	server.ledgerOps = handlers.NewLedgerOperationHandler(log, connector)
	server.cocoonCodeOps = handlers.NewCocoonCodeHandler(connector.GetCocoonCodeRPCAddr())
	server.lockOps = handlers.NewLockOperationHandler(log, connector)
	return server
}

// GetConnector returns the connector
func (rpc *RPC) GetConnector() *connector.Connector {
	return rpc.connector
}

// Start starts the API service
func (rpc *RPC) Start(addr string, startedCh chan bool) {

	_, port, _ := net.SplitHostPort(addr)

	lis, err := net.Listen("tcp", fmt.Sprintf("%s", addr))
	if err != nil {
		log.Fatalf("failed to listen on port=%s. Err: %s", port, err)
	}

	time.AfterFunc(2*time.Second, func() {
		log.Infof("Started GRPC API server @ %s", addr)
		startedCh <- true
		time.Sleep(1 * time.Second)
	})

	rpc.server = grpc.NewServer()
	proto_connector.RegisterConnectorServer(rpc.server, rpc)
	rpc.server.Serve(lis)
}

// Stop stops the server
func (rpc *RPC) Stop() {
	if rpc.server != nil {
		rpc.server.Stop()
	}
}

// Transact handles cocoon code or ledger bound transactions.
func (rpc *RPC) Transact(ctx context.Context, req *proto_connector.Request) (*proto_connector.Response, error) {
	switch req.OpType {
	case proto_connector.OpType_LedgerOp:
		return rpc.ledgerOps.Handle(ctx, req.LedgerOp)
	case proto_connector.OpType_LockOp:
		return rpc.lockOps.Handle(ctx, req.LockOp)
	default:
		return nil, fmt.Errorf("unsupported operation type")
	}
}
<|endoftext|>