<commit_before>package main

import (
	"path/filepath"
	str "strings"

	sp "github.com/scipipe/scipipe"
	spcomp "github.com/scipipe/scipipe/components"
)

const (
	workDir = "/scipipe-data/"
)

func main() {
	prun := sp.NewPipelineRunner()

	sampleFilesSender := sp.NewIPQueue(workDir + "002_CRa_H9M5_M470_Pool_01_alternate_neg_low_mr.mzML")
	prun.AddProcess(sampleFilesSender)

	// -------------------------------------------------------------------
	// Peak Picker Process
	// -------------------------------------------------------------------
	peakPicker := sp.NewFromShell("peakpicker", "PeakPickerHiRes -in {i:sample} -out {o:peaks} -ini "+workDir+"openms-params/PPparam.ini")
	peakPicker.PathFormatters["peaks"] = func(t *sp.SciTask) string {
		parts := str.Split(filepath.Base(t.GetInPath("sample")), ".")
		peaksPath := workDir + "results/" + str.Join(parts[:len(parts)-1], "_") + ".peaks"
		return peaksPath
	}
	peakPicker.ExecMode = sp.ExecModeK8s
	peakPicker.Image = "container-registry.phenomenal-h2020.eu/phnmnl/openms:v1.11.1_cv0.1.9"
	prun.AddProcess(peakPicker)

	// -------------------------------------------------------------------
	// Feature Finder process
	// -------------------------------------------------------------------
	featFinder := sp.NewFromShell("featfinder", "FeatureFinderMetabo -in {i:peaks} -out {o:feats} -ini "+workDir+"openms-params/FFparam.ini")
	featFinder.PathFormatters["feats"] = func(t *sp.SciTask) string {
		featsPath := t.GetInPath("peaks") + ".featureXML"
		return featsPath
	}
	featFinder.ExecMode = sp.ExecModeK8s
	featFinder.Image = "container-registry.phenomenal-h2020.eu/phnmnl/openms:v1.11.1_cv0.1.9"
	prun.AddProcess(featFinder)

	// -------------------------------------------------------------------
	// Feature Linker process
	// -------------------------------------------------------------------
	// groupSuffix = luigi.Parameter()
	// inputList = map(lambda i: "/work/" + i.path, self.input())
	// inputStr = ' '.join(inputList)
	//
	// "command": ["sh","-c"],
	// "args": [
	//     "FeatureLinkerUnlabeledQT -in " + inputStr +
	//     " -out /work/" + self.output().path +
	//     " -ini /work/openms-params/FLparam.ini" +
	//     " -threads 2"],
	//
	// def requires(self):
	//     inputFiles = glob.glob("data/*_"+self.groupSuffix+".mzML")
	//     return map(lambda f: FeatureFinderTask(sampleFile=f),inputFiles)
	//
	// def output(self):
	//     return luigi.LocalTarget("results/linked_"+self.groupSuffix+".consensusXML")
	strToSubstr := spcomp.NewStreamToSubStream()
	prun.AddProcess(strToSubstr)

	featLinker := sp.NewFromShell("featlinker", "FeatureLinkerUnlabeledQT -in {i:feats:r: } -out {o:consensus} -ini "+workDir+"openms-params/FLparam.ini -threads 2")
	featLinker.PathFormatters["consensus"] = func(t *sp.SciTask) string {
		featsPath := "linked.consensusXML"
		return featsPath
	}
	featLinker.ExecMode = sp.ExecModeK8s
	featLinker.Image = "container-registry.phenomenal-h2020.eu/phnmnl/openms:v1.11.1_cv0.1.9"
	prun.AddProcess(featLinker)

	// -------------------------------------------------------------------
	// File Filter process
	// -------------------------------------------------------------------
	// groupSuffix = luigi.Parameter()
	//
	// "FileFilter",
	//     "-in", "/work/" + self.input().path,
	//     "-out", "/work/" + self.output().path,
	//     "-ini", "/work/openms-params/FileFparam.ini"
	//
	// def requires(self):
	//     return FeatureLinkerTask(groupSuffix=self.groupSuffix)
	//
	// def output(self):
	//     return luigi.LocalTarget("results/linked_filtered_"+self.groupSuffix+".consensusXML")

	// -------------------------------------------------------------------
	// Text Exporter process
	// -------------------------------------------------------------------
	//
	// "TextExporter",
	//     "-in", "/work/" + self.input().path,
	//     "-out", "/work/" + self.output().path,
	//     "-ini", "/work/openms-params/TEparam.ini"
	//
	// def requires(self):
	//     return FileFilterTask(groupSuffix=self.groupSuffix)
	//
	// def output(self):
	//     return luigi.LocalTarget("results/"+self.groupSuffix+".csv")

	sink := sp.NewSink()
	prun.AddProcess(sink)

	// -------------------------------------------------------------------
	// Connect network
	// -------------------------------------------------------------------
	peakPicker.GetInPort("sample").Connect(sampleFilesSender.Out)
	featFinder.GetInPort("peaks").Connect(peakPicker.GetOutPort("peaks"))
	strToSubstr.In.Connect(featFinder.GetOutPort("feats"))
	featLinker.GetInPort("feats").Connect(strToSubstr.OutSubStream)
	sink.Connect(featLinker.GetOutPort("consensus"))

	prun.Run()
}
<commit_msg>Include workdir in path too<commit_after>package main

import (
	"path/filepath"
	str "strings"

	sp "github.com/scipipe/scipipe"
	spcomp "github.com/scipipe/scipipe/components"
)

const (
	workDir = "/scipipe-data/"
)

func main() {
	prun := sp.NewPipelineRunner()

	sampleFilesSender := sp.NewIPQueue(workDir+"002_CRa_H9M5_M470_Pool_01_alternate_neg_low_mr.mzML", workDir+"001_CRa_H9M5_M470_Blank_01_alternate_neg_low_mr.mzML")
	prun.AddProcess(sampleFilesSender)

	// -------------------------------------------------------------------
	// Peak Picker Process
	// -------------------------------------------------------------------
	peakPicker := sp.NewFromShell("peakpicker", "PeakPickerHiRes -in {i:sample} -out {o:peaks} -ini "+workDir+"openms-params/PPparam.ini")
	peakPicker.PathFormatters["peaks"] = func(t *sp.SciTask) string {
		parts := str.Split(filepath.Base(t.GetInPath("sample")), ".")
		peaksPath := workDir + "results/" + str.Join(parts[:len(parts)-1], "_") + ".peaks"
		return peaksPath
	}
	peakPicker.ExecMode = sp.ExecModeK8s
	peakPicker.Image = "container-registry.phenomenal-h2020.eu/phnmnl/openms:v1.11.1_cv0.1.9"
	prun.AddProcess(peakPicker)

	// -------------------------------------------------------------------
	// Feature Finder process
	// -------------------------------------------------------------------
	featFinder := sp.NewFromShell("featfinder", "FeatureFinderMetabo -in {i:peaks} -out {o:feats} -ini "+workDir+"openms-params/FFparam.ini")
	featFinder.PathFormatters["feats"] = func(t *sp.SciTask) string {
		featsPath := t.GetInPath("peaks") + ".featureXML"
		return featsPath
	}
	featFinder.ExecMode = sp.ExecModeK8s
	featFinder.Image = "container-registry.phenomenal-h2020.eu/phnmnl/openms:v1.11.1_cv0.1.9"
	prun.AddProcess(featFinder)

	// -------------------------------------------------------------------
	// Feature Linker process
	// -------------------------------------------------------------------
	// groupSuffix = luigi.Parameter()
	// inputList = map(lambda i: "/work/" + i.path, self.input())
	// inputStr = ' '.join(inputList)
	//
	// "command": ["sh","-c"],
	// "args": [
	//     "FeatureLinkerUnlabeledQT -in " + inputStr +
	//     " -out /work/" + self.output().path +
	//     " -ini /work/openms-params/FLparam.ini" +
	//     " -threads 2"],
	//
	// def requires(self):
	//     inputFiles = glob.glob("data/*_"+self.groupSuffix+".mzML")
	//     return map(lambda f: FeatureFinderTask(sampleFile=f),inputFiles)
	//
	// def output(self):
	//     return luigi.LocalTarget("results/linked_"+self.groupSuffix+".consensusXML")
	strToSubstr := spcomp.NewStreamToSubStream()
	prun.AddProcess(strToSubstr)

	featLinker := sp.NewFromShell("featlinker", "FeatureLinkerUnlabeledQT -in {i:feats:r: } -out {o:consensus} -ini "+workDir+"openms-params/FLparam.ini -threads 2")
	featLinker.PathFormatters["consensus"] = func(t *sp.SciTask) string {
		featsPath := "linked.consensusXML"
		return featsPath
	}
	featLinker.ExecMode = sp.ExecModeK8s
	featLinker.Image = "container-registry.phenomenal-h2020.eu/phnmnl/openms:v1.11.1_cv0.1.9"
	prun.AddProcess(featLinker)

	// -------------------------------------------------------------------
	// File Filter process
	// -------------------------------------------------------------------
	// groupSuffix = luigi.Parameter()
	//
	// "FileFilter",
	//     "-in", "/work/" + self.input().path,
	//     "-out", "/work/" + self.output().path,
	//     "-ini", "/work/openms-params/FileFparam.ini"
	//
	// def requires(self):
	//     return FeatureLinkerTask(groupSuffix=self.groupSuffix)
	//
	// def output(self):
	//     return luigi.LocalTarget("results/linked_filtered_"+self.groupSuffix+".consensusXML")

	// -------------------------------------------------------------------
	// Text Exporter process
	// -------------------------------------------------------------------
	//
	// "TextExporter",
	//     "-in", "/work/" + self.input().path,
	//     "-out", "/work/" + self.output().path,
	//     "-ini", "/work/openms-params/TEparam.ini"
	//
	// def requires(self):
	//     return FileFilterTask(groupSuffix=self.groupSuffix)
	//
	// def output(self):
	//     return luigi.LocalTarget("results/"+self.groupSuffix+".csv")

	sink := sp.NewSink()
	prun.AddProcess(sink)

	// -------------------------------------------------------------------
	// Connect network
	// -------------------------------------------------------------------
	peakPicker.GetInPort("sample").Connect(sampleFilesSender.Out)
	featFinder.GetInPort("peaks").Connect(peakPicker.GetOutPort("peaks"))
	strToSubstr.In.Connect(featFinder.GetOutPort("feats"))
	featLinker.GetInPort("feats").Connect(strToSubstr.OutSubStream)
	sink.Connect(featLinker.GetOutPort("consensus"))

	prun.Run()
}
<|endoftext|>


<commit_before>package shell

import (
	"bytes"
	"errors"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"

	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/kardianos/osext"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/executors"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
)

type executor struct {
	executors.AbstractExecutor
	cmd       *exec.Cmd
	scriptDir string
}

func (s *executor) Prepare(globalConfig *common.Config, config *common.RunnerConfig, build *common.Build) error {
	if globalConfig != nil {
		s.Shell.User = globalConfig.User
	}

	// expand environment variables to have current directory
	wd, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("Getwd: %v", err)
	}

	mapping := func(key string) string {
		switch key {
		case "PWD":
			return wd
		default:
			return ""
		}
	}

	s.DefaultBuildsDir = os.Expand(s.DefaultBuildsDir, mapping)
	s.DefaultCacheDir = os.Expand(s.DefaultCacheDir, mapping)

	// Pass control to executor
	err = s.AbstractExecutor.Prepare(globalConfig, config, build)
	if err != nil {
		return err
	}

	s.Println("Using Shell executor...")
	return nil
}

func (s *executor) Start() error {
	s.Debugln("Starting shell command...")

	// Create execution command
	s.cmd = exec.Command(s.BuildScript.Command, s.BuildScript.Arguments...)
	if s.cmd == nil {
		return errors.New("Failed to generate execution command")
	}

	helpers.SetProcessGroup(s.cmd)

	// Fill process environment variables
	s.cmd.Env = append(os.Environ(), s.BuildScript.Environment...)
	s.cmd.Stdout = s.BuildLog
	s.cmd.Stderr = s.BuildLog

	if s.BuildScript.PassFile {
		scriptDir, err := ioutil.TempDir("", "build_script")
		if err != nil {
			return err
		}
		s.scriptDir = scriptDir

		scriptFile := filepath.Join(scriptDir, "script."+s.BuildScript.Extension)
		err = ioutil.WriteFile(scriptFile, s.BuildScript.GetScriptBytes(), 0700)
		if err != nil {
			return err
		}

		s.cmd.Args = append(s.cmd.Args, scriptFile)
	} else {
		s.cmd.Stdin = bytes.NewReader(s.BuildScript.GetScriptBytes())
	}

	// Start process
	err := s.cmd.Start()
	if err != nil {
		return errors.New("Failed to start process")
	}

	// Wait for process to exit
	go func() {
		s.BuildFinish <- s.cmd.Wait()
	}()
	return nil
}

func (s *executor) Cleanup() {
	helpers.KillProcessGroup(s.cmd)

	if s.scriptDir != "" {
		os.RemoveAll(s.scriptDir)
	}

	s.AbstractExecutor.Cleanup()
}

func init() {
	// Look for self
	runnerCommand, err := osext.Executable()
	if err != nil {
		logrus.Warningln(err)
	}

	options := executors.ExecutorOptions{
		DefaultBuildsDir: "$PWD/builds",
		DefaultCacheDir:  "$PWD/cache",
		SharedBuildsDir:  true,
		Shell: common.ShellScriptInfo{
			Shell:         common.GetDefaultShell(),
			Type:          common.LoginShell,
			RunnerCommand: runnerCommand,
		},
		ShowHostname: false,
	}

	creator := func() common.Executor {
		return &executor{
			AbstractExecutor: executors.AbstractExecutor{
				ExecutorOptions: options,
			},
		}
	}

	featuresUpdater := func(features *common.FeaturesInfo) {
		features.Variables = true
	}

	common.RegisterExecutor("shell", executors.DefaultExecutorProvider{
		Creator:         creator,
		FeaturesUpdater: featuresUpdater,
	})
}
<commit_msg>report process start failure<commit_after>package shell

import (
	"bytes"
	"errors"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"

	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/kardianos/osext"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/executors"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
)

type executor struct {
	executors.AbstractExecutor
	cmd       *exec.Cmd
	scriptDir string
}

func (s *executor) Prepare(globalConfig *common.Config, config *common.RunnerConfig, build *common.Build) error {
	if globalConfig != nil {
		s.Shell.User = globalConfig.User
	}

	// expand environment variables to have current directory
	wd, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("Getwd: %v", err)
	}

	mapping := func(key string) string {
		switch key {
		case "PWD":
			return wd
		default:
			return ""
		}
	}

	s.DefaultBuildsDir = os.Expand(s.DefaultBuildsDir, mapping)
	s.DefaultCacheDir = os.Expand(s.DefaultCacheDir, mapping)

	// Pass control to executor
	err = s.AbstractExecutor.Prepare(globalConfig, config, build)
	if err != nil {
		return err
	}

	s.Println("Using Shell executor...")
	return nil
}

func (s *executor) Start() error {
	s.Debugln("Starting shell command...")

	// Create execution command
	s.cmd = exec.Command(s.BuildScript.Command, s.BuildScript.Arguments...)
	if s.cmd == nil {
		return errors.New("Failed to generate execution command")
	}

	helpers.SetProcessGroup(s.cmd)

	// Fill process environment variables
	s.cmd.Env = append(os.Environ(), s.BuildScript.Environment...)
	s.cmd.Stdout = s.BuildLog
	s.cmd.Stderr = s.BuildLog

	if s.BuildScript.PassFile {
		scriptDir, err := ioutil.TempDir("", "build_script")
		if err != nil {
			return err
		}
		s.scriptDir = scriptDir

		scriptFile := filepath.Join(scriptDir, "script."+s.BuildScript.Extension)
		err = ioutil.WriteFile(scriptFile, s.BuildScript.GetScriptBytes(), 0700)
		if err != nil {
			return err
		}

		s.cmd.Args = append(s.cmd.Args, scriptFile)
	} else {
		s.cmd.Stdin = bytes.NewReader(s.BuildScript.GetScriptBytes())
	}

	// Start process
	err := s.cmd.Start()
	if err != nil {
		return fmt.Errorf("Failed to start process: %s", err)
	}

	// Wait for process to exit
	go func() {
		s.BuildFinish <- s.cmd.Wait()
	}()
	return nil
}

func (s *executor) Cleanup() {
	helpers.KillProcessGroup(s.cmd)

	if s.scriptDir != "" {
		os.RemoveAll(s.scriptDir)
	}

	s.AbstractExecutor.Cleanup()
}

func init() {
	// Look for self
	runnerCommand, err := osext.Executable()
	if err != nil {
		logrus.Warningln(err)
	}

	options := executors.ExecutorOptions{
		DefaultBuildsDir: "$PWD/builds",
		DefaultCacheDir:  "$PWD/cache",
		SharedBuildsDir:  true,
		Shell: common.ShellScriptInfo{
			Shell:         common.GetDefaultShell(),
			Type:          common.LoginShell,
			RunnerCommand: runnerCommand,
		},
		ShowHostname: false,
	}

	creator := func() common.Executor {
		return &executor{
			AbstractExecutor: executors.AbstractExecutor{
				ExecutorOptions: options,
			},
		}
	}

	featuresUpdater := func(features *common.FeaturesInfo) {
		features.Variables = true
	}

	common.RegisterExecutor("shell", executors.DefaultExecutorProvider{
		Creator:         creator,
		FeaturesUpdater: featuresUpdater,
	})
}
<|endoftext|>


<commit_before>package pangram

import (
	"testing"
)

type testCase struct {
	input         string
	expected      bool
	failureReason string
}

var testCases = []testCase{
	{"", false, "sentence empty"},
	{"The quick brown fox jumps over the lazy dog", true, ""},
	{"a quick movement of the enemy will jeopardize five gunboats", false, "missing character 'x'"},
	{"the quick brown fish jumps over the lazy dog", false, "another missing character 'x'"},
	{"the 1 quick brown fox jumps over the 2 lazy dogs", true, ""},
	{"7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog", false, "missing letters replaced by numbers"},
	{"\"Five quacking Zephyrs jolt my wax bed.\"", true, ""},
}

func TestPangram(t *testing.T) {
	for _, test := range testCases {
		actual := IsPangram(test.input)
		if actual != test.expected {
			t.Errorf("Pangram test [%s], expected [%t], actual [%t]", test.input, test.expected, actual)
			if !test.expected {
				t.Logf("[%s] should not be a pangram because : %s\n", test.input, test.failureReason)
			}
		}
	}
}

func BenchmarkPangram(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, test := range testCases {
			IsPangram(test.input)
		}
	}
}
<commit_msg>pangram: Add test cases<commit_after>package pangram

import (
	"testing"
)

type testCase struct {
	input         string
	expected      bool
	failureReason string
}

var testCases = []testCase{
	{"", false, "sentence empty"},
	{"The quick brown fox jumps over the lazy dog", true, ""},
	{"a quick movement of the enemy will jeopardize five gunboats", false, "missing character 'x'"},
	{"the quick brown fish jumps over the lazy dog", false, "another missing character 'x'"},
	{"the 1 quick brown fox jumps over the 2 lazy dogs", true, ""},
	{"7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog", false, "missing letters replaced by numbers"},
	{"\"Five quacking Zephyrs jolt my wax bed.\"", true, ""},
	{"abcdefghijklmnopqrstuvwxy", false, "missing character 'z'"},
	{"bcdefghijklmnopqrstuvwxyz", false, "missing character 'a'"},
}

func TestPangram(t *testing.T) {
	for _, test := range testCases {
		actual := IsPangram(test.input)
		if actual != test.expected {
			t.Errorf("Pangram test [%s], expected [%t], actual [%t]", test.input, test.expected, actual)
			if !test.expected {
				t.Logf("[%s] should not be a pangram because : %s\n", test.input, test.failureReason)
			}
		}
	}
}

func BenchmarkPangram(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, test := range testCases {
			IsPangram(test.input)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"net/url"
	"os"
	"strings"
)

func main() {
	var cn163 string
	var ids []string

	flag.StringVar(&cn163, "cn163", "", "Comma separated list of ids.")
	flag.Parse()
	if flag.NFlag() == 0 {
		flag.PrintDefaults()
		os.Exit(1)
	}

	ids = strings.Split(cn163, ",")

	for _, id := range ids {
		link := "http://cn163.net/archives/" + id
		doc, err := goquery.NewDocument(link)
		if err != nil {
			fmt.Println("Cannot open url")
			os.Exit(2)
		}

		doc.Find("a").Each(func(i int, s *goquery.Selection) {
			href := s.AttrOr("href", "")
			if strings.HasPrefix(href, "ed2k://") {
				uu, _ := url.QueryUnescape(href)
				fmt.Println(uu)
			}
		})
	}
}
<commit_msg>change arguments<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"net/url"
	"os"
	"strings"
)

func main() {
	var argIds, argURL string
	var ids []string

	flag.StringVar(&argIds, "ids", "", "Comma separated list of ids, like `11,31,51`. Each joined after the given `--url`.")
	flag.StringVar(&argURL, "url", "cn163.net/archives/", "URL of the site without `http://`. `cn163.net/archives/` by default.")
	flag.Parse()
	if flag.NFlag() == 0 {
		flag.PrintDefaults()
		os.Exit(1)
	}

	ids = strings.Split(argIds, ",")

	for _, id := range ids {
		link := "http://" + argURL + id
		doc, err := goquery.NewDocument(link)
		if err != nil {
			fmt.Println("Cannot open url")
			os.Exit(2)
		}

		doc.Find("a").Each(func(i int, s *goquery.Selection) {
			href := s.AttrOr("href", "")
			if strings.HasPrefix(href, "ed2k://") {
				uu, _ := url.QueryUnescape(href)
				fmt.Println(uu)
			}
		})
	}
}
<|endoftext|>


<commit_before>package transaction

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/stefankopieczek/gossip/base"
	"github.com/stefankopieczek/gossip/log"
	"github.com/stefankopieczek/gossip/transport"
)

var (
	global *Manager = &Manager{
		txs: map[key]Transaction{},
	}
)

type Manager struct {
	txs       map[key]Transaction
	transport *transport.Manager
	requests  chan *ServerTransaction
	txLock    *sync.RWMutex
}

// Transactions are identified by the branch parameter in the top Via header, and the method. (RFC 3261 17.1.3)
type key struct {
	branch string
	method string
}

func NewManager(trans, addr string) (*Manager, error) {
	t, err := transport.NewManager(trans)
	if err != nil {
		return nil, err
	}

	mng := &Manager{
		txs:       map[key]Transaction{},
		txLock:    &sync.RWMutex{},
		transport: t,
	}

	mng.requests = make(chan *ServerTransaction, 5)

	// Spin up a goroutine to pull messages up from the depths.
	c := mng.transport.GetChannel()
	go func() {
		for msg := range c {
			go mng.handle(msg)
		}
	}()

	err = mng.transport.Listen(addr)
	if err != nil {
		return nil, err
	}

	return mng, nil
}

// Stop the manager and close down all processing on it, losing all transactions in progress.
func (mng *Manager) Stop() {
	// Stop the transport layer.
	mng.transport.Stop()
}

func (mng *Manager) Requests() <-chan *ServerTransaction {
	return (<-chan *ServerTransaction)(mng.requests)
}

func (mng *Manager) putTx(tx Transaction) {
	viaHeaders := tx.Origin().Headers("Via")
	if len(viaHeaders) == 0 {
		log.Warn("No Via header on new transaction. Transaction will be dropped.")
		return
	}

	via, ok := viaHeaders[0].(*base.ViaHeader)
	if !ok {
		// TODO: Handle this better.
		panic(errors.New("Headers('Via') returned non-Via header!"))
	}

	branch, ok := (*via)[0].Params["branch"]
	if !ok {
		log.Warn("No branch parameter on top Via header.  Transaction will be dropped.")
		return
	}

	key := key{*branch, string(tx.Origin().Method)}
	mng.txLock.Lock()
	mng.txs[key] = tx
	mng.txLock.Unlock()
}

func (mng *Manager) makeKey(s base.SipMessage) (key, bool) {
	viaHeaders := s.Headers("Via")
	via, ok := viaHeaders[0].(*base.ViaHeader)
	if !ok {
		panic(errors.New("Headers('Via') returned non-Via header!"))
	}

	branch, ok := (*via)[0].Params["branch"]
	if !ok {
		return key{}, false
	}

	var method string
	switch s := s.(type) {
	case *base.Request:
		// Correlate an ACK request to the related INVITE.
		if s.Method == base.ACK {
			method = string(base.INVITE)
		} else {
			method = string(s.Method)
		}
	case *base.Response:
		cseqs := s.Headers("CSeq")
		if len(cseqs) == 0 {
			// TODO - Handle non-existent CSeq
			panic("No CSeq on response!")
		}

		cseq, _ := s.Headers("CSeq")[0].(*base.CSeq)
		method = string(cseq.MethodName)
	}

	return key{*branch, method}, true
}

// Gets a transaction from the transaction store.
// Should only be called inside the storage handling goroutine to ensure concurrency safety.
func (mng *Manager) getTx(s base.SipMessage) (Transaction, bool) {
	key, ok := mng.makeKey(s)
	if !ok {
		// TODO: Here we should initiate more intense searching as specified in RFC3261 section 17
		log.Warn("Could not correlate message to transaction by branch/method. Dropping.")
		return nil, false
	}

	mng.txLock.RLock()
	tx, ok := mng.txs[key]
	mng.txLock.RUnlock()

	return tx, ok
}

// Deletes a transaction from the transaction store.
// Should only be called inside the storage handling goroutine to ensure concurrency safety.
func (mng *Manager) delTx(t Transaction) {
	key, ok := mng.makeKey(t.Origin())
	if !ok {
		log.Debug("Could not build lookup key for transaction. Is it missing a branch parameter?")
	}

	mng.txLock.Lock()
	delete(mng.txs, key)
	mng.txLock.Unlock()
}

func (mng *Manager) handle(msg base.SipMessage) {
	log.Info("Received message: %s", msg.Short())
	switch m := msg.(type) {
	case *base.Request:
		mng.request(m)
	case *base.Response:
		mng.correlate(m)
	default:
		// TODO: Error
	}
}

// Create Client transaction.
func (mng *Manager) Send(r *base.Request, dest string) *ClientTransaction {
	log.Debug("Sending to %v: %v", dest, r.String())

	tx := &ClientTransaction{}
	tx.origin = r
	tx.dest = dest
	tx.transport = mng.transport
	tx.tm = mng

	tx.initFSM()

	tx.tu = make(chan *base.Response, 3)
	tx.tu_err = make(chan error, 1)

	tx.timer_a_time = T1
	tx.timer_a = time.AfterFunc(tx.timer_a_time, func() {
		tx.fsm.Spin(client_input_timer_a)
	})
	tx.timer_b = time.AfterFunc(64*T1, func() {
		tx.fsm.Spin(client_input_timer_b)
	})

	// Timer D is set to 32 seconds for unreliable transports, and 0 seconds otherwise.
	tx.timer_d_time = 32 * time.Second

	err := mng.transport.Send(dest, r)
	if err != nil {
		log.Warn("Failed to send message: %s", err.Error())
		tx.fsm.Spin(client_input_transport_err)
	}

	mng.putTx(tx)

	return tx
}

// Give a received response to the correct transaction.
func (mng *Manager) correlate(r *base.Response) {
	tx, ok := mng.getTx(r)
	if !ok {
		// TODO: Something
		log.Warn("Failed to correlate response to active transaction. Dropping it.")
		return
	}

	tx.Receive(r)
}

// Handle a request.
func (mng *Manager) request(r *base.Request) {
	t, ok := mng.getTx(r)
	if ok {
		t.Receive(r)
		return
	}

	// If we failed to correlate an ACK, just drop it.
	if r.Method == base.ACK {
		log.Warn("Couldn't correlate ACK to an open transaction. Dropping it.")
		return
	}

	// Create a new transaction
	tx := &ServerTransaction{}
	tx.tm = mng
	tx.origin = r
	tx.transport = mng.transport

	// Use the remote address in the top Via header.  This is not correct behaviour.
	viaHeaders := tx.Origin().Headers("Via")
	if len(viaHeaders) == 0 {
		log.Warn("No Via header on new transaction. Transaction will be dropped.")
		return
	}

	via, ok := viaHeaders[0].(*base.ViaHeader)
	if !ok {
		panic(errors.New("Headers('Via') returned non-Via header!"))
	}

	if len(*via) == 0 {
		log.Warn("Via header contained no hops! Transaction will be dropped.")
		return
	}

	hop := (*via)[0]

	tx.dest = fmt.Sprintf("%v:%v", hop.Host, *hop.Port)
	tx.transport = mng.transport

	tx.initFSM()

	tx.tu = make(chan *base.Response, 3)
	tx.tu_err = make(chan error, 1)
	tx.ack = make(chan *base.Request, 1)

	// Send a 100 Trying immediately.
	// Technically we shouldn't do this if we trustthe user to do it within 200ms,
	// but I'm not sure how to handle that situation right now.

	// Pretend the user sent us a 100 to send.
	trying := base.NewResponse(
		"SIP/2.0",
		100,
		"Trying",
		[]base.SipHeader{},
		"",
	)

	base.CopyHeaders("Via", tx.origin, trying)
	base.CopyHeaders("From", tx.origin, trying)
	base.CopyHeaders("To", tx.origin, trying)
	base.CopyHeaders("Call-Id", tx.origin, trying)
	base.CopyHeaders("CSeq", tx.origin, trying)

	tx.lastResp = trying
	tx.fsm.Spin(server_input_user_1xx)

	mng.requests <- tx
}
<commit_msg>Fixed up transaction layer.<commit_after>package transaction

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/stefankopieczek/gossip/base"
	"github.com/stefankopieczek/gossip/log"
	"github.com/stefankopieczek/gossip/transport"
)

var (
	global *Manager = &Manager{
		txs: map[key]Transaction{},
	}
)

type Manager struct {
	txs       map[key]Transaction
	transport *transport.Manager
	requests  chan *ServerTransaction
	txLock    *sync.RWMutex
}

// Transactions are identified by the branch parameter in the top Via header, and the method. (RFC 3261 17.1.3)
type key struct {
	branch string
	method string
}

func NewManager(trans, addr string) (*Manager, error) {
	t, err := transport.NewManager(trans)
	if err != nil {
		return nil, err
	}

	mng := &Manager{
		txs:       map[key]Transaction{},
		txLock:    &sync.RWMutex{},
		transport: t,
	}

	mng.requests = make(chan *ServerTransaction, 5)

	// Spin up a goroutine to pull messages up from the depths.
	c := mng.transport.GetChannel()
	go func() {
		for msg := range c {
			go mng.handle(msg)
		}
	}()

	err = mng.transport.Listen(addr)
	if err != nil {
		return nil, err
	}

	return mng, nil
}

// Stop the manager and close down all processing on it, losing all transactions in progress.
func (mng *Manager) Stop() {
	// Stop the transport layer.
	mng.transport.Stop()
}

func (mng *Manager) Requests() <-chan *ServerTransaction {
	return (<-chan *ServerTransaction)(mng.requests)
}

func (mng *Manager) putTx(tx Transaction) {
	viaHeaders := tx.Origin().Headers("Via")
	if len(viaHeaders) == 0 {
		log.Warn("No Via header on new transaction. Transaction will be dropped.")
		return
	}

	via, ok := viaHeaders[0].(*base.ViaHeader)
	if !ok {
		// TODO: Handle this better.
		panic(errors.New("Headers('Via') returned non-Via header!"))
	}

	branch, ok := (*via)[0].Params["branch"]
	if !ok {
		log.Warn("No branch parameter on top Via header.  Transaction will be dropped.")
		return
	}

	var k key
	switch branch := branch.(type) {
	case base.String:
		k = key{branch.String(), string(tx.Origin().Method)}
	case base.NoString:
		log.Warn("Empty branch parameter on top Via header. Transaction will be dropped.")
		return
	default:
		log.Warn("Unexpected type of branch value on top Via header: %T", branch)
		return
	}
	mng.txLock.Lock()
	mng.txs[k] = tx
	mng.txLock.Unlock()
}

func (mng *Manager) makeKey(s base.SipMessage) (key, bool) {
	viaHeaders := s.Headers("Via")
	via, ok := viaHeaders[0].(*base.ViaHeader)
	if !ok {
		panic(errors.New("Headers('Via') returned non-Via header!"))
	}

	b, ok := (*via)[0].Params["branch"]
	if !ok {
		return key{}, false
	}

	branch, ok := b.(base.String)
	if !ok {
		return key{}, false
	}

	var method string
	switch s := s.(type) {
	case *base.Request:
		// Correlate an ACK request to the related INVITE.
		if s.Method == base.ACK {
			method = string(base.INVITE)
		} else {
			method = string(s.Method)
		}
	case *base.Response:
		cseqs := s.Headers("CSeq")
		if len(cseqs) == 0 {
			// TODO - Handle non-existent CSeq
			panic("No CSeq on response!")
		}

		cseq, _ := s.Headers("CSeq")[0].(*base.CSeq)
		method = string(cseq.MethodName)
	}

	return key{branch.String(), method}, true
}

// Gets a transaction from the transaction store.
// Should only be called inside the storage handling goroutine to ensure concurrency safety.
func (mng *Manager) getTx(s base.SipMessage) (Transaction, bool) {
	key, ok := mng.makeKey(s)
	if !ok {
		// TODO: Here we should initiate more intense searching as specified in RFC3261 section 17
		log.Warn("Could not correlate message to transaction by branch/method. Dropping.")
		return nil, false
	}

	mng.txLock.RLock()
	tx, ok := mng.txs[key]
	mng.txLock.RUnlock()

	return tx, ok
}

// Deletes a transaction from the transaction store.
// Should only be called inside the storage handling goroutine to ensure concurrency safety.
func (mng *Manager) delTx(t Transaction) {
	key, ok := mng.makeKey(t.Origin())
	if !ok {
		log.Debug("Could not build lookup key for transaction. Is it missing a branch parameter?")
	}

	mng.txLock.Lock()
	delete(mng.txs, key)
	mng.txLock.Unlock()
}

func (mng *Manager) handle(msg base.SipMessage) {
	log.Info("Received message: %s", msg.Short())
	switch m := msg.(type) {
	case *base.Request:
		mng.request(m)
	case *base.Response:
		mng.correlate(m)
	default:
		// TODO: Error
	}
}

// Create Client transaction.
func (mng *Manager) Send(r *base.Request, dest string) *ClientTransaction {
	log.Debug("Sending to %v: %v", dest, r.String())

	tx := &ClientTransaction{}
	tx.origin = r
	tx.dest = dest
	tx.transport = mng.transport
	tx.tm = mng

	tx.initFSM()

	tx.tu = make(chan *base.Response, 3)
	tx.tu_err = make(chan error, 1)

	tx.timer_a_time = T1
	tx.timer_a = time.AfterFunc(tx.timer_a_time, func() {
		tx.fsm.Spin(client_input_timer_a)
	})
	tx.timer_b = time.AfterFunc(64*T1, func() {
		tx.fsm.Spin(client_input_timer_b)
	})

	// Timer D is set to 32 seconds for unreliable transports, and 0 seconds otherwise.
	tx.timer_d_time = 32 * time.Second

	err := mng.transport.Send(dest, r)
	if err != nil {
		log.Warn("Failed to send message: %s", err.Error())
		tx.fsm.Spin(client_input_transport_err)
	}

	mng.putTx(tx)

	return tx
}

// Give a received response to the correct transaction.
func (mng *Manager) correlate(r *base.Response) {
	tx, ok := mng.getTx(r)
	if !ok {
		// TODO: Something
		log.Warn("Failed to correlate response to active transaction. Dropping it.")
		return
	}

	tx.Receive(r)
}

// Handle a request.
func (mng *Manager) request(r *base.Request) {
	t, ok := mng.getTx(r)
	if ok {
		t.Receive(r)
		return
	}

	// If we failed to correlate an ACK, just drop it.
	if r.Method == base.ACK {
		log.Warn("Couldn't correlate ACK to an open transaction. Dropping it.")
		return
	}

	// Create a new transaction
	tx := &ServerTransaction{}
	tx.tm = mng
	tx.origin = r
	tx.transport = mng.transport

	// Use the remote address in the top Via header.  This is not correct behaviour.
	viaHeaders := tx.Origin().Headers("Via")
	if len(viaHeaders) == 0 {
		log.Warn("No Via header on new transaction. Transaction will be dropped.")
		return
	}

	via, ok := viaHeaders[0].(*base.ViaHeader)
	if !ok {
		panic(errors.New("Headers('Via') returned non-Via header!"))
	}

	if len(*via) == 0 {
		log.Warn("Via header contained no hops! Transaction will be dropped.")
		return
	}

	hop := (*via)[0]

	tx.dest = fmt.Sprintf("%v:%v", hop.Host, *hop.Port)
	tx.transport = mng.transport

	tx.initFSM()

	tx.tu = make(chan *base.Response, 3)
	tx.tu_err = make(chan error, 1)
	tx.ack = make(chan *base.Request, 1)

	// Send a 100 Trying immediately.
	// Technically we shouldn't do this if we trustthe user to do it within 200ms,
	// but I'm not sure how to handle that situation right now.

	// Pretend the user sent us a 100 to send.
	trying := base.NewResponse(
		"SIP/2.0",
		100,
		"Trying",
		[]base.SipHeader{},
		"",
	)

	base.CopyHeaders("Via", tx.origin, trying)
	base.CopyHeaders("From", tx.origin, trying)
	base.CopyHeaders("To", tx.origin, trying)
	base.CopyHeaders("Call-Id", tx.origin, trying)
	base.CopyHeaders("CSeq", tx.origin, trying)

	tx.lastResp = trying
	tx.fsm.Spin(server_input_user_1xx)

	mng.requests <- tx
}
<|endoftext|>


<commit_before>package tcp

import (
	"errors"
	"fmt"
	"net"

	"github.com/jennal/goplay/handler/pkg"
	"github.com/jennal/goplay/protocol"
	"github.com/jennal/goplay/transfer"
)

type client struct {
	conn        net.Conn
	isConnected bool
}

func NewClientWithConnect(conn net.Conn) transfer.Client {
	return &client{
		conn:        conn,
		isConnected: true,
	}
}

func NewClient() transfer.Client {
	return &client{
		isConnected: false,
	}
}

func (client *client) IsConnected() bool {
	return client.isConnected
}

func (client *client) Connect(host string, port int) error {
	if client.isConnected {
		return errors.New("already connected")
	}

	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		return err
	}

	client.conn = conn
	client.isConnected = true

	return nil
}

func (client *client) Disconnect() error {
	return client.conn.Close()
}

func (client *client) Read(buf []byte) (int, error) {
	return client.conn.Read(buf)
}

func (client *client) Write(buf []byte) (int, error) {
	return client.conn.Write(buf)
}

func (client *client) Send(header *pkg.Header, data interface{}) error {
	encoder := protocol.GetEncodeDecoder(header.Encoding)
	buffer, err := encoder.Marshal(header, data)
	if err != nil {
		return err
	}

	fmt.Println("Write:", header, data, buffer)

	// fmt.Println("write-0")
	_, err = client.Write(buffer)
	// fmt.Println("write-1")
	return err
}

func (client *client) Recv(header *pkg.Header, data interface{}) error {
	var buffer = make([]byte, protocol.HEADER_STATIC_SIZE)
	_, err := client.Read(buffer)
	if err != nil {
		return err
	}
	fmt.Println("Header:", err, buffer)

	routeBuf := make([]byte, 1)
	_, err = client.Read(routeBuf)
	if err != nil {
		return err
	}
	buffer = append(buffer, routeBuf...)
	/* heartbeat/heartbeat_response has no route */
	if routeBuf[0] > 0 {
		routeBuf = make([]byte, routeBuf[0])
		_, err = client.Read(routeBuf)
		if err != nil {
			return err
		}

		buffer = append(buffer, routeBuf...)
	}

	h, _, err := protocol.UnMarshalHeader(buffer)
	fmt.Println(h)
	if err != nil {
		return err
	}
	*header = *h

	decoder := protocol.GetEncodeDecoder(header.Encoding)
	buffer = make([]byte, header.ContentSize)
	_, err = client.Read(buffer)
	if err != nil {
		return err
	}

	return decoder.UnmarshalContent(buffer, data)
}
<commit_msg>change error define<commit_after>package tcp

import (
	"errors"
	"fmt"
	"net"

	"github.com/jennal/goplay/handler/pkg"
	"github.com/jennal/goplay/protocol"
	"github.com/jennal/goplay/transfer"
)

var (
	ERR_ALREADY_CONNECTED = errors.New("already connected")
)

type client struct {
	conn        net.Conn
	isConnected bool
}

func NewClientWithConnect(conn net.Conn) transfer.Client {
	return &client{
		conn:        conn,
		isConnected: true,
	}
}

func NewClient() transfer.Client {
	return &client{
		isConnected: false,
	}
}

func (client *client) IsConnected() bool {
	return client.isConnected
}

func (client *client) Connect(host string, port int) error {
	if client.isConnected {
		return ERR_ALREADY_CONNECTED
	}

	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		return err
	}

	client.conn = conn
	client.isConnected = true

	return nil
}

func (client *client) Disconnect() error {
	return client.conn.Close()
}

func (client *client) Read(buf []byte) (int, error) {
	return client.conn.Read(buf)
}

func (client *client) Write(buf []byte) (int, error) {
	return client.conn.Write(buf)
}

func (client *client) Send(header *pkg.Header, data interface{}) error {
	encoder := protocol.GetEncodeDecoder(header.Encoding)
	buffer, err := encoder.Marshal(header, data)
	if err != nil {
		return err
	}

	fmt.Println("Write:", header, data, buffer)

	// fmt.Println("write-0")
	_, err = client.Write(buffer)
	// fmt.Println("write-1")
	return err
}

func (client *client) Recv(header *pkg.Header, data interface{}) error {
	var buffer = make([]byte, protocol.HEADER_STATIC_SIZE)
	_, err := client.Read(buffer)
	if err != nil {
		return err
	}
	fmt.Println("Header:", err, buffer)

	routeBuf := make([]byte, 1)
	_, err = client.Read(routeBuf)
	if err != nil {
		return err
	}
	buffer = append(buffer, routeBuf...)
	/* heartbeat/heartbeat_response has no route */
	if routeBuf[0] > 0 {
		routeBuf = make([]byte, routeBuf[0])
		_, err = client.Read(routeBuf)
		if err != nil {
			return err
		}

		buffer = append(buffer, routeBuf...)
	}

	h, _, err := protocol.UnMarshalHeader(buffer)
	fmt.Println(h)
	if err != nil {
		return err
	}
	*header = *h

	decoder := protocol.GetEncodeDecoder(header.Encoding)
	buffer = make([]byte, header.ContentSize)
	_, err = client.Read(buffer)
	if err != nil {
		return err
	}

	return decoder.UnmarshalContent(buffer, data)
}
<|endoftext|>


<commit_before>// Package translate provides methods for convert Go AST to Fun AST.
package translate

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"strings"

	"github.com/jBugman/fun-lang/fun"
)

// NewFun creates new translator with provided fileset
func NewFun(fset *token.FileSet) Fun {
	return funC{fset}
}

// Fun provides methods for translation
type Fun interface {
	Module(src *ast.File) (fun.Module, error)
	Import(imp *ast.ImportSpec) (fun.Import, error)
	Function(fd *ast.FuncDecl) (fun.FuncDecl, error)
	Statement(stmt ast.Stmt) (fun.Expression, error)
	Expression(expr ast.Expr) (fun.Expression, error)
}

type funC struct {
	fset *token.FileSet
}

// Module converts Go ast.File to Fun Module.
func (conv funC) Module(src *ast.File) (fun.Module, error) {
	var module fun.Module
	// Module name
	module.Name = strings.Title(identToString(src.Name))
	// Imports
	for _, imp := range src.Imports {
		funImp, err := conv.Import(imp)
		if err != nil {
			return module, err
		}
		module.Imports = append(module.Imports, funImp)
	}
	// Top-level declarations
	for _, gd := range src.Decls {
		switch d := gd.(type) {
		case *ast.FuncDecl:
			fn, err := conv.Function(d)
			if err != nil {
				return module, err
			}
			module.Decls = append(module.Decls, fn)
		}
	}
	return module, nil
}

// Import converts Go import to Fun Import.
func (conv funC) Import(imp *ast.ImportSpec) (fun.Import, error) {
	var result fun.Import
	ex, err := conv.Expression(imp.Path)
	if err != nil {
		return result, err
	}
	s, ok := ex.(fun.String)
	if !ok {
		return result, conv.errorWithAST("not a string or char literal", imp.Path)
	}
	result.Path = string(s)
	// TODO aliases
	return result, nil
}

// Function converts Go function declaration to the Fun one.
func (conv funC) Function(fd *ast.FuncDecl) (fun.FuncDecl, error) {
	// Name
	fn := fun.FuncDecl{Name: identToString(fd.Name)}
	// Parameters
	if fd.Type.Params.List != nil {
		for _, p := range fd.Type.Params.List {
			tp := identToString(p.Type.(*ast.Ident))
			for _, n := range p.Names {
				fn.Params = append(fn.Params, fun.Parameter{Name: identToString(n), Type: fun.Type(tp)})
			}
		}
	}
	// Results
	if fd.Type.Results != nil {
		for _, p := range fd.Type.Results.List {
			tp := identToString(p.Type.(*ast.Ident))
			fn.Results = append(fn.Results, fun.Type(tp))
		}
	}
	// Body
	if fd.Body == nil {
		return fn, conv.errorWithAST("empty function body is not supported", fd)
	}
	if len(fd.Body.List) == 1 {
		// Convert to FuncApplication
		stmt, err := conv.Statement(fd.Body.List[0])
		if err != nil {
			return fn, err
		}
		fn.Body = fun.SingleExprBody{Expr: stmt}
	} else {
		// Convert to Fun DoBlock
		db := fun.DoBlock{}
		for _, stmt := range fd.Body.List {
			var buf bytes.Buffer
			printer.Fprint(&buf, conv.fset, stmt)
			db.Text = append(db.Text, buf.String())
		}
		fn.Body = db
	}

	return fn, nil
}

// Statement converts Go statement to a corresponding Fun Expression depending on type
func (conv funC) Statement(stmt ast.Stmt) (fun.Expression, error) {
	switch st := stmt.(type) {
	case *ast.ReturnStmt:
		lr := len(st.Results)
		switch lr {
		case 0:
			return nil, conv.errorWithAST("result list of zero length is not supported", st)
		case 1:
			// Single expression
			result, err := conv.Expression(st.Results[0])
			if err != nil {
				return nil, err
			}
			return result, nil
		default:
			// Tuple
			result := make(fun.Tuple, lr)
			for i := 0; i < lr; i++ {
				expr, err := conv.Expression(st.Results[i])
				if err != nil {
					return nil, err
				}
				result[i] = expr
			}
			return result, nil
		}
	case *ast.ExprStmt:
		result, err := conv.Expression(st.X)
		if err != nil {
			return nil, err
		}
		return result, nil
	default:
		return nil, conv.errorWithAST("ast.Stmt type not supported", st)
	}
}

// Expression converts Go expression to a Fun one.
func (conv funC) Expression(expr ast.Expr) (fun.Expression, error) {
	switch ex := expr.(type) {
	case *ast.Ident:
		if ex.Obj == nil {
			return nil, conv.errorWithAST("Ident with empty Obj is not supported", ex)
		}
		switch ex.Obj.Kind {
		case ast.Var:
			return fun.Val(ex.Name), nil
		default:
			return nil, conv.errorWithAST("unsupported Obj kind", ex.Obj)
		}
	case *ast.BinaryExpr:
		x, err := conv.Expression(ex.X)
		if err != nil {
			return nil, err
		}
		y, err := conv.Expression(ex.Y)
		if err != nil {
			return nil, err
		}
		result := fun.InfixOperation{X: x, Y: y, Operator: fun.Operator(ex.Op.String())}
		return result, nil
	case *ast.SelectorExpr:
		result := fun.FunctionVal{Name: identToString(ex.Sel)}
		switch x := ex.X.(type) {
		case *ast.Ident:
			result.Module = identToString(x)
		default:
			return nil, conv.errorWithAST("argument type not supported", x)
		}
		return result, nil
	case *ast.CallExpr:
		e, err := conv.Expression(ex.Fun)
		if err != nil {
			return nil, err
		}
		funcVal, ok := e.(fun.FunctionVal)
		if !ok {
			return nil, conv.errorWithAST("expected FunctionVal but got", e)
		}
		result := fun.FuncApplication{Func: funcVal}
		for _, aex := range ex.Args {
			arg, err := conv.Expression(aex)
			if err != nil {
				return nil, err
			}
			result.Arguments = append(result.Arguments, arg)
		}
		return result, nil
	case *ast.BasicLit:
		switch ex.Kind {
		case token.INT:
			return fun.Int(ex.Value), nil
		case token.FLOAT:
			return fun.Double(ex.Value), nil
		case token.STRING:
			return fun.String(strings.Trim(ex.Value, `"`)), nil
		case token.CHAR:
			return fun.Char(strings.Trim(ex.Value, "'")), nil
		case token.IMAG:
			return fun.Imaginary(ex.Value), nil
		default:
			return nil, conv.errorWithAST("unexpected literal type", ex)
		}
	default:
		return nil, conv.errorWithAST("Expr type not supported", ex)
	}
}

func (conv funC) errorWithAST(message string, obj interface{}) error {
	var buf bytes.Buffer
	ast.Fprint(&buf, conv.fset, obj, ast.NotNilFilter)
	return fmt.Errorf("%s:\n%s", message, buf.String())
}

// Shortcut for cases there Ident.Obj is not relevant
func identToString(ident *ast.Ident) string {
	return ident.Name
}
<commit_msg>Fixed interface cast crash<commit_after>// Package translate provides methods for convert Go AST to Fun AST.
package translate

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"strings"

	"github.com/jBugman/fun-lang/fun"
)

// NewFun creates new translator with provided fileset
func NewFun(fset *token.FileSet) Fun {
	return funC{fset}
}

// Fun provides methods for translation
type Fun interface {
	Module(src *ast.File) (fun.Module, error)
	Import(imp *ast.ImportSpec) (fun.Import, error)
	Function(fd *ast.FuncDecl) (fun.FuncDecl, error)
	Statement(stmt ast.Stmt) (fun.Expression, error)
	Expression(expr ast.Expr) (fun.Expression, error)
}

type funC struct {
	fset *token.FileSet
}

// Module converts Go ast.File to Fun Module.
func (conv funC) Module(src *ast.File) (fun.Module, error) {
	var module fun.Module
	// Module name
	module.Name = strings.Title(identToString(src.Name))
	// Imports
	for _, imp := range src.Imports {
		funImp, err := conv.Import(imp)
		if err != nil {
			return module, err
		}
		module.Imports = append(module.Imports, funImp)
	}
	// Top-level declarations
	for _, gd := range src.Decls {
		switch d := gd.(type) {
		case *ast.FuncDecl:
			fn, err := conv.Function(d)
			if err != nil {
				return module, err
			}
			module.Decls = append(module.Decls, fn)
		}
	}
	return module, nil
}

// Import converts Go import to Fun Import.
func (conv funC) Import(imp *ast.ImportSpec) (fun.Import, error) {
	var result fun.Import
	ex, err := conv.Expression(imp.Path)
	if err != nil {
		return result, err
	}
	s, ok := ex.(fun.String)
	if !ok {
		return result, conv.errorWithAST("not a string or char literal", imp.Path)
	}
	result.Path = string(s)
	// TODO aliases
	return result, nil
}

// Function converts Go function declaration to the Fun one.
func (conv funC) Function(fd *ast.FuncDecl) (fun.FuncDecl, error) {
	// Name
	fn := fun.FuncDecl{Name: identToString(fd.Name)}
	// Parameters
	if fd.Type.Params.List != nil {
		for _, p := range fd.Type.Params.List {
			ex, ok := p.Type.(*ast.Ident)
			if !ok {
				return fn, conv.errorWithAST("not supported type", p.Type)
			}
			tp := identToString(ex)
			for _, n := range p.Names {
				fn.Params = append(fn.Params, fun.Parameter{Name: identToString(n), Type: fun.Type(tp)})
			}
		}
	}
	// Results
	if fd.Type.Results != nil {
		for _, p := range fd.Type.Results.List {
			tp := identToString(p.Type.(*ast.Ident))
			fn.Results = append(fn.Results, fun.Type(tp))
		}
	}
	// Body
	if fd.Body == nil {
		return fn, conv.errorWithAST("empty function body is not supported", fd)
	}
	if len(fd.Body.List) == 1 {
		// Convert to FuncApplication
		stmt, err := conv.Statement(fd.Body.List[0])
		if err != nil {
			return fn, err
		}
		fn.Body = fun.SingleExprBody{Expr: stmt}
	} else {
		// Convert to Fun DoBlock
		db := fun.DoBlock{}
		for _, stmt := range fd.Body.List {
			var buf bytes.Buffer
			printer.Fprint(&buf, conv.fset, stmt)
			db.Text = append(db.Text, buf.String())
		}
		fn.Body = db
	}

	return fn, nil
}

// Statement converts Go statement to a corresponding Fun Expression depending on type
func (conv funC) Statement(stmt ast.Stmt) (fun.Expression, error) {
	switch st := stmt.(type) {
	case *ast.ReturnStmt:
		lr := len(st.Results)
		switch lr {
		case 0:
			return nil, conv.errorWithAST("result list of zero length is not supported", st)
		case 1:
			// Single expression
			result, err := conv.Expression(st.Results[0])
			if err != nil {
				return nil, err
			}
			return result, nil
		default:
			// Tuple
			result := make(fun.Tuple, lr)
			for i := 0; i < lr; i++ {
				expr, err := conv.Expression(st.Results[i])
				if err != nil {
					return nil, err
				}
				result[i] = expr
			}
			return result, nil
		}
	case *ast.ExprStmt:
		result, err := conv.Expression(st.X)
		if err != nil {
			return nil, err
		}
		return result, nil
	default:
		return nil, conv.errorWithAST("ast.Stmt type not supported", st)
	}
}

// Expression converts Go expression to a Fun one.
func (conv funC) Expression(expr ast.Expr) (fun.Expression, error) {
	switch ex := expr.(type) {
	case *ast.Ident:
		if ex.Obj == nil {
			return nil, conv.errorWithAST("Ident with empty Obj is not supported", ex)
		}
		switch ex.Obj.Kind {
		case ast.Var:
			return fun.Val(ex.Name), nil
		default:
			return nil, conv.errorWithAST("unsupported Obj kind", ex.Obj)
		}
	case *ast.BinaryExpr:
		x, err := conv.Expression(ex.X)
		if err != nil {
			return nil, err
		}
		y, err := conv.Expression(ex.Y)
		if err != nil {
			return nil, err
		}
		result := fun.InfixOperation{X: x, Y: y, Operator: fun.Operator(ex.Op.String())}
		return result, nil
	case *ast.SelectorExpr:
		result := fun.FunctionVal{Name: identToString(ex.Sel)}
		switch x := ex.X.(type) {
		case *ast.Ident:
			result.Module = identToString(x)
		default:
			return nil, conv.errorWithAST("argument type not supported", x)
		}
		return result, nil
	case *ast.CallExpr:
		e, err := conv.Expression(ex.Fun)
		if err != nil {
			return nil, err
		}
		funcVal, ok := e.(fun.FunctionVal)
		if !ok {
			return nil, conv.errorWithAST("expected FunctionVal but got", e)
		}
		result := fun.FuncApplication{Func: funcVal}
		for _, aex := range ex.Args {
			arg, err := conv.Expression(aex)
			if err != nil {
				return nil, err
			}
			result.Arguments = append(result.Arguments, arg)
		}
		return result, nil
	case *ast.BasicLit:
		switch ex.Kind {
		case token.INT:
			return fun.Int(ex.Value), nil
		case token.FLOAT:
			return fun.Double(ex.Value), nil
		case token.STRING:
			return fun.String(strings.Trim(ex.Value, `"`)), nil
		case token.CHAR:
			return fun.Char(strings.Trim(ex.Value, "'")), nil
		case token.IMAG:
			return fun.Imaginary(ex.Value), nil
		default:
			return nil, conv.errorWithAST("unexpected literal type", ex)
		}
	default:
		return nil, conv.errorWithAST("Expr type not supported", ex)
	}
}

func (conv funC) errorWithAST(message string, obj interface{}) error {
	var buf bytes.Buffer
	ast.Fprint(&buf, conv.fset, obj, ast.NotNilFilter)
	return fmt.Errorf("%s:\n%s", message, buf.String())
}

// Shortcut for cases there Ident.Obj is not relevant
func identToString(ident *ast.Ident) string {
	return ident.Name
}
<|endoftext|>


<commit_before>// Package translate provides methods for convert Go AST to Fun AST.
package translate

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"strings"

	"github.com/jBugman/fun-lang/fun"
)

// FromFile converts Go ast.File to Fun Module.
func FromFile(fset *token.FileSet, src *ast.File) (fun.Module, error) {
	var module fun.Module
	// Module name
	module.Name = strings.Title(identToString(src.Name))
	// Imports
	for _, imp := range src.Imports {
		funImp, err := Import(imp)
		if err != nil {
			return module, err
		}
		module.Imports = append(module.Imports, funImp)
	}
	// Top-level declarations
	for _, gd := range src.Decls {
		switch d := gd.(type) {
		case *ast.FuncDecl:
			fn, err := Function(fset, d)
			if err != nil {
				return module, err
			}
			module.Decls = append(module.Decls, fn)
		}
	}
	return module, nil
}

// Import converts Go import to Fun Import.
func Import(imp *ast.ImportSpec) (fun.Import, error) {
	var result fun.Import
	var err error
	result.Path, err = litStringToString(imp.Path)
	if err != nil {
		return result, err
	}
	// TODO aliases
	return result, nil
}

// Function converts Go function declaration to the Fun one.
func Function(fset *token.FileSet, fd *ast.FuncDecl) (fun.FuncDecl, error) {
	// Name
	fn := fun.FuncDecl{Name: identToString(fd.Name)}
	// Parameters
	if fd.Type.Params.List != nil {
		for _, p := range fd.Type.Params.List {
			tp := identToString(p.Type.(*ast.Ident))
			for _, n := range p.Names {
				fn.Params = append(fn.Params, fun.Parameter{Name: identToString(n), Type: fun.Type(tp)})
			}
		}
	}
	// Results
	if fd.Type.Results != nil {
		for _, p := range fd.Type.Results.List {
			tp := identToString(p.Type.(*ast.Ident))
			fn.Results = append(fn.Results, fun.Type(tp))
		}
	}
	// Body
	if fd.Body == nil {
		return fn, fmt.Errorf("empty function body is not supported: %v", fd)
	}
	if len(fd.Body.List) == 1 {
		// Convert to FuncApplication
		stmt, err := Statement(fset, fd.Body.List[0])
		if err != nil {
			return fn, err
		}
		fn.Body = fun.SingleExprBody{Expr: stmt}
	} else {
		// Convert to Fun DoBlock
		db := fun.DoBlock{}
		for _, stmt := range fd.Body.List {
			var buf bytes.Buffer
			printer.Fprint(&buf, fset, stmt)
			db.Text = append(db.Text, buf.String())
		}
		fn.Body = db
	}

	return fn, nil
}

// Statement converts Go statement to a corresponding Fun Expression depending on type
func Statement(fset *token.FileSet, stmt ast.Stmt) (fun.Expression, error) {
	switch st := stmt.(type) {
	case *ast.ReturnStmt:
		ast.Print(fset, st)
		return fun.Undefined, nil // TODO binary expr
	case *ast.ExprStmt:
		result, err := Expression(fset, st.X)
		if err != nil {
			return nil, err
		}
		return result, nil
	default:
		// debug
		ast.Print(fset, st)
		return nil, fmt.Errorf("ast.Stmt type not supported: %v", st) // TODO add more
	}
}

// Expression converts Go expression to a Fun one.
func Expression(fset *token.FileSet, expr ast.Expr) (fun.Expression, error) {
	switch ex := expr.(type) {
	case *ast.BinaryExpr:
		// TODO
		return nil, fmt.Errorf("BinaryExpr is not implemented yet")
	case *ast.SelectorExpr:
		result := fun.FunctionVal{Name: identToString(ex.Sel)}
		switch x := ex.X.(type) {
		case *ast.Ident:
			result.Module = identToString(x)
		default:
			ast.Print(fset, x)
			return result, fmt.Errorf("argument type not supported: %v", x) // TODO add more
		}
		return result, nil
	case *ast.CallExpr:
		e, err := Expression(fset, ex.Fun)
		if err != nil {
			return nil, err
		}
		funcVal, ok := e.(fun.FunctionVal)
		if !ok {
			return nil, fmt.Errorf("expected FunctionVal but got %+v", e)
		}
		result := fun.FuncApplication{Func: funcVal}
		var arg fun.Expression
		for _, ea := range ex.Args {
			switch a := ea.(type) {
			case *ast.BasicLit:
				arg = litToExpression(a)
			default:
				ast.Print(fset, ea)
				return nil, fmt.Errorf("argument type not supported: %v", ea) // TODO add more
			}
			result.Arguments = append(result.Arguments, arg)
		}
		return result, nil
	default:
		// debug
		ast.Print(fset, ex)
		return nil, fmt.Errorf("Expr type not supported: %v", ex) // TODO add more
	}
}

func litToExpression(lit *ast.BasicLit) fun.Expression {
	switch lit.Kind {
	case token.INT:
		return fun.Int(lit.Value)
	case token.FLOAT:
		return fun.Double(lit.Value)
	case token.STRING:
		s, _ := litStringToString(lit) // should not be error
		return fun.String(s)
	case token.CHAR:
		s, _ := litStringToString(lit) // should not be error
		return fun.Char(s)
	case token.IMAG:
		return fun.Imaginary(lit.Value)
	default:
		panic(fmt.Sprintf("unexpected type: %v", lit))
	}
}

func identToString(ident *ast.Ident) string {
	return ident.Name
}

func litStringToString(lit *ast.BasicLit) (string, error) {
	switch lit.Kind {
	case token.STRING:
		return strings.Trim(lit.Value, `"`), nil
	case token.CHAR:
		return strings.Trim(lit.Value, "'"), nil
	default:
		return "", fmt.Errorf("not a string or char literal: %v", lit)
	}
}
<commit_msg>ReturnStmt converter<commit_after>// Package translate provides methods for convert Go AST to Fun AST.
package translate

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"strings"

	"github.com/jBugman/fun-lang/fun"
)

// FromFile converts Go ast.File to Fun Module.
func FromFile(fset *token.FileSet, src *ast.File) (fun.Module, error) {
	var module fun.Module
	// Module name
	module.Name = strings.Title(identToString(src.Name))
	// Imports
	for _, imp := range src.Imports {
		funImp, err := Import(imp)
		if err != nil {
			return module, err
		}
		module.Imports = append(module.Imports, funImp)
	}
	// Top-level declarations
	for _, gd := range src.Decls {
		switch d := gd.(type) {
		case *ast.FuncDecl:
			fn, err := Function(fset, d)
			if err != nil {
				return module, err
			}
			module.Decls = append(module.Decls, fn)
		}
	}
	return module, nil
}

// Import converts Go import to Fun Import.
func Import(imp *ast.ImportSpec) (fun.Import, error) {
	var result fun.Import
	var err error
	result.Path, err = litStringToString(imp.Path)
	if err != nil {
		return result, err
	}
	// TODO aliases
	return result, nil
}

// Function converts Go function declaration to the Fun one.
func Function(fset *token.FileSet, fd *ast.FuncDecl) (fun.FuncDecl, error) {
	// Name
	fn := fun.FuncDecl{Name: identToString(fd.Name)}
	// Parameters
	if fd.Type.Params.List != nil {
		for _, p := range fd.Type.Params.List {
			tp := identToString(p.Type.(*ast.Ident))
			for _, n := range p.Names {
				fn.Params = append(fn.Params, fun.Parameter{Name: identToString(n), Type: fun.Type(tp)})
			}
		}
	}
	// Results
	if fd.Type.Results != nil {
		for _, p := range fd.Type.Results.List {
			tp := identToString(p.Type.(*ast.Ident))
			fn.Results = append(fn.Results, fun.Type(tp))
		}
	}
	// Body
	if fd.Body == nil {
		return fn, fmt.Errorf("empty function body is not supported: %v", fd)
	}
	if len(fd.Body.List) == 1 {
		// Convert to FuncApplication
		stmt, err := Statement(fset, fd.Body.List[0])
		if err != nil {
			return fn, err
		}
		fn.Body = fun.SingleExprBody{Expr: stmt}
	} else {
		// Convert to Fun DoBlock
		db := fun.DoBlock{}
		for _, stmt := range fd.Body.List {
			var buf bytes.Buffer
			printer.Fprint(&buf, fset, stmt)
			db.Text = append(db.Text, buf.String())
		}
		fn.Body = db
	}

	return fn, nil
}

// Statement converts Go statement to a corresponding Fun Expression depending on type
func Statement(fset *token.FileSet, stmt ast.Stmt) (fun.Expression, error) {
	switch st := stmt.(type) {
	case *ast.ReturnStmt:
		lr := len(st.Results)
		switch lr {
		case 0:
			return nil, fmt.Errorf("result list of zero length is not supported: %+v", st)
		case 1:
			// Single expression
			result, err := Expression(fset, st.Results[0])
			if err != nil {
				return nil, err
			}
			return result, nil
		default:
			// Tuple
			result := make(fun.Tuple, lr)
			for i := 0; i < lr; i++ {
				expr, err := Expression(fset, st.Results[i])
				if err != nil {
					return nil, err
				}
				result = append(result, expr)
			}
			return result, nil
		}
	case *ast.ExprStmt:
		result, err := Expression(fset, st.X)
		if err != nil {
			return nil, err
		}
		return result, nil
	default:
		// debug
		ast.Print(fset, st)
		return nil, fmt.Errorf("ast.Stmt type not supported: %v", st) // TODO add more
	}
}

// Expression converts Go expression to a Fun one.
func Expression(fset *token.FileSet, expr ast.Expr) (fun.Expression, error) {
	switch ex := expr.(type) {
	// case *ast.BinaryExpr:
	// 	result := fun.InfixOperation{}
	// 	return result, nil
	case *ast.SelectorExpr:
		result := fun.FunctionVal{Name: identToString(ex.Sel)}
		switch x := ex.X.(type) {
		case *ast.Ident:
			result.Module = identToString(x)
		default:
			ast.Print(fset, x)
			return result, fmt.Errorf("argument type not supported: %v", x) // TODO add more
		}
		return result, nil
	case *ast.CallExpr:
		e, err := Expression(fset, ex.Fun)
		if err != nil {
			return nil, err
		}
		funcVal, ok := e.(fun.FunctionVal)
		if !ok {
			return nil, fmt.Errorf("expected FunctionVal but got %+v", e)
		}
		result := fun.FuncApplication{Func: funcVal}
		var arg fun.Expression
		for _, ea := range ex.Args {
			switch a := ea.(type) {
			case *ast.BasicLit:
				arg = litToExpression(a)
			default:
				ast.Print(fset, ea)
				return nil, fmt.Errorf("argument type not supported: %v", ea) // TODO add more
			}
			result.Arguments = append(result.Arguments, arg)
		}
		return result, nil
	default:
		// debug
		ast.Print(fset, ex)
		return nil, fmt.Errorf("Expr type not supported: %v", ex) // TODO add more
	}
}

func litToExpression(lit *ast.BasicLit) fun.Expression {
	switch lit.Kind {
	case token.INT:
		return fun.Int(lit.Value)
	case token.FLOAT:
		return fun.Double(lit.Value)
	case token.STRING:
		s, _ := litStringToString(lit) // should not be error
		return fun.String(s)
	case token.CHAR:
		s, _ := litStringToString(lit) // should not be error
		return fun.Char(s)
	case token.IMAG:
		return fun.Imaginary(lit.Value)
	default:
		panic(fmt.Sprintf("unexpected type: %v", lit))
	}
}

func identToString(ident *ast.Ident) string {
	return ident.Name
}

func litStringToString(lit *ast.BasicLit) (string, error) {
	switch lit.Kind {
	case token.STRING:
		return strings.Trim(lit.Value, `"`), nil
	case token.CHAR:
		return strings.Trim(lit.Value, "'"), nil
	default:
		return "", fmt.Errorf("not a string or char literal: %v", lit)
	}
}
<|endoftext|>


<commit_before>package turnservicecli

// CredentialsResponse defines a REST response containing TURN data.
type CredentialsResponse struct {
	Success bool             `json:"success"`
	Nonce   string           `json:"nonce"`
	Turn    *CredentialsData `json:"turn"`
	Session string           `json:"session,omitempty"`
}

// CredentialsData defines TURN credentials with servers.
type CredentialsData struct {
	TTL      int64         `json:"ttl"`
	Username string        `json:"username"`
	Password string        `json:"password"`
	Servers  []*URNsWithID `json:"servers,omitempty"`
	GeoURI   string        `json:"geo_uri,omitempty"`
}

// URNsWithID defines TURN servers groups with ID.
type URNsWithID struct {
	ID   string   `json:"id"`
	URNs []string `json:"urns"`
	Prio int      `json:"prio"`
}

// GeoResponse defines a REST response containing TURN geo.
type GeoResponse struct {
	Success bool     `json:"success"`
	Nonce   string   `json:"nonce"`
	Geo     *GeoData `json:"geo,omitempty"`
}

// GeoData defines ordered TURN IDs.
type GeoData struct {
	Prefer []string `json:"prefer"`
}
<commit_msg>Add support for TURN server labels<commit_after>package turnservicecli

// CredentialsResponse defines a REST response containing TURN data.
type CredentialsResponse struct {
	Success bool             `json:"success"`
	Nonce   string           `json:"nonce"`
	Turn    *CredentialsData `json:"turn"`
	Session string           `json:"session,omitempty"`
}

// CredentialsData defines TURN credentials with servers.
type CredentialsData struct {
	TTL      int64         `json:"ttl"`
	Username string        `json:"username"`
	Password string        `json:"password"`
	Servers  []*URNsWithID `json:"servers,omitempty"`
	GeoURI   string        `json:"geo_uri,omitempty"`
}

// URNsWithID defines TURN servers groups with ID.
type URNsWithID struct {
	ID    string            `json:"id"`
	URNs  []string          `json:"urns"`
	Prio  int               `json:"prio"`
	Label string            `json:"label,omitempty"`
	I18N  map[string]string `json:"i18n,omitempty"`
}

// GeoResponse defines a REST response containing TURN geo.
type GeoResponse struct {
	Success bool     `json:"success"`
	Nonce   string   `json:"nonce"`
	Geo     *GeoData `json:"geo,omitempty"`
}

// GeoData defines ordered TURN IDs.
type GeoData struct {
	Prefer []string `json:"prefer"`
}
<|endoftext|>


<commit_before>package utils

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"os"

	"github.com/lxc/lxd/shared/i18n"
	"github.com/olekukonko/tablewriter"
	"gopkg.in/yaml.v2"
)

// Table list format.
const (
	TableFormatCSV     = "csv"
	TableFormatJSON    = "json"
	TableFormatTable   = "table"
	TableFormatYAML    = "yaml"
	TableFormatCompact = "compact"
)

// RenderTable renders tabular data in various formats.
func RenderTable(format string, header []string, data [][]string, raw any) error {
	switch format {
	case TableFormatTable:
		table := getBaseTable(header, data)
		table.SetRowLine(true)
		table.Render()
	case TableFormatCompact:
		table := getBaseTable(header, data)
		table.SetColumnSeparator("")
		table.SetHeaderLine(false)
		table.SetBorder(false)
		table.Render()
	case TableFormatCSV:
		w := csv.NewWriter(os.Stdout)
		err := w.WriteAll(data)
		if err != nil {
			return err
		}

		err = w.Error()
		if err != nil {
			return err
		}
	case TableFormatJSON:
		enc := json.NewEncoder(os.Stdout)

		err := enc.Encode(raw)
		if err != nil {
			return err
		}
	case TableFormatYAML:
		out, err := yaml.Marshal(raw)
		if err != nil {
			return err
		}

		fmt.Printf("%s", out)
	default:
		return fmt.Errorf(i18n.G("Invalid format %q"), format)
	}

	return nil
}

func getBaseTable(header []string, data [][]string) *tablewriter.Table {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetAutoWrapText(false)
	table.SetAlignment(tablewriter.ALIGN_LEFT)
	table.SetHeader(header)
	table.AppendBulk(data)
	return table
}
<commit_msg>lxc/utils: Fix import order.<commit_after>package utils

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"os"

	"github.com/olekukonko/tablewriter"
	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd/shared/i18n"
)

// Table list format.
const (
	TableFormatCSV     = "csv"
	TableFormatJSON    = "json"
	TableFormatTable   = "table"
	TableFormatYAML    = "yaml"
	TableFormatCompact = "compact"
)

// RenderTable renders tabular data in various formats.
func RenderTable(format string, header []string, data [][]string, raw any) error {
	switch format {
	case TableFormatTable:
		table := getBaseTable(header, data)
		table.SetRowLine(true)
		table.Render()
	case TableFormatCompact:
		table := getBaseTable(header, data)
		table.SetColumnSeparator("")
		table.SetHeaderLine(false)
		table.SetBorder(false)
		table.Render()
	case TableFormatCSV:
		w := csv.NewWriter(os.Stdout)
		err := w.WriteAll(data)
		if err != nil {
			return err
		}

		err = w.Error()
		if err != nil {
			return err
		}
	case TableFormatJSON:
		enc := json.NewEncoder(os.Stdout)

		err := enc.Encode(raw)
		if err != nil {
			return err
		}
	case TableFormatYAML:
		out, err := yaml.Marshal(raw)
		if err != nil {
			return err
		}

		fmt.Printf("%s", out)
	default:
		return fmt.Errorf(i18n.G("Invalid format %q"), format)
	}

	return nil
}

func getBaseTable(header []string, data [][]string) *tablewriter.Table {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetAutoWrapText(false)
	table.SetAlignment(tablewriter.ALIGN_LEFT)
	table.SetHeader(header)
	table.AppendBulk(data)
	return table
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/m-nakada/slackposter"
	"strings"
)

type MessageBuilder struct {
	GitHubOwner  string
	GitHubRepo   string
	UsersManager UsersManager
}

func (builder MessageBuilder) titleString(pull PullRequest) string {
	username := builder.UsersManager.ConvertGitHubToSlack(pull.User.Login)
	return fmt.Sprintf("\t<%s|[#%d, %s]> by `%s`",
		pull.HTMLURL, pull.Number, pull.Title, username)
}

func (builder MessageBuilder) allAssigneeString(pull PullRequest) string {
	if len(pull.Assignees) == 0 {
		return "*アサインお願いします*"
	}

	var str = ""
	for _, assignee := range pull.Assignees {
		name := builder.UsersManager.ConvertGitHubToSlack(assignee.Login)
		str += "@" + name + " "
	}
	return str
}

func (builder MessageBuilder) reviewerString(pull PullRequest, thumbsUppers []string) string {
	var str = ""
	for _, assignee := range pull.Assignees {
		assigneeLogin := builder.UsersManager.ConvertGitHubToSlack(assignee.Login)
		found := false
		for _, thumbsUpper := range thumbsUppers {
			if assigneeLogin == thumbsUpper {
				found = true
				break
			}
		}
		if found == false {
			str += "@" + assigneeLogin + " "
		}
	}
	return str
}

func (builder MessageBuilder) BudildSummary(pullsCount int) string {
	repo := builder.GitHubOwner + "/" + builder.GitHubRepo
	url := "https://github.com/" + repo
	link := fmt.Sprintf("<%s|%s>", url, repo)

	var summary string
	switch pullsCount {
	case 0:
		summary = fmt.Sprintf("There's no open pull request for %s :tada: Let's take a break :dango: :tea:", link)
	case 1:
		summary = fmt.Sprintf("There's only one open pull request for %s :point_up:", link)
	default:
		summary = fmt.Sprintf("I found %d open pull requests for %s:\n", pullsCount, link)
	}
	return summary
}

func (builder MessageBuilder) BuildAttachment(pull PullRequest, comments []Comment) slackposter.Attachment {

	var thumbsUppers []string

	for _, comment := range comments {
		if strings.Contains(comment.Body, ":+1:") || strings.Contains(comment.Body, "👍") {
			username := builder.UsersManager.ConvertGitHubToSlack(comment.User.Login)
			thumbsUppers = append(thumbsUppers, username)
		}
	}

	title := builder.titleString(pull)
	var color, reaction, mention string
	switch len(thumbsUppers) {
	case 0:
		reaction = ":fearful:"
		color = "danger"
		name := builder.allAssigneeString(pull)
		mention = "=> " + name
	case 1:
		reaction = ":+1:"
		color = "warning"
		name := builder.reviewerString(pull, thumbsUppers)
		mention = " => " + name
	default:
		reaction = ":+1: :+1:"
		color = "good"
		name := "@" + builder.UsersManager.ConvertGitHubToSlack(pull.User.Login)
		mention = name + "*マージお願いします*"
	}

	var message = title + " | " + reaction + " | " + mention

	var attachment slackposter.Attachment
	attachment = slackposter.Attachment{
		Fallback: message,
		Text:     message,
		Color:    color,
		Fields:   []slackposter.Field{},
		MrkdwnIn: []string{"text", "fallback"},
	}

	return attachment
}

func NewMessageBuilder(gh GitHubAPI, usersManager UsersManager) MessageBuilder {
	return MessageBuilder{
		GitHubOwner:  gh.Owner,
		GitHubRepo:   gh.Repo,
		UsersManager: usersManager,
	}
}
<commit_msg>Refine message format<commit_after>package main

import (
	"fmt"
	"github.com/m-nakada/slackposter"
	"strings"
)

type MessageBuilder struct {
	GitHubOwner  string
	GitHubRepo   string
	UsersManager UsersManager
}

func (builder MessageBuilder) titleString(pull PullRequest) string {
	return fmt.Sprintf("\t<%s|#%d> %s by %s",
		pull.HTMLURL, pull.Number, pull.Title, pull.User.Login)
}

func (builder MessageBuilder) allAssigneeString(pull PullRequest) string {
	if len(pull.Assignees) == 0 {
		name := builder.UsersManager.ConvertGitHubToSlack(pull.User.Login)
		return "@" + name + " *Assignee の指定をお願いします*"
	}

	var str = ""
	for _, assignee := range pull.Assignees {
		name := builder.UsersManager.ConvertGitHubToSlack(assignee.Login)
		str += "@" + name + " "
	}
	return str
}

func (builder MessageBuilder) reviewerString(pull PullRequest, thumbsUppers []string) string {
	var str = ""
	for _, assignee := range pull.Assignees {
		assigneeLogin := builder.UsersManager.ConvertGitHubToSlack(assignee.Login)
		found := false
		for _, thumbsUpper := range thumbsUppers {
			if assigneeLogin == thumbsUpper {
				found = true
				break
			}
		}
		if found == false {
			str += "@" + assigneeLogin + " "
		}
	}
	return str
}

func (builder MessageBuilder) BudildSummary(pullsCount int) string {
	repo := builder.GitHubOwner + "/" + builder.GitHubRepo
	url := "https://github.com/" + repo
	link := fmt.Sprintf("<%s|%s>", url, repo)

	var summary string
	switch pullsCount {
	case 0:
		summary = fmt.Sprintf("There's no open pull request for %s :tada: Let's take a break :dango: :tea:", link)
	case 1:
		summary = fmt.Sprintf("There's only one open pull request for %s :point_up:", link)
	default:
		summary = fmt.Sprintf("I found %d open pull requests for %s:\n", pullsCount, link)
	}
	return summary
}

func (builder MessageBuilder) BuildAttachment(pull PullRequest, comments []Comment) slackposter.Attachment {

	var thumbsUppers []string

	for _, comment := range comments {
		if strings.Contains(comment.Body, ":+1:") || strings.Contains(comment.Body, "👍") {
			username := builder.UsersManager.ConvertGitHubToSlack(comment.User.Login)
			thumbsUppers = append(thumbsUppers, username)
		}
	}

	title := builder.titleString(pull)
	var color, reaction, mention string
	switch len(thumbsUppers) {
	case 0:
		reaction = ""
		color = "danger"
		name := builder.allAssigneeString(pull)
		mention = "=> " + name
	case 1:
		reaction = ":+1:"
		color = "warning"
		name := builder.reviewerString(pull, thumbsUppers)
		mention = "=> " + name
	default:
		reaction = ":+1::+1:"
		color = "good"
		name := "@" + builder.UsersManager.ConvertGitHubToSlack(pull.User.Login)
		mention = name + " *マージお願いします*"
	}

	var message = title + " " + reaction + "\n" + mention

	var attachment slackposter.Attachment
	attachment = slackposter.Attachment{
		Fallback: message,
		Text:     message,
		Color:    color,
		Fields:   []slackposter.Field{},
		MrkdwnIn: []string{"text", "fallback"},
	}

	return attachment
}

func NewMessageBuilder(gh GitHubAPI, usersManager UsersManager) MessageBuilder {
	return MessageBuilder{
		GitHubOwner:  gh.Owner,
		GitHubRepo:   gh.Repo,
		UsersManager: usersManager,
	}
}
<|endoftext|>


<commit_before>package auth

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"strings"

	"code.google.com/p/vitess/go/relog"
	rpc "code.google.com/p/vitess/go/rpcplus"
	"code.google.com/p/vitess/go/rpcwrap/proto"
)

// UnusedArgument is a type used to indicate an argument that is
// necessary because of net/rpc requirements.
type UnusedArgument string

// cramMD5Credentials maps usernames to lists of secrets.
type cramMD5Credentials map[string][]string

// AuthenticatorCRAMMD5 is an authenticator that uses the SASL
// CRAM-MD5 authentication mechanism.
type AuthenticatorCRAMMD5 struct {
	Credentials cramMD5Credentials
}

// Load loads the contents of a JSON file named
// filename into c.
func (c *cramMD5Credentials) Load(filename string) error {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	if err = json.Unmarshal(data, c); err != nil {
		return err
	}
	relog.Info("Loaded credentials from %s.", filename)
	return nil
}

// CRAMMD5MaxRequests is the maximum number of requests that an
// unauthenticated client is allowed to make (this should be enough to
// perform authentication).
const CRAMMD5MaxRequests = 2

var (
	AuthenticationServer        = rpc.NewServer()
	DefaultAuthenticatorCRAMMD5 = NewAuthenticatorCRAMMD5()
)

// AuthenticationFailed is returned when the client fails to
// authenticate.
var AuthenticationFailed = errors.New("authentication error: authentication failed")

func NewAuthenticatorCRAMMD5() *AuthenticatorCRAMMD5 {
	return &AuthenticatorCRAMMD5{make(cramMD5Credentials)}
}

// LoadCredentials loads credentials stored in the JSON file named
// filename into the default authenticator.
func LoadCredentials(filename string) error {
	return DefaultAuthenticatorCRAMMD5.Credentials.Load(filename)
}

// Authenticate returns true if it the client manages to authenticate
// the codec in at most maxRequest number of requests.
func Authenticate(c rpc.ServerCodec, context *proto.Context) (bool, error) {
	auth := newAuthenticatedCodec(c)
	for i := 0; i < CRAMMD5MaxRequests; i++ {
		err := AuthenticationServer.ServeRequestWithContext(auth, context)
		if err != nil {
			return false, err
		}
		if auth.OK() {
			return true, nil
		}
	}
	return false, nil
}

// GetNewChallenge gives the client a new challenge for
// authentication.
func (a *AuthenticatorCRAMMD5) GetNewChallenge(_ UnusedArgument, reply *GetNewChallengeReply) error {
	var err error
	reply.Challenge, err = CRAMMD5GetChallenge()
	if err != nil {
		return err
	}
	return nil
}

// Authenticate checks if the client proof is correct.
func (a *AuthenticatorCRAMMD5) Authenticate(context proto.Context, req *AuthenticateRequest, reply *AuthenticateReply) error {
	username := strings.SplitN(req.Proof, " ", 2)[0]
	secrets, ok := a.Credentials[username]
	if !ok {
		relog.Warning("failed authentication attempt: wrong user: %#v", username)
		return AuthenticationFailed
	}
	if !req.state.challengeIssued {
		relog.Warning("failed authentication attempt: challenge was not issued")
		return AuthenticationFailed
	}
	for _, secret := range secrets {
		if expected := CRAMMD5GetExpected(username, secret, req.state.challenge); expected == req.Proof {
			context.Username = username
			return nil
		}
	}
	relog.Warning("failed authentication attempt: wrong proof")
	return AuthenticationFailed
}

type GetNewChallengeReply struct {
	Challenge string
}

type AuthenticateReply struct{}

type AuthenticateRequest struct {
	Proof string
	state authenticationState
}

// authenticationState maintains the state of the authentication and
// is passed between authenticatedCodec and AuthenticateRequest.
type authenticationState struct {
	authenticated   bool
	challenge       string
	challengeIssued bool
}

// authenticatedCodec is a codec that uses AuthenticatorCRAMMD5 to
// authenticate a request (it implements rpc.ServerCodec). Any
// requests performed before successful authentication will fail.
type authenticatedCodec struct {
	rpc.ServerCodec
	currentMethod string
	state         authenticationState
}

// OK returns true if the codec is authenticated.
func (c *authenticatedCodec) OK() bool {
	return c.state.authenticated
}

// newAuthenticatedCodec returns a fresh authenticatedCodec (in a
// non-authenticated state).
func newAuthenticatedCodec(codec rpc.ServerCodec) *authenticatedCodec {
	return &authenticatedCodec{ServerCodec: codec}
}

// isAuthenticationMethod returns true if method is the name of an
// authentication method.
func isAuthenticationMethod(method string) bool {
	return strings.HasPrefix(method, "AuthenticatorCRAMMD5.")
}

func (c *authenticatedCodec) ReadRequestHeader(r *rpc.Request) error {
	err := c.ServerCodec.ReadRequestHeader(r)

	if err != nil {
		return err
	}

	c.currentMethod = r.ServiceMethod
	return err
}

func (c *authenticatedCodec) ReadRequestBody(body interface{}) error {
	err := c.ServerCodec.ReadRequestBody(body)

	if err != nil {
		return err
	}

	if !isAuthenticationMethod(c.currentMethod) {
		return fmt.Errorf("authentication error: authentication required for %s", c.currentMethod)
	}

	if b, ok := body.(*AuthenticateRequest); ok {
		b.state = c.state
	}

	return err
}

func (c *authenticatedCodec) WriteResponse(r *rpc.Response, body interface{}, last bool) error {
	c.transferState(body)
	return c.ServerCodec.WriteResponse(r, body, last)
}

// transferState transfers the authentication state from body
// (returned by an authentication rpc call) to the codec.
func (c *authenticatedCodec) transferState(body interface{}) {
	switch body.(type) {
	case *GetNewChallengeReply:
		c.state.challenge = body.(*GetNewChallengeReply).Challenge
		c.state.challengeIssued = true
	case *AuthenticateReply:
		c.state.authenticated = true
		c.state.challenge = ""
		c.state.challengeIssued = false
	}
}

func init() {
	AuthenticationServer.Register(DefaultAuthenticatorCRAMMD5)
}
<commit_msg>Fix typo in authentication.<commit_after>package auth

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"strings"

	"code.google.com/p/vitess/go/relog"
	rpc "code.google.com/p/vitess/go/rpcplus"
	"code.google.com/p/vitess/go/rpcwrap/proto"
)

// UnusedArgument is a type used to indicate an argument that is
// necessary because of net/rpc requirements.
type UnusedArgument string

// cramMD5Credentials maps usernames to lists of secrets.
type cramMD5Credentials map[string][]string

// AuthenticatorCRAMMD5 is an authenticator that uses the SASL
// CRAM-MD5 authentication mechanism.
type AuthenticatorCRAMMD5 struct {
	Credentials cramMD5Credentials
}

// Load loads the contents of a JSON file named
// filename into c.
func (c *cramMD5Credentials) Load(filename string) error {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	if err = json.Unmarshal(data, c); err != nil {
		return err
	}
	relog.Info("Loaded credentials from %s.", filename)
	return nil
}

// CRAMMD5MaxRequests is the maximum number of requests that an
// unauthenticated client is allowed to make (this should be enough to
// perform authentication).
const CRAMMD5MaxRequests = 2

var (
	AuthenticationServer        = rpc.NewServer()
	DefaultAuthenticatorCRAMMD5 = NewAuthenticatorCRAMMD5()
)

// AuthenticationFailed is returned when the client fails to
// authenticate.
var AuthenticationFailed = errors.New("authentication error: authentication failed")

func NewAuthenticatorCRAMMD5() *AuthenticatorCRAMMD5 {
	return &AuthenticatorCRAMMD5{make(cramMD5Credentials)}
}

// LoadCredentials loads credentials stored in the JSON file named
// filename into the default authenticator.
func LoadCredentials(filename string) error {
	return DefaultAuthenticatorCRAMMD5.Credentials.Load(filename)
}

// Authenticate returns true if it the client manages to authenticate
// the codec in at most maxRequest number of requests.
func Authenticate(c rpc.ServerCodec, context *proto.Context) (bool, error) {
	auth := newAuthenticatedCodec(c)
	for i := 0; i < CRAMMD5MaxRequests; i++ {
		err := AuthenticationServer.ServeRequestWithContext(auth, context)
		if err != nil {
			return false, err
		}
		if auth.OK() {
			return true, nil
		}
	}
	return false, nil
}

// GetNewChallenge gives the client a new challenge for
// authentication.
func (a *AuthenticatorCRAMMD5) GetNewChallenge(_ UnusedArgument, reply *GetNewChallengeReply) error {
	var err error
	reply.Challenge, err = CRAMMD5GetChallenge()
	if err != nil {
		return err
	}
	return nil
}

// Authenticate checks if the client proof is correct.
func (a *AuthenticatorCRAMMD5) Authenticate(context *proto.Context, req *AuthenticateRequest, reply *AuthenticateReply) error {
	username := strings.SplitN(req.Proof, " ", 2)[0]
	secrets, ok := a.Credentials[username]
	if !ok {
		relog.Warning("failed authentication attempt: wrong user: %#v", username)
		return AuthenticationFailed
	}
	if !req.state.challengeIssued {
		relog.Warning("failed authentication attempt: challenge was not issued")
		return AuthenticationFailed
	}
	for _, secret := range secrets {
		if expected := CRAMMD5GetExpected(username, secret, req.state.challenge); expected == req.Proof {
			context.Username = username
			return nil
		}
	}
	relog.Warning("failed authentication attempt: wrong proof")
	return AuthenticationFailed
}

type GetNewChallengeReply struct {
	Challenge string
}

type AuthenticateReply struct{}

type AuthenticateRequest struct {
	Proof string
	state authenticationState
}

// authenticationState maintains the state of the authentication and
// is passed between authenticatedCodec and AuthenticateRequest.
type authenticationState struct {
	authenticated   bool
	challenge       string
	challengeIssued bool
}

// authenticatedCodec is a codec that uses AuthenticatorCRAMMD5 to
// authenticate a request (it implements rpc.ServerCodec). Any
// requests performed before successful authentication will fail.
type authenticatedCodec struct {
	rpc.ServerCodec
	currentMethod string
	state         authenticationState
}

// OK returns true if the codec is authenticated.
func (c *authenticatedCodec) OK() bool {
	return c.state.authenticated
}

// newAuthenticatedCodec returns a fresh authenticatedCodec (in a
// non-authenticated state).
func newAuthenticatedCodec(codec rpc.ServerCodec) *authenticatedCodec {
	return &authenticatedCodec{ServerCodec: codec}
}

// isAuthenticationMethod returns true if method is the name of an
// authentication method.
func isAuthenticationMethod(method string) bool {
	return strings.HasPrefix(method, "AuthenticatorCRAMMD5.")
}

func (c *authenticatedCodec) ReadRequestHeader(r *rpc.Request) error {
	err := c.ServerCodec.ReadRequestHeader(r)

	if err != nil {
		return err
	}

	c.currentMethod = r.ServiceMethod
	return err
}

func (c *authenticatedCodec) ReadRequestBody(body interface{}) error {
	err := c.ServerCodec.ReadRequestBody(body)

	if err != nil {
		return err
	}

	if !isAuthenticationMethod(c.currentMethod) {
		return fmt.Errorf("authentication error: authentication required for %s", c.currentMethod)
	}

	if b, ok := body.(*AuthenticateRequest); ok {
		b.state = c.state
	}

	return err
}

func (c *authenticatedCodec) WriteResponse(r *rpc.Response, body interface{}, last bool) error {
	c.transferState(body)
	return c.ServerCodec.WriteResponse(r, body, last)
}

// transferState transfers the authentication state from body
// (returned by an authentication rpc call) to the codec.
func (c *authenticatedCodec) transferState(body interface{}) {
	switch body.(type) {
	case *GetNewChallengeReply:
		c.state.challenge = body.(*GetNewChallengeReply).Challenge
		c.state.challengeIssued = true
	case *AuthenticateReply:
		c.state.authenticated = true
		c.state.challenge = ""
		c.state.challengeIssued = false
	}
}

func init() {
	AuthenticationServer.Register(DefaultAuthenticatorCRAMMD5)
}
<|endoftext|>


<commit_before>package cipher

import (
	"strings"
	"unicode"
)

type caesar struct{}
type shift struct {
	distance int
}
type vigenere struct {
	key string
}

func NewCaesar() Cipher {
	return caesar{}
}

func (c caesar) Encode(s string) (encoded string) {
	return NewShift(3).Encode(s)
}

func (c caesar) Decode(s string) (decoded string) {
	return NewShift(-3).Encode(s)
}

func NewShift(distance int) Cipher {
	if distance >= 26 || distance == 0 || distance <= -26 {
		return nil
	}
	return shift{distance: distance}
}

func (c shift) Encode(input string) (encoded string) {
	for _, r := range strings.ToLower(input) {
		if unicode.IsLetter(r) {
			encoded += string(shiftLetter(r, c.distance))
		}
	}
	return encoded
}

func (c shift) Decode(input string) (decoded string) {
	for _, r := range strings.ToLower(input) {
		if unicode.IsLetter(r) {
			decoded += string(shiftLetter(r, -c.distance))
		}
	}
	return decoded
}

func NewVigenere(key string) Cipher {
	return vigenere{
		key: key,
	}
}

func (v vigenere) Encode(input string) string {
	panic("Please implement the Encode function")
}

func (v vigenere) Decode(input string) string {
	panic("Please implement the Decode function")
}

func shiftLetter(letter rune, distance int) (shifted rune) {
	// HACKHACK go % operator returns a negative number for -2 % 26 so add 26 then modulo 26
	// https://stackoverflow.com/questions/43018206/modulo-of-negative-integers-in-go
	d := rune(((int(letter-97)+distance)%26)+26)%26 + 97
	return rune(d)
}
<commit_msg>Extract hard-coded Caesar distance<commit_after>package cipher

import (
	"strings"
	"unicode"
)

type caesar struct {
	distance int
}
type shift struct {
	distance int
}
type vigenere struct {
	key string
}

func NewCaesar() Cipher {
	return caesar{
		distance: 3,
	}
}

func (c caesar) Encode(s string) (encoded string) {
	return NewShift(c.distance).Encode(s)
}

func (c caesar) Decode(s string) (decoded string) {
	return NewShift(-c.distance).Encode(s)
}

func NewShift(distance int) Cipher {
	if distance >= 26 || distance == 0 || distance <= -26 {
		return nil
	}
	return shift{distance: distance}
}

func (c shift) Encode(input string) (encoded string) {
	for _, r := range strings.ToLower(input) {
		if unicode.IsLetter(r) {
			encoded += string(shiftLetter(r, c.distance))
		}
	}
	return encoded
}

func (c shift) Decode(input string) (decoded string) {
	for _, r := range strings.ToLower(input) {
		if unicode.IsLetter(r) {
			decoded += string(shiftLetter(r, -c.distance))
		}
	}
	return decoded
}

func NewVigenere(key string) Cipher {
	return vigenere{
		key: key,
	}
}

func (v vigenere) Encode(input string) string {
	panic("Please implement the Encode function")
}

func (v vigenere) Decode(input string) string {
	panic("Please implement the Decode function")
}

func shiftLetter(letter rune, distance int) (shifted rune) {
	// HACKHACK go % operator returns a negative number for -2 % 26 so add 26 then modulo 26
	// https://stackoverflow.com/questions/43018206/modulo-of-negative-integers-in-go
	d := rune(((int(letter-97)+distance)%26)+26)%26 + 97
	return rune(d)
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

func RemoveTrollContent(i bongo.Modellable, disabled bool) func(d *gorm.DB) *gorm.DB {
	return func(d *gorm.DB) *gorm.DB {
		if disabled {
			return d
		}

		if bongo.B.DB.NewScope(i).HasColumn("MetaBits") {
			d = d.Where("meta_bits = ?", 0)
		}

		return d
	}
}

func Paginated(limit, skip int) func(d *gorm.DB) *gorm.DB {
	return func(d *gorm.DB) *gorm.DB {
		// add skip
		if skip > 0 {
			d = d.Offset(skip)
		}

		// add limit
		if limit > 0 {
			d = d.Limit(limit)
		}

		return d
	}
}

func SortedByAddedAt(d *gorm.DB) *gorm.DB {
	return d.Order("added_at DESC")
}

func SortedByCreatedAt(d *gorm.DB) *gorm.DB {
	return d.Order("created_at DESC")
}
<commit_msg>bongo: update return values of scope functions as Scope<commit_after>package models

import (
	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

func RemoveTrollContent(i bongo.Modellable, disabled bool) bongo.Scope {
	return func(d *gorm.DB) *gorm.DB {
		if disabled {
			return d
		}

		if bongo.B.DB.NewScope(i).HasColumn("MetaBits") {
			d = d.Where("meta_bits = ?", 0)
		}

		return d
	}
}

func Paginated(limit, skip int) bongo.Scope {
	return func(d *gorm.DB) *gorm.DB {
		// add skip
		if skip > 0 {
			d = d.Offset(skip)
		}

		// add limit
		if limit > 0 {
			d = d.Limit(limit)
		}

		return d
	}
}

func SortedByAddedAt(d *gorm.DB) *gorm.DB {
	return d.Order("added_at DESC")
}

func SortedByCreatedAt(d *gorm.DB) *gorm.DB {
	return d.Order("created_at DESC")
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess 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 wrangler

import (
	"context"

	"vitess.io/vitess/go/vt/vtctl/workflow"
)

type streamMigrater struct {
	sm *workflow.StreamMigrator
}

func buildStreamMigrater(ctx context.Context, ts *trafficSwitcher, cancelMigrate bool) (*streamMigrater, error) {
	sm, err := workflow.BuildStreamMigrator(ctx, ts, cancelMigrate)
	if err != nil {
		return nil, err
	}

	return &streamMigrater{sm: sm}, nil
}

func (sm *streamMigrater) stopStreams(ctx context.Context) ([]string, error) {
	return sm.sm.StopStreams(ctx)
}

func (sm *streamMigrater) migrateStreams(ctx context.Context) error {
	return sm.sm.MigrateStreams(ctx)
}

func (sm *streamMigrater) cancelMigration(ctx context.Context) {
	sm.sm.CancelMigration(ctx)
}

// streamMigraterFinalize finalizes the stream migration.
// It's a standalone function because it does not use the streamMigrater state.
func streamMigraterfinalize(ctx context.Context, ts *trafficSwitcher, workflows []string) error {
	return workflow.StreamMigratorFinalize(ctx, ts, workflows)
}

func copyTabletStreams(in []*workflow.VReplicationStream) []*workflow.VReplicationStream {
	return workflow.VReplicationStreams(in).Copy().ToSlice()
}
<commit_msg>Remove dead code<commit_after>/*
Copyright 2019 The Vitess 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 wrangler

import (
	"context"

	"vitess.io/vitess/go/vt/vtctl/workflow"
)

type streamMigrater struct {
	sm *workflow.StreamMigrator
}

func (sm *streamMigrater) stopStreams(ctx context.Context) ([]string, error) {
	return sm.sm.StopStreams(ctx)
}

func (sm *streamMigrater) migrateStreams(ctx context.Context) error {
	return sm.sm.MigrateStreams(ctx)
}

func (sm *streamMigrater) cancelMigration(ctx context.Context) {
	sm.sm.CancelMigration(ctx)
}

// streamMigraterFinalize finalizes the stream migration.
// It's a standalone function because it does not use the streamMigrater state.
func streamMigraterfinalize(ctx context.Context, ts *trafficSwitcher, workflows []string) error {
	return workflow.StreamMigratorFinalize(ctx, ts, workflows)
}
<|endoftext|>


<commit_before><commit_msg>Minor<commit_after><|endoftext|>


<commit_before>package message

import (
	"io"

	"github.com/ugorji/go/codec"
	"github.com/yosisa/fluxion/buffer"
)

type Encoder interface {
	Encode(interface{}) error
}

type Decoder interface {
	Decode(interface{}) error
}

type MessageType uint8

const (
	TypInfoRequest MessageType = iota
	TypInfoResponse
	TypBufferOption
	TypConfigure
	TypStart
	TypStop
	TypTerminated
	TypEvent
	TypEventChain
	TypStdout
)

type Message struct {
	Type    MessageType
	UnitID  int32
	Payload interface{}
}

func (m *Message) Encode(enc Encoder) (err error) {
	if err = enc.Encode(m.UnitID); err != nil {
		return
	}
	return enc.Encode(m.Payload)
}

func (m *Message) Decode(dec Decoder) (err error) {
	if err = dec.Decode(&m.UnitID); err != nil {
		return
	}

	switch m.Type {
	case TypInfoResponse:
		var info PluginInfo
		err = dec.Decode(&info)
		m.Payload = &info
	case TypBufferOption:
		var opts buffer.Options
		err = dec.Decode(&opts)
		m.Payload = &opts
	case TypConfigure:
		var s string
		err = dec.Decode(&s)
		m.Payload = s
	case TypEvent, TypEventChain:
		var ev Event
		err = dec.Decode(&ev)
		m.Payload = &ev
	default:
		err = dec.Decode(&m.Payload)
	}
	return
}

type PluginInfo struct {
	ProtoVer uint8 `codec:"proto_ver"`
}

var mh = &codec.MsgpackHandle{RawToString: true, WriteExt: true}

func NewEncoder(w io.Writer) Encoder {
	return codec.NewEncoder(w, mh)
}

func NewDecoder(r io.Reader) Decoder {
	return codec.NewDecoder(r, mh)
}
<commit_msg>Restrict map type for resolving jsonify issue<commit_after>package message

import (
	"io"
	"reflect"

	"github.com/ugorji/go/codec"
	"github.com/yosisa/fluxion/buffer"
)

type Encoder interface {
	Encode(interface{}) error
}

type Decoder interface {
	Decode(interface{}) error
}

type MessageType uint8

const (
	TypInfoRequest MessageType = iota
	TypInfoResponse
	TypBufferOption
	TypConfigure
	TypStart
	TypStop
	TypTerminated
	TypEvent
	TypEventChain
	TypStdout
)

type Message struct {
	Type    MessageType
	UnitID  int32
	Payload interface{}
}

func (m *Message) Encode(enc Encoder) (err error) {
	if err = enc.Encode(m.UnitID); err != nil {
		return
	}
	return enc.Encode(m.Payload)
}

func (m *Message) Decode(dec Decoder) (err error) {
	if err = dec.Decode(&m.UnitID); err != nil {
		return
	}

	switch m.Type {
	case TypInfoResponse:
		var info PluginInfo
		err = dec.Decode(&info)
		m.Payload = &info
	case TypBufferOption:
		var opts buffer.Options
		err = dec.Decode(&opts)
		m.Payload = &opts
	case TypConfigure:
		var s string
		err = dec.Decode(&s)
		m.Payload = s
	case TypEvent, TypEventChain:
		var ev Event
		err = dec.Decode(&ev)
		m.Payload = &ev
	default:
		err = dec.Decode(&m.Payload)
	}
	return
}

type PluginInfo struct {
	ProtoVer uint8 `codec:"proto_ver"`
}

var mh = &codec.MsgpackHandle{RawToString: true, WriteExt: true}

func NewEncoder(w io.Writer) Encoder {
	return codec.NewEncoder(w, mh)
}

func NewDecoder(r io.Reader) Decoder {
	return codec.NewDecoder(r, mh)
}

func init() {
	mh.MapType = reflect.TypeOf(map[string]interface{}(nil))
}
<|endoftext|>


<commit_before>package middleware

import (
	"net/http"
	"strconv"
	"strings"
)

type AccessControlConfig struct {
	AllowOrigin      string
	AllowCredentials bool
	AllowMethods     []string
	AllowHeaders     []string
	ExposeHeaders    []string
	MaxAge           int
}

func CORS(cfg AccessControlConfig) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			if len(cfg.AllowOrigin) > 0 {
				w.Header().Set("Access-Control-Allow-Origin", cfg.AllowOrigin)
			}

			if len(cfg.AllowMethods) > 0 {
				w.Header().Set("Access-Control-Allow-Methods", strings.Join(cfg.AllowMethods, ","))
			}

			if len(cfg.AllowHeaders) > 0 {
				w.Header().Set("Access-Control-Allow-Headers", strings.Join(cfg.AllowHeaders, ","))
			}

			if len(cfg.ExposeHeaders) > 0 {
				w.Header().Set("Access-Control-Expose-Headers", strings.Join(cfg.ExposeHeaders, ","))
			}

			if cfg.MaxAge > 0 {
				w.Header().Set("Access-Control-Max-Age", strconv.Itoa(cfg.MaxAge))
			}

			w.Header().Set("Access-Control-Allow-Credentials", strconv.FormatBool(cfg.AllowCredentials))

			next.ServeHTTP(w, r)
		}

		return http.HandlerFunc(fn)
	}
}
<commit_msg>fix lint<commit_after>package middleware

import (
	"net/http"
	"strconv"
	"strings"
)

type AccessControlConfig struct {
	AllowOrigin      string
	AllowCredentials bool
	AllowMethods     []string
	AllowHeaders     []string
	ExposeHeaders    []string
	MaxAge           int
}

func CORS(cfg AccessControlConfig) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			if len(cfg.AllowOrigin) > 0 {
				w.Header().Set("Access-Control-Allow-Origin", cfg.AllowOrigin)
			}
			if len(cfg.AllowMethods) > 0 {
				w.Header().Set("Access-Control-Allow-Methods", strings.Join(cfg.AllowMethods, ","))
			}
			if len(cfg.AllowHeaders) > 0 {
				w.Header().Set("Access-Control-Allow-Headers", strings.Join(cfg.AllowHeaders, ","))
			}
			if len(cfg.ExposeHeaders) > 0 {
				w.Header().Set("Access-Control-Expose-Headers", strings.Join(cfg.ExposeHeaders, ","))
			}
			if cfg.MaxAge > 0 {
				w.Header().Set("Access-Control-Max-Age", strconv.Itoa(cfg.MaxAge))
			}

			w.Header().Set("Access-Control-Allow-Credentials", strconv.FormatBool(cfg.AllowCredentials))
			next.ServeHTTP(w, r)
		}

		return http.HandlerFunc(fn)
	}
}
<|endoftext|>