<commit_before>package tcpoverdns

import (
	"bytes"
	"compress/flate"
	"compress/gzip"
	"compress/lzw"
	"compress/zlib"
	"crypto/rand"
	"encoding/base32"
	"fmt"
	"reflect"
	"testing"
	"time"
)

func TestSegment_Packet(t *testing.T) {
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   []byte{1, 2, 3, 4},
	}

	packet := want.Packet()
	got := SegmentFromPacket(packet)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("recovered: %+#v original: %+#v", got, want)
	}

	want.Flags = FlagHandshakeSyn
	packet = want.Packet()
	got = SegmentFromPacket(packet)
	if !reflect.DeepEqual(got, Segment{Flags: FlagMalformed}) {
		t.Fatal("did not identify malformed segment without initiator config")
	}
}

func TestSegmentFromMalformedPacket(t *testing.T) {
	want := Segment{Flags: FlagMalformed}
	segWithData := Segment{Data: []byte{1, 2}}
	segWithMalformedLen := segWithData.Packet()
	for _, seg := range [][]byte{nil, {1}, segWithMalformedLen[:SegmentHeaderLen+1]} {
		if got := SegmentFromPacket(seg); !reflect.DeepEqual(got, want) {
			t.Fatalf("got: %+#v, want: %+#v", got, want)
		}
	}
}

func TestFlags(t *testing.T) {
	allFlags := FlagHandshakeSyn | FlagHandshakeAck | FlagAckOnly | FlagKeepAlive | FlagReset | FlagMalformed
	for _, flag := range []Flag{FlagHandshakeSyn, FlagHandshakeAck, FlagAckOnly, FlagKeepAlive, FlagReset, FlagMalformed} {
		if !allFlags.Has(flag) {
			t.Fatalf("missing %d", flag)
		}
	}
	if allFlags.Has(1 << 6) {
		t.Fatalf("should not have had flag %d", 1<<4)
	}
}

func TestSegment_Equals(t *testing.T) {
	original := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   []byte{1, 2, 3, 4},
	}
	if !original.Equals(original) {
		t.Errorf("should have been equal")
	}

	tests := []struct {
		a, b Segment
	}{
		{a: Segment{ID: 1}, b: Segment{ID: 2}},
		{a: Segment{Flags: 1}, b: Segment{Flags: 2}},
		{a: Segment{SeqNum: 1}, b: Segment{SeqNum: 2}},
		{a: Segment{AckNum: 1}, b: Segment{AckNum: 2}},
		{a: Segment{Data: []byte{0}}, b: Segment{Data: []byte{1}}},
	}
	for _, test := range tests {
		if test.a.Equals(test.b) {
			t.Errorf("should not have been equal: %+v, %+v", test.a, test.b)
		}
	}
}

func TestBase62(t *testing.T) {
	randBuf := make([]byte, 2000)
	if _, err := rand.Read(randBuf); err != nil {
		t.Fatal(err)
	}
	encoded := ToBase62(randBuf)
	got, err := ParseBase62(encoded)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(got, randBuf) {
		t.Fatalf("got: %v, want: %v", got, randBuf)
	}
}

func TestCompression(t *testing.T) {
	base32EncodingNoPadding := base32.StdEncoding.WithPadding(base32.NoPadding)
	randBuf := make([]byte, 234)
	if _, err := rand.Read(randBuf); err != nil {
		t.Fatal(err)
	}
	var input = []struct {
		name    string
		content []byte
	}{
		{
			name:    "natural language (short)",
			content: []byte(`NIV The words of the Teacher, son of David, king in Jerusalem: “Meaningless! Meaningless!” says the Teacher. “Utterly meaningless! Everything is meaningless.” What do people gain from all their labors at which they toil under the sun?`),
		},
		{
			name:    "natural language (long)",
			content: []byte(`NIV The words of the Teacher, son of David, king in Jerusalem: “Meaningless! Meaningless!” says the Teacher. “Utterly meaningless! Everything is meaningless.” What do people gain from all their labors at which they toil under the sun? Generations come and generations go, but the earth remains forever. The sun rises and the sun sets, and hurries back to where it rises. The wind blows to the south and turns to the north; round and round it goes, ever returning on its course.`),
		},
		{
			name:    "html",
			content: []byte(`<!doctype html><html itemscope="" itemtype="http://schema.org/SearchResultsPage" lang="en-IE"><head><meta charset="UTF-8"><meta content="dark" name="color-scheme"><meta content="origin" name="referrer"><meta content="/images/branding/`),
		},
		{
			name:    "random",
			content: randBuf,
		},
	}

	t.Run("no-compression", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			b.Write(example.content)
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("no-compression - %v, original: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("zlib", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w, err := zlib.NewWriterLevel(&b, zlib.BestCompression)
			if err != nil {
				t.Fatal(err)
			}
			w.Write(example.content)
			w.Close()
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("zlib - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("lzw", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w := lzw.NewWriter(&b, lzw.MSB, 8)
			w.Write(example.content)
			w.Close()
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("lzm - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("flate", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w, err := flate.NewWriter(&b, flate.BestCompression)
			if err != nil {
				t.Fatal(err)
			}
			w.Write(example.content)
			w.Close()
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("flate - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("flate+base62", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w, err := flate.NewWriter(&b, flate.BestCompression)
			if err != nil {
				t.Fatal(err)
			}
			w.Write(example.content)
			w.Close()
			encodedLen := len(ToBase62(b.Bytes()))
			fmt.Printf("flate - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("gzip", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w, err := gzip.NewWriterLevel(&b, gzip.BestCompression)
			if err != nil {
				t.Fatal(err)
			}
			w.Write(example.content)
			w.Close()
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("gzip - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})
}

func TestCompressDecompressBytes(t *testing.T) {
	tests := [][]byte{
		{},
		{0},
		{0, 1},
		{0, 1, 2},
		[]byte(`<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-IE"><head><meta charset="UTF-8"><meta content="dark" name="color-scheme"><meta content="origin" name="referrer"><meta content="/images/branding/googleg/1x/googleg_standard_colo`),
	}
	for _, original := range tests {
		compressed := CompressBytes(original)
		got, err := DecompressBytes(compressed)
		if err != nil || !reflect.DeepEqual(got, original) {
			t.Fatalf("DecompressBytes(%+v): got %+v, want %+v", compressed, got, original)
		}
	}
}

func TestInitiatorConfig(t *testing.T) {
	wantTiming := TimingConfig{
		SlidingWindowWaitDuration: 1000 * time.Millisecond,
		RetransmissionInterval:    1234 * time.Millisecond,
		AckDelay:                  3456 * time.Millisecond,
		KeepAliveInterval:         4567 * time.Millisecond,
		ReadTimeout:               5678 * time.Millisecond,
		WriteTimeout:              7890 * time.Millisecond,
	}
	want := &InitiatorConfig{
		SetConfig:               true,
		MaxSegmentLenExclHeader: 123,
		Debug:                   true,
		Timing:                  wantTiming,
	}
	serialised := want.Bytes()
	got := DeserialiseInitiatorConfig(serialised)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("got: %+#v want: %+#v", got, want)
	}

	wantTC := &TransmissionControl{
		MaxSegmentLenExclHeader: 123,
		MaxSlidingWindow:        123 * 64,
		InitialTiming:           wantTiming,
		LiveTiming:              wantTiming,
		Debug:                   true,
	}
	gotTC := &TransmissionControl{}
	got.Config(gotTC)
	if !reflect.DeepEqual(gotTC, wantTC) {
		t.Fatalf("got: %+#v want: %+#v", gotTC, wantTC)
	}
}

func TestSegment_DNSNameQuery(t *testing.T) {
	randData := make([]byte, 100)
	if _, err := rand.Read(randData); err != nil {
		t.Fatal(err)
	}
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   randData,
	}
	query := want.DNSNameQuery("prefix-label", "example.com")
	fmt.Println(query)
	got := SegmentFromDNSName(2, query)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("recovered: %+#v original: %+#v", got, want)
	}
}
<commit_msg>tcpoverdns: fix failing TestInitiatorConfig<commit_after>package tcpoverdns

import (
	"bytes"
	"compress/flate"
	"compress/gzip"
	"compress/lzw"
	"compress/zlib"
	"crypto/rand"
	"encoding/base32"
	"fmt"
	"reflect"
	"testing"
	"time"
)

func TestSegment_Packet(t *testing.T) {
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   []byte{1, 2, 3, 4},
	}

	packet := want.Packet()
	got := SegmentFromPacket(packet)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("recovered: %+#v original: %+#v", got, want)
	}

	want.Flags = FlagHandshakeSyn
	packet = want.Packet()
	got = SegmentFromPacket(packet)
	if !reflect.DeepEqual(got, Segment{Flags: FlagMalformed}) {
		t.Fatal("did not identify malformed segment without initiator config")
	}
}

func TestSegmentFromMalformedPacket(t *testing.T) {
	want := Segment{Flags: FlagMalformed}
	segWithData := Segment{Data: []byte{1, 2}}
	segWithMalformedLen := segWithData.Packet()
	for _, seg := range [][]byte{nil, {1}, segWithMalformedLen[:SegmentHeaderLen+1]} {
		if got := SegmentFromPacket(seg); !reflect.DeepEqual(got, want) {
			t.Fatalf("got: %+#v, want: %+#v", got, want)
		}
	}
}

func TestFlags(t *testing.T) {
	allFlags := FlagHandshakeSyn | FlagHandshakeAck | FlagAckOnly | FlagKeepAlive | FlagReset | FlagMalformed
	for _, flag := range []Flag{FlagHandshakeSyn, FlagHandshakeAck, FlagAckOnly, FlagKeepAlive, FlagReset, FlagMalformed} {
		if !allFlags.Has(flag) {
			t.Fatalf("missing %d", flag)
		}
	}
	if allFlags.Has(1 << 6) {
		t.Fatalf("should not have had flag %d", 1<<4)
	}
}

func TestSegment_Equals(t *testing.T) {
	original := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   []byte{1, 2, 3, 4},
	}
	if !original.Equals(original) {
		t.Errorf("should have been equal")
	}

	tests := []struct {
		a, b Segment
	}{
		{a: Segment{ID: 1}, b: Segment{ID: 2}},
		{a: Segment{Flags: 1}, b: Segment{Flags: 2}},
		{a: Segment{SeqNum: 1}, b: Segment{SeqNum: 2}},
		{a: Segment{AckNum: 1}, b: Segment{AckNum: 2}},
		{a: Segment{Data: []byte{0}}, b: Segment{Data: []byte{1}}},
	}
	for _, test := range tests {
		if test.a.Equals(test.b) {
			t.Errorf("should not have been equal: %+v, %+v", test.a, test.b)
		}
	}
}

func TestBase62(t *testing.T) {
	randBuf := make([]byte, 2000)
	if _, err := rand.Read(randBuf); err != nil {
		t.Fatal(err)
	}
	encoded := ToBase62(randBuf)
	got, err := ParseBase62(encoded)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(got, randBuf) {
		t.Fatalf("got: %v, want: %v", got, randBuf)
	}
}

func TestCompression(t *testing.T) {
	base32EncodingNoPadding := base32.StdEncoding.WithPadding(base32.NoPadding)
	randBuf := make([]byte, 234)
	if _, err := rand.Read(randBuf); err != nil {
		t.Fatal(err)
	}
	var input = []struct {
		name    string
		content []byte
	}{
		{
			name:    "natural language (short)",
			content: []byte(`NIV The words of the Teacher, son of David, king in Jerusalem: “Meaningless! Meaningless!” says the Teacher. “Utterly meaningless! Everything is meaningless.” What do people gain from all their labors at which they toil under the sun?`),
		},
		{
			name:    "natural language (long)",
			content: []byte(`NIV The words of the Teacher, son of David, king in Jerusalem: “Meaningless! Meaningless!” says the Teacher. “Utterly meaningless! Everything is meaningless.” What do people gain from all their labors at which they toil under the sun? Generations come and generations go, but the earth remains forever. The sun rises and the sun sets, and hurries back to where it rises. The wind blows to the south and turns to the north; round and round it goes, ever returning on its course.`),
		},
		{
			name:    "html",
			content: []byte(`<!doctype html><html itemscope="" itemtype="http://schema.org/SearchResultsPage" lang="en-IE"><head><meta charset="UTF-8"><meta content="dark" name="color-scheme"><meta content="origin" name="referrer"><meta content="/images/branding/`),
		},
		{
			name:    "random",
			content: randBuf,
		},
	}

	t.Run("no-compression", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			b.Write(example.content)
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("no-compression - %v, original: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("zlib", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w, err := zlib.NewWriterLevel(&b, zlib.BestCompression)
			if err != nil {
				t.Fatal(err)
			}
			w.Write(example.content)
			w.Close()
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("zlib - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("lzw", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w := lzw.NewWriter(&b, lzw.MSB, 8)
			w.Write(example.content)
			w.Close()
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("lzm - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("flate", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w, err := flate.NewWriter(&b, flate.BestCompression)
			if err != nil {
				t.Fatal(err)
			}
			w.Write(example.content)
			w.Close()
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("flate - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("flate+base62", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w, err := flate.NewWriter(&b, flate.BestCompression)
			if err != nil {
				t.Fatal(err)
			}
			w.Write(example.content)
			w.Close()
			encodedLen := len(ToBase62(b.Bytes()))
			fmt.Printf("flate - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})

	t.Run("gzip", func(t *testing.T) {
		for _, example := range input {
			var b bytes.Buffer
			w, err := gzip.NewWriterLevel(&b, gzip.BestCompression)
			if err != nil {
				t.Fatal(err)
			}
			w.Write(example.content)
			w.Close()
			encodedLen := len(base32EncodingNoPadding.EncodeToString(b.Bytes()))
			fmt.Printf("gzip - %v, compressed: %d, encoded: %d, ratio: %.3f\n", example.name, len(b.Bytes()), encodedLen, float64(encodedLen)/float64(len(example.content)))
		}
	})
}

func TestCompressDecompressBytes(t *testing.T) {
	tests := [][]byte{
		{},
		{0},
		{0, 1},
		{0, 1, 2},
		[]byte(`<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-IE"><head><meta charset="UTF-8"><meta content="dark" name="color-scheme"><meta content="origin" name="referrer"><meta content="/images/branding/googleg/1x/googleg_standard_colo`),
	}
	for _, original := range tests {
		compressed := CompressBytes(original)
		got, err := DecompressBytes(compressed)
		if err != nil || !reflect.DeepEqual(got, original) {
			t.Fatalf("DecompressBytes(%+v): got %+v, want %+v", compressed, got, original)
		}
	}
}

func TestInitiatorConfig(t *testing.T) {
	wantTiming := TimingConfig{
		SlidingWindowWaitDuration: 1000 * time.Millisecond,
		RetransmissionInterval:    1234 * time.Millisecond,
		AckDelay:                  3456 * time.Millisecond,
		KeepAliveInterval:         4567 * time.Millisecond,
		ReadTimeout:               5678 * time.Millisecond,
		WriteTimeout:              7890 * time.Millisecond,
	}
	want := &InitiatorConfig{
		SetConfig:               true,
		MaxSegmentLenExclHeader: 123,
		Debug:                   true,
		Timing:                  wantTiming,
	}
	serialised := want.Bytes()
	got := DeserialiseInitiatorConfig(serialised)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("got: %+#v want: %+#v", got, want)
	}

	wantTC := &TransmissionControl{
		MaxSegmentLenExclHeader: 123,
		MaxSlidingWindow:        123 * 16,
		InitialTiming:           wantTiming,
		LiveTiming:              wantTiming,
		Debug:                   true,
	}
	gotTC := &TransmissionControl{}
	got.Config(gotTC)
	if !reflect.DeepEqual(gotTC, wantTC) {
		t.Fatalf("got: %+#v want: %+#v", gotTC, wantTC)
	}
}

func TestSegment_DNSNameQuery(t *testing.T) {
	randData := make([]byte, 100)
	if _, err := rand.Read(randData); err != nil {
		t.Fatal(err)
	}
	want := Segment{
		ID:     12345,
		Flags:  FlagHandshakeAck & FlagHandshakeSyn,
		SeqNum: 23456,
		AckNum: 34567,
		Data:   randData,
	}
	query := want.DNSNameQuery("prefix-label", "example.com")
	fmt.Println(query)
	got := SegmentFromDNSName(2, query)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("recovered: %+#v original: %+#v", got, want)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"git"
	"net/http"
	"router"
	"strconv"
)

var connConf git.Config

func init() {
	connConf = git.Config{
		GitUrl:           "https://api.github.com",
		BaseOrganisation: "/informationgrid",
		GitAuthkey:       "QlJvZWhybDpZcCFtSzZGMw=="}

	git.SetConfig(connConf)
}

func main() {

	RunCHM()

}

type Config struct {
	Port int
}

func RunCHM() {

	var config = Config{
		Port: 2506,
	}

	fmt.Println("starting CHM...")

	router := router.NewRouter()

	fmt.Println("starting server on Port", strconv.Itoa(config.Port))
	panic(http.ListenAndServe(":"+strconv.Itoa(config.Port), router))
}
<commit_msg>- updated auth key<commit_after>package main

import (
	"fmt"
	"git"
	"net/http"
	"router"
	"strconv"
)

var connConf git.Config

func init() {
	connConf = git.Config{
		GitUrl:           "https://api.github.com",
		BaseOrganisation: "/informationgrid",
		GitAuthkey:       "QlJvZWhybDppVk4zSlJNTGZjeVh4eFU="}

	git.SetConfig(connConf)
}

func main() {

	RunCHM()

}

type Config struct {
	Port int
}

func RunCHM() {

	var config = Config{
		Port: 2506,
	}

	fmt.Println("starting CHM...")

	router := router.NewRouter()

	fmt.Println("starting server on Port", strconv.Itoa(config.Port))
	panic(http.ListenAndServe(":"+strconv.Itoa(config.Port), router))
}
<|endoftext|>


<commit_before>package scheduler

import (
	"fmt"
	"time"

	"github.com/Dataman-Cloud/swan/src/config"
	swanevent "github.com/Dataman-Cloud/swan/src/manager/event"
	"github.com/Dataman-Cloud/swan/src/manager/framework/event"
	"github.com/Dataman-Cloud/swan/src/manager/framework/mesos_connector"
	"github.com/Dataman-Cloud/swan/src/manager/framework/state"
	"github.com/Dataman-Cloud/swan/src/manager/framework/store"
	"github.com/Dataman-Cloud/swan/src/manager/swancontext"
	"github.com/Dataman-Cloud/swan/src/mesosproto/mesos"
	"github.com/Dataman-Cloud/swan/src/mesosproto/sched"

	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

type Scheduler struct {
	scontext         *swancontext.SwanContext
	heartbeater      *time.Ticker
	mesosFailureChan chan error

	handlerManager *HandlerManager

	stopC chan struct{}

	AppStorage *memoryStore

	Allocator               *state.OfferAllocator
	MesosConnector          *mesos_connector.MesosConnector
	mesosConnectorCancelFun context.CancelFunc
	store                   store.Store
	config                  config.SwanConfig
}

func NewScheduler(config config.SwanConfig, scontext *swancontext.SwanContext, store store.Store) *Scheduler {
	scheduler := &Scheduler{
		MesosConnector: mesos_connector.NewMesosConnector(config.Scheduler),
		heartbeater:    time.NewTicker(10 * time.Second),
		scontext:       scontext,

		AppStorage: NewMemoryStore(),
		store:      store,
		config:     config,

		mesosFailureChan: make(chan error, 1),
	}

	RegiserFun := func(m *HandlerManager) {
		m.Register(sched.Event_SUBSCRIBED, LoggerHandler, SubscribedHandler)
		m.Register(sched.Event_HEARTBEAT, LoggerHandler, DummyHandler)
		m.Register(sched.Event_OFFERS, LoggerHandler, OfferHandler, DummyHandler)
		m.Register(sched.Event_RESCIND, LoggerHandler, DummyHandler)
		m.Register(sched.Event_UPDATE, LoggerHandler, UpdateHandler, DummyHandler)
		m.Register(sched.Event_FAILURE, LoggerHandler, DummyHandler)
		m.Register(sched.Event_MESSAGE, LoggerHandler, DummyHandler)
		m.Register(sched.Event_ERROR, LoggerHandler, DummyHandler)
	}

	scheduler.handlerManager = NewHanlderManager(scheduler, RegiserFun)
	scheduler.Allocator = state.NewOfferAllocator()

	state.SetStore(store)

	return scheduler
}

// shutdown main scheduler and related
func (scheduler *Scheduler) Stop() error {
	scheduler.stopC <- struct{}{}
	return nil
}

// revive from crash or rotate from leader change
func (scheduler *Scheduler) Start(ctx context.Context) error {

	if !scheduler.config.NoRecover {
		apps, err := state.LoadAppData(scheduler.Allocator, scheduler.MesosConnector, scheduler.scontext)
		if err != nil {
			return err
		}

		for _, app := range apps {
			scheduler.AppStorage.Add(app.AppId, app)
		}
	}

	// temp solution
	go func() {
		framework := mesos_connector.CreateFrameworkInfo(scheduler.config.Scheduler)
		frameworkId, err := scheduler.store.GetFrameworkId()
		if err == nil {
			framework.Id = &mesos.FrameworkID{Value: &frameworkId}
		}
		scheduler.MesosConnector.Framework = framework

		var c context.Context
		c, scheduler.mesosConnectorCancelFun = context.WithCancel(ctx)
		scheduler.MesosConnector.Start(c, scheduler.mesosFailureChan)
	}()

	return scheduler.Run(context.Background()) // context as a placeholder
}

// main loop
func (scheduler *Scheduler) Run(ctx context.Context) error {
	for {
		select {
		case e := <-scheduler.MesosConnector.MesosEventChan:
			logrus.WithFields(logrus.Fields{"mesos event chan": "yes"}).Debugf("")
			scheduler.handlerMesosEvent(e)

		case e := <-scheduler.mesosFailureChan:
			logrus.WithFields(logrus.Fields{"failure": "yes"}).Debugf("%s", e)
			scheduler.mesosConnectorCancelFun()

		case <-scheduler.heartbeater.C: // heartbeat timeout for now

		case <-scheduler.stopC:
			logrus.Infof("stopping main scheduler")
			return nil
		}
	}
}

func (scheduler *Scheduler) handlerMesosEvent(event *event.MesosEvent) {
	scheduler.handlerManager.Handle(event)
}

// reevaluation of apps state, clean up stale apps
func (scheduler *Scheduler) InvalidateApps() {
	appsPendingRemove := make([]string, 0)
	for _, app := range scheduler.AppStorage.Data() {
		if app.CanBeCleanAfterDeletion() { // check if app should be cleanup
			appsPendingRemove = append(appsPendingRemove, app.AppId)
		}
	}

	for _, appId := range appsPendingRemove {
		scheduler.AppStorage.Delete(appId)
	}
}

func (scheduler *Scheduler) EmitEvent(swanEvent *swanevent.Event) {
	scheduler.scontext.EventBus.EventChan <- swanEvent
}
<commit_msg>make build pass<commit_after>package scheduler

import (
	"time"

	"github.com/Dataman-Cloud/swan/src/config"
	swanevent "github.com/Dataman-Cloud/swan/src/manager/event"
	"github.com/Dataman-Cloud/swan/src/manager/framework/event"
	"github.com/Dataman-Cloud/swan/src/manager/framework/mesos_connector"
	"github.com/Dataman-Cloud/swan/src/manager/framework/state"
	"github.com/Dataman-Cloud/swan/src/manager/framework/store"
	"github.com/Dataman-Cloud/swan/src/manager/swancontext"
	"github.com/Dataman-Cloud/swan/src/mesosproto/mesos"
	"github.com/Dataman-Cloud/swan/src/mesosproto/sched"

	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

type Scheduler struct {
	scontext         *swancontext.SwanContext
	heartbeater      *time.Ticker
	mesosFailureChan chan error

	handlerManager *HandlerManager

	stopC chan struct{}

	AppStorage *memoryStore

	Allocator               *state.OfferAllocator
	MesosConnector          *mesos_connector.MesosConnector
	mesosConnectorCancelFun context.CancelFunc
	store                   store.Store
	config                  config.SwanConfig
}

func NewScheduler(config config.SwanConfig, scontext *swancontext.SwanContext, store store.Store) *Scheduler {
	scheduler := &Scheduler{
		MesosConnector: mesos_connector.NewMesosConnector(config.Scheduler),
		heartbeater:    time.NewTicker(10 * time.Second),
		scontext:       scontext,

		AppStorage: NewMemoryStore(),
		store:      store,
		config:     config,

		mesosFailureChan: make(chan error, 1),
	}

	RegiserFun := func(m *HandlerManager) {
		m.Register(sched.Event_SUBSCRIBED, LoggerHandler, SubscribedHandler)
		m.Register(sched.Event_HEARTBEAT, LoggerHandler, DummyHandler)
		m.Register(sched.Event_OFFERS, LoggerHandler, OfferHandler, DummyHandler)
		m.Register(sched.Event_RESCIND, LoggerHandler, DummyHandler)
		m.Register(sched.Event_UPDATE, LoggerHandler, UpdateHandler, DummyHandler)
		m.Register(sched.Event_FAILURE, LoggerHandler, DummyHandler)
		m.Register(sched.Event_MESSAGE, LoggerHandler, DummyHandler)
		m.Register(sched.Event_ERROR, LoggerHandler, DummyHandler)
	}

	scheduler.handlerManager = NewHanlderManager(scheduler, RegiserFun)
	scheduler.Allocator = state.NewOfferAllocator()

	state.SetStore(store)

	return scheduler
}

// shutdown main scheduler and related
func (scheduler *Scheduler) Stop() error {
	scheduler.stopC <- struct{}{}
	return nil
}

// revive from crash or rotate from leader change
func (scheduler *Scheduler) Start(ctx context.Context) error {

	if !scheduler.config.NoRecover {
		apps, err := state.LoadAppData(scheduler.Allocator, scheduler.MesosConnector, scheduler.scontext)
		if err != nil {
			return err
		}

		for _, app := range apps {
			scheduler.AppStorage.Add(app.AppId, app)
		}
	}

	// temp solution
	go func() {
		framework := mesos_connector.CreateFrameworkInfo(scheduler.config.Scheduler)
		frameworkId, err := scheduler.store.GetFrameworkId()
		if err == nil {
			framework.Id = &mesos.FrameworkID{Value: &frameworkId}
		}
		scheduler.MesosConnector.Framework = framework

		var c context.Context
		c, scheduler.mesosConnectorCancelFun = context.WithCancel(ctx)
		scheduler.MesosConnector.Start(c, scheduler.mesosFailureChan)
	}()

	return scheduler.Run(context.Background()) // context as a placeholder
}

// main loop
func (scheduler *Scheduler) Run(ctx context.Context) error {
	for {
		select {
		case e := <-scheduler.MesosConnector.MesosEventChan:
			logrus.WithFields(logrus.Fields{"mesos event chan": "yes"}).Debugf("")
			scheduler.handlerMesosEvent(e)

		case e := <-scheduler.mesosFailureChan:
			logrus.WithFields(logrus.Fields{"failure": "yes"}).Debugf("%s", e)
			scheduler.mesosConnectorCancelFun()

		case <-scheduler.heartbeater.C: // heartbeat timeout for now

		case <-scheduler.stopC:
			logrus.Infof("stopping main scheduler")
			return nil
		}
	}
}

func (scheduler *Scheduler) handlerMesosEvent(event *event.MesosEvent) {
	scheduler.handlerManager.Handle(event)
}

// reevaluation of apps state, clean up stale apps
func (scheduler *Scheduler) InvalidateApps() {
	appsPendingRemove := make([]string, 0)
	for _, app := range scheduler.AppStorage.Data() {
		if app.CanBeCleanAfterDeletion() { // check if app should be cleanup
			appsPendingRemove = append(appsPendingRemove, app.AppId)
		}
	}

	for _, appId := range appsPendingRemove {
		scheduler.AppStorage.Delete(appId)
	}
}

func (scheduler *Scheduler) EmitEvent(swanEvent *swanevent.Event) {
	scheduler.scontext.EventBus.EventChan <- swanEvent
}
<|endoftext|>


<commit_before>package reverseconnection

import (
	"encoding/json"
	"io"
	"net"
	"net/http"
	"time"

	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/log/nulllogger"
)

func newDialer(rawDialer *net.Dialer, serveMux *http.ServeMux,
	minimumInterval, maximumInterval time.Duration,
	logger log.DebugLogger) *Dialer {
	if rawDialer == nil {
		rawDialer = &net.Dialer{}
	}
	if serveMux == nil {
		serveMux = http.DefaultServeMux
	}
	if minimumInterval < time.Second {
		minimumInterval = time.Second
	}
	if maximumInterval <= minimumInterval {
		maximumInterval = 0
	}
	if logger == nil {
		logger = nulllogger.New()
	}
	dialer := &Dialer{
		dialer:          rawDialer,
		minimumInterval: minimumInterval,
		maximumInterval: maximumInterval,
		logger:          logger,
		connectionMap:   make(map[string]net.Conn),
	}
	serveMux.Handle(urlPath, dialer)
	return dialer
}

// Add a connection to the map. Returns true if added, false if duplicate.
func (d *Dialer) add(address string, conn net.Conn) bool {
	d.connectionMapLock.Lock()
	defer d.connectionMapLock.Unlock()
	if _, ok := d.connectionMap[address]; ok {
		return false
	} else {
		d.connectionMap[address] = conn
		return true
	}
}

func (d *Dialer) dial(network, address string) (net.Conn, error) {
	if network != "tcp" || len(d.connectionMap) < 1 {
		return d.dialer.Dial(network, address)
	}
	if conn, err := d.lookupDial(address); err != nil {
		return nil, err
	} else if conn != nil {
		return conn, nil
	}
	return d.dialer.Dial(network, address)
}

func (d *Dialer) lookupDial(address string) (net.Conn, error) {
	host, port, err := net.SplitHostPort(address)
	if err != nil {
		return nil, err
	}
	addrs, err := net.LookupHost(host)
	if err != nil {
		return nil, err
	}
	if len(addrs) < 1 {
		return nil, nil
	}
	for _, addr := range addrs {
		oneAddress := net.JoinHostPort(addr, port)
		if conn := d.lookup(oneAddress); conn != nil {
			d.logger.Debugf(0, "Consuming reverse dialer connection from: %s\n",
				oneAddress)
			// Tell other side we are ready for them to accept.
			buffer := make([]byte, 1)
			if _, err := conn.Write(buffer); err != nil {
				d.logger.Printf("error sending please-accept message: %s\n",
					err)
				return nil, nil
			}
			return conn, nil
		}
	}
	return nil, nil
}

// Lookup a connection and remove it from the map. Caller must consume.
func (d *Dialer) lookup(address string) net.Conn {
	d.connectionMapLock.Lock()
	defer d.connectionMapLock.Unlock()
	if conn, ok := d.connectionMap[address]; ok {
		delete(d.connectionMap, address)
		return conn
	}
	return nil
}

func (d *Dialer) serveHTTP(w http.ResponseWriter, req *http.Request) {
	d.connectionMapLock.Lock()
	_, ok := d.connectionMap[req.RemoteAddr]
	d.connectionMapLock.Unlock()
	if ok {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusAlreadyReported)
		return
	}
	if req.Method != "CONNECT" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	hijacker, ok := w.(http.Hijacker)
	if !ok {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		d.logger.Println("not a hijacker ", req.RemoteAddr)
		return
	}
	conn, _, err := hijacker.Hijack()
	if err != nil {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		d.logger.Println("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
		return
	}
	defer func() {
		if conn != nil {
			conn.Close()
		}
	}()
	_, err = io.WriteString(conn, "HTTP/1.0 "+connectString+"\n\n")
	if err != nil {
		d.logger.Println("error writing connect message: ", err.Error())
		return
	}
	message := reverseDialerMessage{
		MinimumInterval: d.minimumInterval,
		MaximumInterval: d.maximumInterval,
	}
	encoder := json.NewEncoder(conn)
	encoder.SetIndent("", "    ")
	if err := encoder.Encode(message); err != nil {
		d.logger.Printf("error writing ReverseDialerMessage: %s\n", err)
		return
	}
	// Ensure we don't write anything else until the other end has drained it's
	// buffer.
	buffer := make([]byte, 1)
	if _, err := conn.Read(buffer); err != nil {
		d.logger.Printf("error reading sync byte: %s\n", err)
		return
	}
	if d.add(req.RemoteAddr, conn) {
		d.logger.Debugf(0, "Registered reverse dialer connection from: %s\n",
			req.RemoteAddr)
	} else {
		d.logger.Printf(
			"Closing duplicate reverse dialer connection from: %s\n",
			req.RemoteAddr)
	}
	conn = nil
}
<commit_msg>Move check for existing connection until after protocol checks are done.<commit_after>package reverseconnection

import (
	"encoding/json"
	"io"
	"net"
	"net/http"
	"time"

	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/log/nulllogger"
)

func newDialer(rawDialer *net.Dialer, serveMux *http.ServeMux,
	minimumInterval, maximumInterval time.Duration,
	logger log.DebugLogger) *Dialer {
	if rawDialer == nil {
		rawDialer = &net.Dialer{}
	}
	if serveMux == nil {
		serveMux = http.DefaultServeMux
	}
	if minimumInterval < time.Second {
		minimumInterval = time.Second
	}
	if maximumInterval <= minimumInterval {
		maximumInterval = 0
	}
	if logger == nil {
		logger = nulllogger.New()
	}
	dialer := &Dialer{
		dialer:          rawDialer,
		minimumInterval: minimumInterval,
		maximumInterval: maximumInterval,
		logger:          logger,
		connectionMap:   make(map[string]net.Conn),
	}
	serveMux.Handle(urlPath, dialer)
	return dialer
}

// Add a connection to the map. Returns true if added, false if duplicate.
func (d *Dialer) add(address string, conn net.Conn) bool {
	d.connectionMapLock.Lock()
	defer d.connectionMapLock.Unlock()
	if _, ok := d.connectionMap[address]; ok {
		return false
	} else {
		d.connectionMap[address] = conn
		return true
	}
}

func (d *Dialer) dial(network, address string) (net.Conn, error) {
	if network != "tcp" || len(d.connectionMap) < 1 {
		return d.dialer.Dial(network, address)
	}
	if conn, err := d.lookupDial(address); err != nil {
		return nil, err
	} else if conn != nil {
		return conn, nil
	}
	return d.dialer.Dial(network, address)
}

func (d *Dialer) lookupDial(address string) (net.Conn, error) {
	host, port, err := net.SplitHostPort(address)
	if err != nil {
		return nil, err
	}
	addrs, err := net.LookupHost(host)
	if err != nil {
		return nil, err
	}
	if len(addrs) < 1 {
		return nil, nil
	}
	for _, addr := range addrs {
		oneAddress := net.JoinHostPort(addr, port)
		if conn := d.lookup(oneAddress); conn != nil {
			d.logger.Debugf(0, "Consuming reverse dialer connection from: %s\n",
				oneAddress)
			// Tell other side we are ready for them to accept.
			buffer := make([]byte, 1)
			if _, err := conn.Write(buffer); err != nil {
				d.logger.Printf("error sending please-accept message: %s\n",
					err)
				return nil, nil
			}
			return conn, nil
		}
	}
	return nil, nil
}

// Lookup a connection and remove it from the map. Caller must consume.
func (d *Dialer) lookup(address string) net.Conn {
	d.connectionMapLock.Lock()
	defer d.connectionMapLock.Unlock()
	if conn, ok := d.connectionMap[address]; ok {
		delete(d.connectionMap, address)
		return conn
	}
	return nil
}

func (d *Dialer) serveHTTP(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	hijacker, ok := w.(http.Hijacker)
	if !ok {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		d.logger.Println("not a hijacker ", req.RemoteAddr)
		return
	}
	conn, _, err := hijacker.Hijack()
	if err != nil {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		d.logger.Println("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
		return
	}
	defer func() {
		if conn != nil {
			conn.Close()
		}
	}()
	d.connectionMapLock.Lock()
	_, ok = d.connectionMap[req.RemoteAddr]
	d.connectionMapLock.Unlock()
	if ok {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusAlreadyReported)
		return
	}
	_, err = io.WriteString(conn, "HTTP/1.0 "+connectString+"\n\n")
	if err != nil {
		d.logger.Println("error writing connect message: ", err.Error())
		return
	}
	message := reverseDialerMessage{
		MinimumInterval: d.minimumInterval,
		MaximumInterval: d.maximumInterval,
	}
	encoder := json.NewEncoder(conn)
	encoder.SetIndent("", "    ")
	if err := encoder.Encode(message); err != nil {
		d.logger.Printf("error writing ReverseDialerMessage: %s\n", err)
		return
	}
	// Ensure we don't write anything else until the other end has drained it's
	// buffer.
	buffer := make([]byte, 1)
	if _, err := conn.Read(buffer); err != nil {
		d.logger.Printf("error reading sync byte: %s\n", err)
		return
	}
	if d.add(req.RemoteAddr, conn) {
		d.logger.Debugf(0, "Registered reverse dialer connection from: %s\n",
			req.RemoteAddr)
	} else {
		d.logger.Printf(
			"Closing duplicate reverse dialer connection from: %s\n",
			req.RemoteAddr)
	}
	conn = nil
}
<|endoftext|>


<commit_before>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package sublime

import (
	"fmt"
	"github.com/limetext/gopy/lib"
	"github.com/limetext/lime-backend/lib"
	"github.com/limetext/lime-backend/lib/log"
	"github.com/limetext/lime-backend/lib/packages"
	"github.com/limetext/lime-backend/lib/render"
	"github.com/limetext/lime-backend/lib/util"
	"github.com/limetext/lime-backend/lib/watch"
	"os"
	"path"
	"path/filepath"
	"time"
)

func sublime_Console(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) {
	if tu.Size() != 1 {
		return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size())
	}
	if i, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		log.Info("Python sez: %s", i)
	}
	return toPython(nil)
}

func sublime_set_timeout(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) {
	var (
		pyarg py.Object
	)
	if tu.Size() != 2 {
		return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size())
	}
	if i, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		pyarg = i
	}
	if i, err := tu.GetItem(1); err != nil {
		return nil, err
	} else if v, err := fromPython(i); err != nil {
		return nil, err
	} else if v2, ok := v.(int); !ok {
		return nil, fmt.Errorf("Expected int not %s", i.Type())
	} else {
		pyarg.Incref()
		go func() {
			time.Sleep(time.Millisecond * time.Duration(v2))
			l := py.NewLock()
			defer l.Unlock()
			defer pyarg.Decref()
			if ret, err := pyarg.Base().CallFunctionObjArgs(); err != nil {
				log.Debug("Error in callback: %v", err)
			} else {
				ret.Decref()
			}
		}()
	}
	return toPython(nil)
}

func init() {
	backend.OnInit.Add(onInit)

	sublime_methods = append(sublime_methods, py.Method{Name: "console", Func: sublime_Console}, py.Method{Name: "set_timeout", Func: sublime_set_timeout})
	backend.GetEditor()
	l := py.InitAndLock()
	defer l.Unlock()
	//	py.InitializeEx(false)
	m, err := py.InitModule("sublime", sublime_methods)
	if err != nil {
		panic(err)
	}

	type class struct {
		name string
		c    *py.Class
	}
	classes := []class{
		{"Region", &_regionClass},
		{"RegionSet", &_region_setClass},
		{"View", &_viewClass},
		{"Window", &_windowClass},
		{"Edit", &_editClass},
		{"Settings", &_settingsClass},
		{"WindowCommandGlue", &_windowCommandGlueClass},
		{"TextCommandGlue", &_textCommandGlueClass},
		{"ApplicationCommandGlue", &_applicationCommandGlueClass},
		{"OnQueryContextGlue", &_onQueryContextGlueClass},
		{"ViewEventGlue", &_viewEventGlueClass},
	}
	type constant struct {
		name     string
		constant int
	}
	constants := []constant{
		{"OP_EQUAL", int(util.OpEqual)},
		{"OP_NOT_EQUAL", int(util.OpNotEqual)},
		{"OP_REGEX_MATCH", int(util.OpRegexMatch)},
		{"OP_NOT_REGEX_MATCH", int(util.OpNotRegexMatch)},
		{"OP_REGEX_CONTAINS", int(util.OpRegexContains)},
		{"OP_NOT_REGEX_CONTAINS", int(util.OpNotRegexContains)},
		{"INHIBIT_WORD_COMPLETIONS", 0},
		{"INHIBIT_EXPLICIT_COMPLETIONS", 0},
		{"LITERAL", int(backend.IGNORECASE)},
		{"IGNORECASE", int(backend.LITERAL)},
		{"CLASS_WORD_START", int(backend.CLASS_WORD_START)},
		{"CLASS_WORD_END", int(backend.CLASS_WORD_END)},
		{"CLASS_PUNCTUATION_START", int(backend.CLASS_PUNCTUATION_START)},
		{"CLASS_PUNCTUATION_END", int(backend.CLASS_PUNCTUATION_END)},
		{"CLASS_SUB_WORD_START", int(backend.CLASS_SUB_WORD_START)},
		{"CLASS_SUB_WORD_END", int(backend.CLASS_SUB_WORD_END)},
		{"CLASS_LINE_START", int(backend.CLASS_LINE_START)},
		{"CLASS_LINE_END", int(backend.CLASS_LINE_END)},
		{"CLASS_EMPTY_LINE", int(backend.CLASS_EMPTY_LINE)},
		{"CLASS_MIDDLE_WORD", int(backend.CLASS_MIDDLE_WORD)},
		{"CLASS_WORD_START_WITH_PUNCTUATION", int(backend.CLASS_WORD_START_WITH_PUNCTUATION)},
		{"CLASS_WORD_END_WITH_PUNCTUATION", int(backend.CLASS_WORD_END_WITH_PUNCTUATION)},
		{"CLASS_OPENING_PARENTHESIS", int(backend.CLASS_OPENING_PARENTHESIS)},
		{"CLASS_CLOSING_PARENTHESIS", int(backend.CLASS_CLOSING_PARENTHESIS)},
		{"DRAW_EMPTY", int(render.DRAW_EMPTY)},
		{"HIDE_ON_MINIMAP", int(render.HIDE_ON_MINIMAP)},
		{"DRAW_EMPTY_AS_OVERWRITE", int(render.DRAW_EMPTY_AS_OVERWRITE)},
		{"DRAW_NO_FILL", int(render.DRAW_NO_FILL)},
		{"DRAW_NO_OUTLINE", int(render.DRAW_NO_OUTLINE)},
		{"DRAW_SOLID_UNDERLINE", int(render.DRAW_SOLID_UNDERLINE)},
		{"DRAW_STIPPLED_UNDERLINE", int(render.DRAW_STIPPLED_UNDERLINE)},
		{"DRAW_SQUIGGLY_UNDERLINE", int(render.DRAW_SQUIGGLY_UNDERLINE)},
		{"PERSISTENT", int(render.PERSISTENT)},
		{"HIDDEN", int(render.HIDDEN)},
	}

	for _, cl := range classes {
		c, err := cl.c.Create()
		if err != nil {
			panic(err)
		}
		if err := m.AddObject(cl.name, c); err != nil {
			panic(err)
		}
	}
	for _, c := range constants {
		if err := m.AddIntConstant(c.name, c.constant); err != nil {
			panic(err)
		}
	}
	py.AddToPath(backend.LIME_PACKAGES_PATH)
	py.AddToPath(backend.LIME_USER_PACKAGES_PATH)

	gopaths := filepath.SplitList(os.ExpandEnv("$GOPATH"))
	for _, gopath := range gopaths {
		py.AddToPath(path.Join(gopath, "src", "github.com", "limetext", "lime-backend", "lib", "sublime"))
	}
}

// Wrapper for packages.Plugin and py.Module
// merges Plugin.Reload and loadPlugin for watcher
type plugin struct {
	*packages.Plugin
	m *py.Module
}

func newPlugin(pl *packages.Plugin, m *py.Module) (p *plugin) {
	p = &plugin{pl, m}
	p.FileChanged(p.Name())
	if err := watcher.Watch(p.Name(), p); err != nil {
		log.Errorf("Couldn't watch %s: %s", p.Name(), err)
	}
	p.loadKeyBindings()
	p.loadSettings()
	return
}

func (p *plugin) FileChanged(name string) {
	p.Reload()
	p.loadPlugin()
}

func (p *plugin) loadPlugin() {
	fi := p.Get().([]os.FileInfo)
	for _, f := range fi {
		fn := f.Name()
		s, err := py.NewUnicode(path.Base(p.Name()) + "." + fn[:len(fn)-3])
		if err != nil {
			log.Error(err)
			return
		}
		if r, err := p.m.Base().CallMethodObjArgs("reload_plugin", s); err != nil {
			log.Error(err)
		} else if r != nil {
			r.Decref()
		}
	}
}

func (p *plugin) load(pkg *packages.Packet) {
	if err := pkg.Load(); err != nil {
		log.Errorf("Failed to load packet %s: %s", pkg.Name(), err)
	} else {
		log.Info("Loaded %s", pkg.Name())
		if err := watcher.Watch(pkg.Name(), pkg); err != nil {
			log.Warn("Couldn't watch %s: %s", pkg.Name(), err)
		}
	}
}

func (p *plugin) loadKeyBindings() {
	ed := backend.GetEditor()
	tmp := ed.KeyBindings().Parent()

	ed.KeyBindings().SetParent(p)
	p.KeyBindings().Parent().KeyBindings().SetParent(tmp)

	pt := path.Join(p.Name(), "Default.sublime-keymap")
	p.load(packages.NewPacket(pt, p.KeyBindings().Parent().KeyBindings()))

	pt = path.Join(p.Name(), "Default ("+ed.Plat()+").sublime-keymap")
	p.load(packages.NewPacket(pt, p.KeyBindings()))
}

func (p *plugin) loadSettings() {
	ed := backend.GetEditor()
	tmp := ed.Settings().Parent()

	ed.Settings().SetParent(p)
	p.Settings().Parent().Settings().Parent().Settings().SetParent(tmp)

	pt := path.Join(p.Name(), "Preferences.sublime-settings")
	p.load(packages.NewPacket(pt, p.Settings().Parent().Settings().Parent().Settings()))

	pt = path.Join(p.Name(), "Preferences ("+ed.Plat()+").sublime-settings")
	p.load(packages.NewPacket(pt, p.Settings().Parent().Settings()))

	pt = path.Join(backend.LIME_USER_PACKAGES_PATH, "Preferences.sublime-settings")
	p.load(packages.NewPacket(pt, p.Settings()))
}

var watcher *watch.Watcher

func onInit() {
	l := py.NewLock()
	defer l.Unlock()
	m, err := py.Import("sublime_plugin")
	if err != nil {
		panic(err)
	}
	sys, err := py.Import("sys")
	if err != nil {
		log.Debug(err)
	} else {
		defer sys.Decref()
	}

	if watcher, err = watch.NewWatcher(); err != nil {
		log.Errorf("Couldn't create watcher: %s", err)
	}

	// TODO: add all plugins after supporting all commands
	// plugins := packages.ScanPlugins(backend.LIME_PACKAGES_PATH, ".py")
	// for _, p := range plugins {
	// 	newPlugin(p, m)
	// }
	newPlugin(packages.NewPlugin(path.Join(backend.LIME_PACKAGES_PATH, "Vintageous"), ".py"), m)

	go watcher.Observe()
}
<commit_msg>Removed redundant log.Errorf function<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package sublime

import (
	"fmt"
	"github.com/limetext/gopy/lib"
	"github.com/limetext/lime-backend/lib"
	"github.com/limetext/lime-backend/lib/log"
	"github.com/limetext/lime-backend/lib/packages"
	"github.com/limetext/lime-backend/lib/render"
	"github.com/limetext/lime-backend/lib/util"
	"github.com/limetext/lime-backend/lib/watch"
	"os"
	"path"
	"path/filepath"
	"time"
)

func sublime_Console(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) {
	if tu.Size() != 1 {
		return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size())
	}
	if i, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		log.Info("Python sez: %s", i)
	}
	return toPython(nil)
}

func sublime_set_timeout(tu *py.Tuple, kwargs *py.Dict) (py.Object, error) {
	var (
		pyarg py.Object
	)
	if tu.Size() != 2 {
		return nil, fmt.Errorf("Unexpected argument count: %d", tu.Size())
	}
	if i, err := tu.GetItem(0); err != nil {
		return nil, err
	} else {
		pyarg = i
	}
	if i, err := tu.GetItem(1); err != nil {
		return nil, err
	} else if v, err := fromPython(i); err != nil {
		return nil, err
	} else if v2, ok := v.(int); !ok {
		return nil, fmt.Errorf("Expected int not %s", i.Type())
	} else {
		pyarg.Incref()
		go func() {
			time.Sleep(time.Millisecond * time.Duration(v2))
			l := py.NewLock()
			defer l.Unlock()
			defer pyarg.Decref()
			if ret, err := pyarg.Base().CallFunctionObjArgs(); err != nil {
				log.Debug("Error in callback: %v", err)
			} else {
				ret.Decref()
			}
		}()
	}
	return toPython(nil)
}

func init() {
	backend.OnInit.Add(onInit)

	sublime_methods = append(sublime_methods, py.Method{Name: "console", Func: sublime_Console}, py.Method{Name: "set_timeout", Func: sublime_set_timeout})
	backend.GetEditor()
	l := py.InitAndLock()
	defer l.Unlock()
	//	py.InitializeEx(false)
	m, err := py.InitModule("sublime", sublime_methods)
	if err != nil {
		panic(err)
	}

	type class struct {
		name string
		c    *py.Class
	}
	classes := []class{
		{"Region", &_regionClass},
		{"RegionSet", &_region_setClass},
		{"View", &_viewClass},
		{"Window", &_windowClass},
		{"Edit", &_editClass},
		{"Settings", &_settingsClass},
		{"WindowCommandGlue", &_windowCommandGlueClass},
		{"TextCommandGlue", &_textCommandGlueClass},
		{"ApplicationCommandGlue", &_applicationCommandGlueClass},
		{"OnQueryContextGlue", &_onQueryContextGlueClass},
		{"ViewEventGlue", &_viewEventGlueClass},
	}
	type constant struct {
		name     string
		constant int
	}
	constants := []constant{
		{"OP_EQUAL", int(util.OpEqual)},
		{"OP_NOT_EQUAL", int(util.OpNotEqual)},
		{"OP_REGEX_MATCH", int(util.OpRegexMatch)},
		{"OP_NOT_REGEX_MATCH", int(util.OpNotRegexMatch)},
		{"OP_REGEX_CONTAINS", int(util.OpRegexContains)},
		{"OP_NOT_REGEX_CONTAINS", int(util.OpNotRegexContains)},
		{"INHIBIT_WORD_COMPLETIONS", 0},
		{"INHIBIT_EXPLICIT_COMPLETIONS", 0},
		{"LITERAL", int(backend.IGNORECASE)},
		{"IGNORECASE", int(backend.LITERAL)},
		{"CLASS_WORD_START", int(backend.CLASS_WORD_START)},
		{"CLASS_WORD_END", int(backend.CLASS_WORD_END)},
		{"CLASS_PUNCTUATION_START", int(backend.CLASS_PUNCTUATION_START)},
		{"CLASS_PUNCTUATION_END", int(backend.CLASS_PUNCTUATION_END)},
		{"CLASS_SUB_WORD_START", int(backend.CLASS_SUB_WORD_START)},
		{"CLASS_SUB_WORD_END", int(backend.CLASS_SUB_WORD_END)},
		{"CLASS_LINE_START", int(backend.CLASS_LINE_START)},
		{"CLASS_LINE_END", int(backend.CLASS_LINE_END)},
		{"CLASS_EMPTY_LINE", int(backend.CLASS_EMPTY_LINE)},
		{"CLASS_MIDDLE_WORD", int(backend.CLASS_MIDDLE_WORD)},
		{"CLASS_WORD_START_WITH_PUNCTUATION", int(backend.CLASS_WORD_START_WITH_PUNCTUATION)},
		{"CLASS_WORD_END_WITH_PUNCTUATION", int(backend.CLASS_WORD_END_WITH_PUNCTUATION)},
		{"CLASS_OPENING_PARENTHESIS", int(backend.CLASS_OPENING_PARENTHESIS)},
		{"CLASS_CLOSING_PARENTHESIS", int(backend.CLASS_CLOSING_PARENTHESIS)},
		{"DRAW_EMPTY", int(render.DRAW_EMPTY)},
		{"HIDE_ON_MINIMAP", int(render.HIDE_ON_MINIMAP)},
		{"DRAW_EMPTY_AS_OVERWRITE", int(render.DRAW_EMPTY_AS_OVERWRITE)},
		{"DRAW_NO_FILL", int(render.DRAW_NO_FILL)},
		{"DRAW_NO_OUTLINE", int(render.DRAW_NO_OUTLINE)},
		{"DRAW_SOLID_UNDERLINE", int(render.DRAW_SOLID_UNDERLINE)},
		{"DRAW_STIPPLED_UNDERLINE", int(render.DRAW_STIPPLED_UNDERLINE)},
		{"DRAW_SQUIGGLY_UNDERLINE", int(render.DRAW_SQUIGGLY_UNDERLINE)},
		{"PERSISTENT", int(render.PERSISTENT)},
		{"HIDDEN", int(render.HIDDEN)},
	}

	for _, cl := range classes {
		c, err := cl.c.Create()
		if err != nil {
			panic(err)
		}
		if err := m.AddObject(cl.name, c); err != nil {
			panic(err)
		}
	}
	for _, c := range constants {
		if err := m.AddIntConstant(c.name, c.constant); err != nil {
			panic(err)
		}
	}
	py.AddToPath(backend.LIME_PACKAGES_PATH)
	py.AddToPath(backend.LIME_USER_PACKAGES_PATH)

	gopaths := filepath.SplitList(os.ExpandEnv("$GOPATH"))
	for _, gopath := range gopaths {
		py.AddToPath(path.Join(gopath, "src", "github.com", "limetext", "lime-backend", "lib", "sublime"))
	}
}

// Wrapper for packages.Plugin and py.Module
// merges Plugin.Reload and loadPlugin for watcher
type plugin struct {
	*packages.Plugin
	m *py.Module
}

func newPlugin(pl *packages.Plugin, m *py.Module) (p *plugin) {
	p = &plugin{pl, m}
	p.FileChanged(p.Name())
	if err := watcher.Watch(p.Name(), p); err != nil {
		log.Error("Couldn't watch %s: %s", p.Name(), err)
	}
	p.loadKeyBindings()
	p.loadSettings()
	return
}

func (p *plugin) FileChanged(name string) {
	p.Reload()
	p.loadPlugin()
}

func (p *plugin) loadPlugin() {
	fi := p.Get().([]os.FileInfo)
	for _, f := range fi {
		fn := f.Name()
		s, err := py.NewUnicode(path.Base(p.Name()) + "." + fn[:len(fn)-3])
		if err != nil {
			log.Error(err)
			return
		}
		if r, err := p.m.Base().CallMethodObjArgs("reload_plugin", s); err != nil {
			log.Error(err)
		} else if r != nil {
			r.Decref()
		}
	}
}

func (p *plugin) load(pkg *packages.Packet) {
	if err := pkg.Load(); err != nil {
		log.Error("Failed to load packet %s: %s", pkg.Name(), err)
	} else {
		log.Info("Loaded %s", pkg.Name())
		if err := watcher.Watch(pkg.Name(), pkg); err != nil {
			log.Warn("Couldn't watch %s: %s", pkg.Name(), err)
		}
	}
}

func (p *plugin) loadKeyBindings() {
	ed := backend.GetEditor()
	tmp := ed.KeyBindings().Parent()

	ed.KeyBindings().SetParent(p)
	p.KeyBindings().Parent().KeyBindings().SetParent(tmp)

	pt := path.Join(p.Name(), "Default.sublime-keymap")
	p.load(packages.NewPacket(pt, p.KeyBindings().Parent().KeyBindings()))

	pt = path.Join(p.Name(), "Default ("+ed.Plat()+").sublime-keymap")
	p.load(packages.NewPacket(pt, p.KeyBindings()))
}

func (p *plugin) loadSettings() {
	ed := backend.GetEditor()
	tmp := ed.Settings().Parent()

	ed.Settings().SetParent(p)
	p.Settings().Parent().Settings().Parent().Settings().SetParent(tmp)

	pt := path.Join(p.Name(), "Preferences.sublime-settings")
	p.load(packages.NewPacket(pt, p.Settings().Parent().Settings().Parent().Settings()))

	pt = path.Join(p.Name(), "Preferences ("+ed.Plat()+").sublime-settings")
	p.load(packages.NewPacket(pt, p.Settings().Parent().Settings()))

	pt = path.Join(backend.LIME_USER_PACKAGES_PATH, "Preferences.sublime-settings")
	p.load(packages.NewPacket(pt, p.Settings()))
}

var watcher *watch.Watcher

func onInit() {
	l := py.NewLock()
	defer l.Unlock()
	m, err := py.Import("sublime_plugin")
	if err != nil {
		panic(err)
	}
	sys, err := py.Import("sys")
	if err != nil {
		log.Debug(err)
	} else {
		defer sys.Decref()
	}

	if watcher, err = watch.NewWatcher(); err != nil {
		log.Error("Couldn't create watcher: %s", err)
	}

	// TODO: add all plugins after supporting all commands
	// plugins := packages.ScanPlugins(backend.LIME_PACKAGES_PATH, ".py")
	// for _, p := range plugins {
	// 	newPlugin(p, m)
	// }
	newPlugin(packages.NewPlugin(path.Join(backend.LIME_PACKAGES_PATH, "Vintageous"), ".py"), m)

	go watcher.Observe()
}
<|endoftext|>


<commit_before><commit_msg>images destroy<commit_after><|endoftext|>


<commit_before><commit_msg>Fix nil dereference panic after 8563c7a<commit_after><|endoftext|>


<commit_before><commit_msg>Move message about which config file we’re using into a log at the start<commit_after><|endoftext|>


<commit_before><commit_msg>Add "aptomi server" command<commit_after><|endoftext|>


<commit_before><commit_msg>cmd_update: Print name of matching rule<commit_after><|endoftext|>


<commit_before>// Copyright 2020 The LUCI 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 git

import (
	"bufio"
	"bytes"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestReadWrite(t *testing.T) {
	t.Parallel()

	Convey(`ReadWrite`, t, func() {
		test := func(g *Graph) {
			buf := &bytes.Buffer{}
			w := writer{w: buf}
			err := w.writeGraph(g)
			So(err, ShouldBeNil)

			r := reader{r: bufio.NewReader(buf)}
			g2 := &Graph{}
			err = r.readGraph(g2)
			So(err, ShouldBeNil)

			g2.root.visit(func(n *node) bool {
				n.copyEdgesOnAppend = false
				return true
			})
			So(g, ShouldResemble, g2)
		}

		Convey(`Zero`, func() {
			test(&Graph{})
		})

		Convey(`Two direct children`, func() {
			foo := &node{name: "/foo", commits: 1}
			bar := &node{name: "/bar", commits: 2}
			foo.edges = []edge{{to: bar, commonCommits: 1}}
			bar.edges = []edge{{to: foo, commonCommits: 1}}
			test(&Graph{
				Commit: "deadbeef",
				root: node{
					children: map[string]*node{
						"foo": foo,
						"bar": bar,
					},
				},
			})
		})
	})
}
<commit_msg>[filegraph] Fix ReadWrite test<commit_after>// Copyright 2020 The LUCI 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 git

import (
	"bufio"
	"bytes"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestReadWrite(t *testing.T) {
	t.Parallel()

	Convey(`ReadWrite`, t, func() {
		test := func(g *Graph) {
			g.ensureInitialized()

			buf := &bytes.Buffer{}
			w := writer{w: buf}
			err := w.writeGraph(g)
			So(err, ShouldBeNil)

			r := reader{r: bufio.NewReader(buf)}
			g2 := &Graph{}
			g2.ensureInitialized()
			err = r.readGraph(g2)
			So(err, ShouldBeNil)

			g2.root.visit(func(n *node) bool {
				n.copyEdgesOnAppend = false
				return true
			})
			So(g, ShouldResemble, g2)
		}

		Convey(`Zero`, func() {
			test(&Graph{})
		})

		Convey(`Two direct children`, func() {
			foo := &node{name: "//foo", commits: 1}
			bar := &node{name: "//bar", commits: 2}
			foo.edges = []edge{{to: bar, commonCommits: 1}}
			bar.edges = []edge{{to: foo, commonCommits: 1}}
			test(&Graph{
				Commit: "deadbeef",
				root: node{
					name: "//",
					children: map[string]*node{
						"foo": foo,
						"bar": bar,
					},
				},
			})
		})
	})
}
<|endoftext|>


<commit_before>package input

import (
	"encoding/json"
	"errors"
	"fmt"
	"sync/atomic"
	"time"

	"github.com/Jeffail/benthos/v3/internal/bloblang"
	"github.com/Jeffail/benthos/v3/internal/bloblang/mapping"
	"github.com/Jeffail/benthos/v3/internal/docs"
	"github.com/Jeffail/benthos/v3/internal/interop"
	"github.com/Jeffail/benthos/v3/internal/shutdown"
	"github.com/Jeffail/benthos/v3/lib/condition"
	"github.com/Jeffail/benthos/v3/lib/log"
	"github.com/Jeffail/benthos/v3/lib/metrics"
	"github.com/Jeffail/benthos/v3/lib/types"
	"github.com/cenkalti/backoff/v4"
	"github.com/google/go-cmp/cmp"
	"gopkg.in/yaml.v3"
)

//------------------------------------------------------------------------------

func init() {
	Constructors[TypeReadUntil] = TypeSpec{
		constructor: fromSimpleConstructor(NewReadUntil),
		Summary: `
Reads messages from a child input until a consumed message passes a [Bloblang query](/docs/guides/bloblang/about/), at which point the input closes.`,
		Description: `
Messages are read continuously while the query check returns false, when the query returns true the message that triggered the check is sent out and the input is closed. Use this to define inputs where the stream should end once a certain message appears.

Sometimes inputs close themselves. For example, when the ` + "`file`" + ` input type reaches the end of a file it will shut down. By default this type will also shut down. If you wish for the input type to be restarted every time it shuts down until the query check is met then set ` + "`restart_input` to `true`." + `

### Metadata

A metadata key ` + "`benthos_read_until` containing the value `final`" + ` is added to the first part of the message that triggers the input to stop.`,
		Examples: []docs.AnnotatedExample{
			{
				Title:   "Consume N Messages",
				Summary: "A common reason to use this input is to consume only N messages from an input and then stop. This can easily be done with the [`count` function](/docs/guides/bloblang/functions/#count):",
				Config: `
# Only read 100 messages, and then exit.
input:
  read_until:
    check: count("messages") >= 100
    input:
      kafka:
        addresses: [ TODO ]
        topics: [ foo, bar ]
        consumer_group: foogroup
`,
			},
		},
		FieldSpecs: docs.FieldSpecs{
			docs.FieldCommon("input", "The child input to consume from.").HasType(docs.FieldTypeInput),
			docs.FieldBloblang(
				"check",
				"A [Bloblang query](/docs/guides/bloblang/about/) that should return a boolean value indicating whether the input should now be closed.",
				`this.type == "foo"`,
				`count("messages") >= 100`,
			).HasDefault(""),
			docs.FieldDeprecated("condition").HasType(docs.FieldTypeCondition).OmitWhen(func(field, _ interface{}) (string, bool) {
				defaultBytes, err := yaml.Marshal(condition.NewConfig())
				if err != nil {
					return "", false
				}
				var iDefault interface{}
				if err = yaml.Unmarshal(defaultBytes, &iDefault); err != nil {
					return "", false
				}
				return "the condition field is deprecated in favour of check", cmp.Equal(field, iDefault)
			}),
			docs.FieldCommon("restart_input", "Whether the input should be reopened if it closes itself before the condition has resolved to true."),
		},
		Categories: []Category{
			CategoryUtility,
		},
	}
}

func isDefaultCond(cond condition.Config) bool {
	return cmp.Equal(cond, condition.NewConfig())
}

//------------------------------------------------------------------------------

// ReadUntilConfig contains configuration values for the ReadUntil input type.
type ReadUntilConfig struct {
	Input     *Config          `json:"input" yaml:"input"`
	Restart   bool             `json:"restart_input" yaml:"restart_input"`
	Condition condition.Config `json:"condition" yaml:"condition"`
	Check     string           `json:"check" yaml:"check"`
}

// NewReadUntilConfig creates a new ReadUntilConfig with default values.
func NewReadUntilConfig() ReadUntilConfig {
	return ReadUntilConfig{
		Input:     nil,
		Restart:   false,
		Condition: condition.NewConfig(),
		Check:     "",
	}
}

//------------------------------------------------------------------------------

type dummyReadUntilConfig struct {
	Input     interface{}      `json:"input" yaml:"input"`
	Restart   bool             `json:"restart_input" yaml:"restart_input"`
	Condition condition.Config `json:"condition" yaml:"condition"`
	Check     string           `json:"check" yaml:"check"`
}

// MarshalJSON prints an empty object instead of nil.
func (r ReadUntilConfig) MarshalJSON() ([]byte, error) {
	dummy := dummyReadUntilConfig{
		Input:     r.Input,
		Restart:   r.Restart,
		Condition: r.Condition,
		Check:     r.Check,
	}
	if r.Input == nil {
		dummy.Input = struct{}{}
	}
	return json.Marshal(dummy)
}

// MarshalYAML prints an empty object instead of nil.
func (r ReadUntilConfig) MarshalYAML() (interface{}, error) {
	dummy := dummyReadUntilConfig{
		Input:     r.Input,
		Restart:   r.Restart,
		Condition: r.Condition,
		Check:     r.Check,
	}
	if r.Input == nil {
		dummy.Input = struct{}{}
	}
	return dummy, nil
}

//------------------------------------------------------------------------------

// ReadUntil is an input type that continuously reads another input type until a
// condition returns true on a message consumed.
type ReadUntil struct {
	running int32
	conf    ReadUntilConfig

	wrapped Type
	cond    condition.Type
	check   *mapping.Executor

	wrapperMgr   types.Manager
	wrapperLog   log.Modular
	wrapperStats metrics.Type

	stats metrics.Type
	log   log.Modular

	transactions chan types.Transaction

	closeChan  chan struct{}
	closedChan chan struct{}
}

// NewReadUntil creates a new ReadUntil input type.
func NewReadUntil(
	conf Config,
	mgr types.Manager,
	log log.Modular,
	stats metrics.Type,
) (Type, error) {
	if conf.ReadUntil.Input == nil {
		return nil, errors.New("cannot create read_until input without a child")
	}

	wrapped, err := New(
		*conf.ReadUntil.Input, mgr, log, stats,
	)
	if err != nil {
		return nil, fmt.Errorf("failed to create input '%v': %v", conf.ReadUntil.Input.Type, err)
	}

	var cond condition.Type
	if !isDefaultCond(conf.ReadUntil.Condition) {
		cMgr, cLog, cStats := interop.LabelChild("read_until.condition", mgr, log, stats)
		if cond, err = condition.New(conf.ReadUntil.Condition, cMgr, cLog, cStats); err != nil {
			return nil, fmt.Errorf("failed to create condition '%v': %v", conf.ReadUntil.Condition.Type, err)
		}
	}

	var check *mapping.Executor
	if len(conf.ReadUntil.Check) > 0 {
		if check, err = bloblang.NewMapping("", conf.ReadUntil.Check); err != nil {
			return nil, fmt.Errorf("failed to parse check query: %w", err)
		}
	}

	if cond == nil && check == nil {
		return nil, errors.New("a check query is required")
	}

	if cond != nil && check != nil {
		return nil, errors.New("cannot specify both a condition and a check query")
	}

	_, rLog, rStats := interop.LabelChild("read_until", mgr, log, stats)
	rdr := &ReadUntil{
		running: 1,
		conf:    conf.ReadUntil,

		wrapperLog:   log,
		wrapperStats: stats,
		wrapperMgr:   mgr,

		log:          rLog,
		stats:        rStats,
		wrapped:      wrapped,
		cond:         cond,
		check:        check,
		transactions: make(chan types.Transaction),
		closeChan:    make(chan struct{}),
		closedChan:   make(chan struct{}),
	}

	go rdr.loop()
	return rdr, nil
}

//------------------------------------------------------------------------------

func (r *ReadUntil) loop() {
	var (
		mRunning         = r.stats.GetGauge("running")
		mRestartErr      = r.stats.GetCounter("restart.error")
		mRestartSucc     = r.stats.GetCounter("restart.success")
		mInputClosed     = r.stats.GetCounter("input.closed")
		mCount           = r.stats.GetCounter("count")
		mPropagated      = r.stats.GetCounter("propagated")
		mFinalPropagated = r.stats.GetCounter("final.propagated")
		mFinalResSent    = r.stats.GetCounter("final.response.sent")
		mFinalResSucc    = r.stats.GetCounter("final.response.success")
		mFinalResErr     = r.stats.GetCounter("final.response.error")
	)

	defer func() {
		if r.wrapped != nil {
			r.wrapped.CloseAsync()
			_ = r.wrapped.WaitForClose(shutdown.MaximumShutdownWait())
		}
		mRunning.Decr(1)

		close(r.transactions)
		close(r.closedChan)
	}()
	mRunning.Incr(1)

	// Prevents busy loop when an input never yields messages.
	restartBackoff := backoff.NewExponentialBackOff()
	restartBackoff.InitialInterval = time.Millisecond
	restartBackoff.MaxInterval = time.Millisecond * 100
	restartBackoff.MaxElapsedTime = 0

	var open bool

runLoop:
	for atomic.LoadInt32(&r.running) == 1 {
		if r.wrapped == nil {
			if r.conf.Restart {
				select {
				case <-time.After(restartBackoff.NextBackOff()):
				case <-r.closeChan:
					return
				}
				var err error
				if r.wrapped, err = New(
					*r.conf.Input, r.wrapperMgr, r.wrapperLog, r.wrapperStats,
				); err != nil {
					mRestartErr.Incr(1)
					r.log.Errorf("Failed to create input '%v': %v\n", r.conf.Input.Type, err)
					return
				}
				mRestartSucc.Incr(1)
			} else {
				return
			}
		}

		var tran types.Transaction
		select {
		case tran, open = <-r.wrapped.TransactionChan():
			if !open {
				mInputClosed.Incr(1)
				r.wrapped = nil
				continue runLoop
			}
			restartBackoff.Reset()
		case <-r.closeChan:
			return
		}
		mCount.Incr(1)

		var check bool
		if r.cond != nil {
			check = r.cond.Check(tran.Payload)
		} else {
			var err error
			if check, err = r.check.QueryPart(0, tran.Payload); err != nil {
				check = false
				r.log.Errorf("Failed to execute check query: %v\n", err)
			}
		}
		if !check {
			select {
			case r.transactions <- tran:
				mPropagated.Incr(1)
			case <-r.closeChan:
				return
			}
			continue
		}

		tran.Payload.Get(0).Metadata().Set("benthos_read_until", "final")

		// If this transaction succeeds we shut down.
		tmpRes := make(chan types.Response)
		select {
		case r.transactions <- types.NewTransaction(tran.Payload, tmpRes):
			mFinalPropagated.Incr(1)
		case <-r.closeChan:
			return
		}

		var res types.Response
		select {
		case res, open = <-tmpRes:
			if !open {
				return
			}
			streamEnds := res.Error() == nil
			select {
			case tran.ResponseChan <- res:
				mFinalResSent.Incr(1)
			case <-r.closeChan:
				return
			}
			if streamEnds {
				mFinalResSucc.Incr(1)
				return
			}
			mFinalResErr.Incr(1)
		case <-r.closeChan:
			return
		}
	}
}

// TransactionChan returns a transactions channel for consuming messages from
// this input type.
func (r *ReadUntil) TransactionChan() <-chan types.Transaction {
	return r.transactions
}

// Connected returns a boolean indicating whether this input is currently
// connected to its target.
func (r *ReadUntil) Connected() bool {
	return r.wrapped.Connected()
}

// CloseAsync shuts down the ReadUntil input and stops processing requests.
func (r *ReadUntil) CloseAsync() {
	if atomic.CompareAndSwapInt32(&r.running, 1, 0) {
		close(r.closeChan)
	}
}

// WaitForClose blocks until the ReadUntil input has closed down.
func (r *ReadUntil) WaitForClose(timeout time.Duration) error {
	select {
	case <-r.closedChan:
	case <-time.After(timeout):
		return types.ErrTimeout
	}
	return nil
}

//------------------------------------------------------------------------------
<commit_msg>Trigger 2nd tier shutdown from read_until<commit_after>package input

import (
	"encoding/json"
	"errors"
	"fmt"
	"sync/atomic"
	"time"

	"github.com/Jeffail/benthos/v3/internal/bloblang"
	"github.com/Jeffail/benthos/v3/internal/bloblang/mapping"
	"github.com/Jeffail/benthos/v3/internal/docs"
	"github.com/Jeffail/benthos/v3/internal/interop"
	"github.com/Jeffail/benthos/v3/lib/condition"
	"github.com/Jeffail/benthos/v3/lib/log"
	"github.com/Jeffail/benthos/v3/lib/metrics"
	"github.com/Jeffail/benthos/v3/lib/types"
	"github.com/cenkalti/backoff/v4"
	"github.com/google/go-cmp/cmp"
	"gopkg.in/yaml.v3"
)

//------------------------------------------------------------------------------

func init() {
	Constructors[TypeReadUntil] = TypeSpec{
		constructor: fromSimpleConstructor(NewReadUntil),
		Summary: `
Reads messages from a child input until a consumed message passes a [Bloblang query](/docs/guides/bloblang/about/), at which point the input closes.`,
		Description: `
Messages are read continuously while the query check returns false, when the query returns true the message that triggered the check is sent out and the input is closed. Use this to define inputs where the stream should end once a certain message appears.

Sometimes inputs close themselves. For example, when the ` + "`file`" + ` input type reaches the end of a file it will shut down. By default this type will also shut down. If you wish for the input type to be restarted every time it shuts down until the query check is met then set ` + "`restart_input` to `true`." + `

### Metadata

A metadata key ` + "`benthos_read_until` containing the value `final`" + ` is added to the first part of the message that triggers the input to stop.`,
		Examples: []docs.AnnotatedExample{
			{
				Title:   "Consume N Messages",
				Summary: "A common reason to use this input is to consume only N messages from an input and then stop. This can easily be done with the [`count` function](/docs/guides/bloblang/functions/#count):",
				Config: `
# Only read 100 messages, and then exit.
input:
  read_until:
    check: count("messages") >= 100
    input:
      kafka:
        addresses: [ TODO ]
        topics: [ foo, bar ]
        consumer_group: foogroup
`,
			},
		},
		FieldSpecs: docs.FieldSpecs{
			docs.FieldCommon("input", "The child input to consume from.").HasType(docs.FieldTypeInput),
			docs.FieldBloblang(
				"check",
				"A [Bloblang query](/docs/guides/bloblang/about/) that should return a boolean value indicating whether the input should now be closed.",
				`this.type == "foo"`,
				`count("messages") >= 100`,
			).HasDefault(""),
			docs.FieldDeprecated("condition").HasType(docs.FieldTypeCondition).OmitWhen(func(field, _ interface{}) (string, bool) {
				defaultBytes, err := yaml.Marshal(condition.NewConfig())
				if err != nil {
					return "", false
				}
				var iDefault interface{}
				if err = yaml.Unmarshal(defaultBytes, &iDefault); err != nil {
					return "", false
				}
				return "the condition field is deprecated in favour of check", cmp.Equal(field, iDefault)
			}),
			docs.FieldCommon("restart_input", "Whether the input should be reopened if it closes itself before the condition has resolved to true."),
		},
		Categories: []Category{
			CategoryUtility,
		},
	}
}

func isDefaultCond(cond condition.Config) bool {
	return cmp.Equal(cond, condition.NewConfig())
}

//------------------------------------------------------------------------------

// ReadUntilConfig contains configuration values for the ReadUntil input type.
type ReadUntilConfig struct {
	Input     *Config          `json:"input" yaml:"input"`
	Restart   bool             `json:"restart_input" yaml:"restart_input"`
	Condition condition.Config `json:"condition" yaml:"condition"`
	Check     string           `json:"check" yaml:"check"`
}

// NewReadUntilConfig creates a new ReadUntilConfig with default values.
func NewReadUntilConfig() ReadUntilConfig {
	return ReadUntilConfig{
		Input:     nil,
		Restart:   false,
		Condition: condition.NewConfig(),
		Check:     "",
	}
}

//------------------------------------------------------------------------------

type dummyReadUntilConfig struct {
	Input     interface{}      `json:"input" yaml:"input"`
	Restart   bool             `json:"restart_input" yaml:"restart_input"`
	Condition condition.Config `json:"condition" yaml:"condition"`
	Check     string           `json:"check" yaml:"check"`
}

// MarshalJSON prints an empty object instead of nil.
func (r ReadUntilConfig) MarshalJSON() ([]byte, error) {
	dummy := dummyReadUntilConfig{
		Input:     r.Input,
		Restart:   r.Restart,
		Condition: r.Condition,
		Check:     r.Check,
	}
	if r.Input == nil {
		dummy.Input = struct{}{}
	}
	return json.Marshal(dummy)
}

// MarshalYAML prints an empty object instead of nil.
func (r ReadUntilConfig) MarshalYAML() (interface{}, error) {
	dummy := dummyReadUntilConfig{
		Input:     r.Input,
		Restart:   r.Restart,
		Condition: r.Condition,
		Check:     r.Check,
	}
	if r.Input == nil {
		dummy.Input = struct{}{}
	}
	return dummy, nil
}

//------------------------------------------------------------------------------

// ReadUntil is an input type that continuously reads another input type until a
// condition returns true on a message consumed.
type ReadUntil struct {
	running int32
	conf    ReadUntilConfig

	wrapped Type
	cond    condition.Type
	check   *mapping.Executor

	wrapperMgr   types.Manager
	wrapperLog   log.Modular
	wrapperStats metrics.Type

	stats metrics.Type
	log   log.Modular

	transactions chan types.Transaction

	closeChan  chan struct{}
	closedChan chan struct{}
}

// NewReadUntil creates a new ReadUntil input type.
func NewReadUntil(
	conf Config,
	mgr types.Manager,
	log log.Modular,
	stats metrics.Type,
) (Type, error) {
	if conf.ReadUntil.Input == nil {
		return nil, errors.New("cannot create read_until input without a child")
	}

	wrapped, err := New(
		*conf.ReadUntil.Input, mgr, log, stats,
	)
	if err != nil {
		return nil, fmt.Errorf("failed to create input '%v': %v", conf.ReadUntil.Input.Type, err)
	}

	var cond condition.Type
	if !isDefaultCond(conf.ReadUntil.Condition) {
		cMgr, cLog, cStats := interop.LabelChild("read_until.condition", mgr, log, stats)
		if cond, err = condition.New(conf.ReadUntil.Condition, cMgr, cLog, cStats); err != nil {
			return nil, fmt.Errorf("failed to create condition '%v': %v", conf.ReadUntil.Condition.Type, err)
		}
	}

	var check *mapping.Executor
	if len(conf.ReadUntil.Check) > 0 {
		if check, err = bloblang.NewMapping("", conf.ReadUntil.Check); err != nil {
			return nil, fmt.Errorf("failed to parse check query: %w", err)
		}
	}

	if cond == nil && check == nil {
		return nil, errors.New("a check query is required")
	}

	if cond != nil && check != nil {
		return nil, errors.New("cannot specify both a condition and a check query")
	}

	_, rLog, rStats := interop.LabelChild("read_until", mgr, log, stats)
	rdr := &ReadUntil{
		running: 1,
		conf:    conf.ReadUntil,

		wrapperLog:   log,
		wrapperStats: stats,
		wrapperMgr:   mgr,

		log:          rLog,
		stats:        rStats,
		wrapped:      wrapped,
		cond:         cond,
		check:        check,
		transactions: make(chan types.Transaction),
		closeChan:    make(chan struct{}),
		closedChan:   make(chan struct{}),
	}

	go rdr.loop()
	return rdr, nil
}

//------------------------------------------------------------------------------

func (r *ReadUntil) loop() {
	var (
		mRunning         = r.stats.GetGauge("running")
		mRestartErr      = r.stats.GetCounter("restart.error")
		mRestartSucc     = r.stats.GetCounter("restart.success")
		mInputClosed     = r.stats.GetCounter("input.closed")
		mCount           = r.stats.GetCounter("count")
		mPropagated      = r.stats.GetCounter("propagated")
		mFinalPropagated = r.stats.GetCounter("final.propagated")
		mFinalResSent    = r.stats.GetCounter("final.response.sent")
		mFinalResSucc    = r.stats.GetCounter("final.response.success")
		mFinalResErr     = r.stats.GetCounter("final.response.error")
	)

	defer func() {
		if r.wrapped != nil {
			r.wrapped.CloseAsync()

			// TODO: This triggers a tier 2 shutdown in the child.
			err := r.wrapped.WaitForClose(time.Second)
			for ; err != nil; err = r.wrapped.WaitForClose(time.Second) {
			}
		}
		mRunning.Decr(1)

		close(r.transactions)
		close(r.closedChan)
	}()
	mRunning.Incr(1)

	// Prevents busy loop when an input never yields messages.
	restartBackoff := backoff.NewExponentialBackOff()
	restartBackoff.InitialInterval = time.Millisecond
	restartBackoff.MaxInterval = time.Millisecond * 100
	restartBackoff.MaxElapsedTime = 0

	var open bool

runLoop:
	for atomic.LoadInt32(&r.running) == 1 {
		if r.wrapped == nil {
			if r.conf.Restart {
				select {
				case <-time.After(restartBackoff.NextBackOff()):
				case <-r.closeChan:
					return
				}
				var err error
				if r.wrapped, err = New(
					*r.conf.Input, r.wrapperMgr, r.wrapperLog, r.wrapperStats,
				); err != nil {
					mRestartErr.Incr(1)
					r.log.Errorf("Failed to create input '%v': %v\n", r.conf.Input.Type, err)
					return
				}
				mRestartSucc.Incr(1)
			} else {
				return
			}
		}

		var tran types.Transaction
		select {
		case tran, open = <-r.wrapped.TransactionChan():
			if !open {
				mInputClosed.Incr(1)
				r.wrapped = nil
				continue runLoop
			}
			restartBackoff.Reset()
		case <-r.closeChan:
			return
		}
		mCount.Incr(1)

		var check bool
		if r.cond != nil {
			check = r.cond.Check(tran.Payload)
		} else {
			var err error
			if check, err = r.check.QueryPart(0, tran.Payload); err != nil {
				check = false
				r.log.Errorf("Failed to execute check query: %v\n", err)
			}
		}
		if !check {
			select {
			case r.transactions <- tran:
				mPropagated.Incr(1)
			case <-r.closeChan:
				return
			}
			continue
		}

		tran.Payload.Get(0).Metadata().Set("benthos_read_until", "final")

		// If this transaction succeeds we shut down.
		tmpRes := make(chan types.Response)
		select {
		case r.transactions <- types.NewTransaction(tran.Payload, tmpRes):
			mFinalPropagated.Incr(1)
		case <-r.closeChan:
			return
		}

		var res types.Response
		select {
		case res, open = <-tmpRes:
			if !open {
				return
			}
			streamEnds := res.Error() == nil
			select {
			case tran.ResponseChan <- res:
				mFinalResSent.Incr(1)
			case <-r.closeChan:
				return
			}
			if streamEnds {
				mFinalResSucc.Incr(1)
				return
			}
			mFinalResErr.Incr(1)
		case <-r.closeChan:
			return
		}
	}
}

// TransactionChan returns a transactions channel for consuming messages from
// this input type.
func (r *ReadUntil) TransactionChan() <-chan types.Transaction {
	return r.transactions
}

// Connected returns a boolean indicating whether this input is currently
// connected to its target.
func (r *ReadUntil) Connected() bool {
	return r.wrapped.Connected()
}

// CloseAsync shuts down the ReadUntil input and stops processing requests.
func (r *ReadUntil) CloseAsync() {
	if atomic.CompareAndSwapInt32(&r.running, 1, 0) {
		close(r.closeChan)
	}
}

// WaitForClose blocks until the ReadUntil input has closed down.
func (r *ReadUntil) WaitForClose(timeout time.Duration) error {
	select {
	case <-r.closedChan:
	case <-time.After(timeout):
		return types.ErrTimeout
	}
	return nil
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>package gherkin

import (
	"fmt"
)

type GherkinDOM interface {
	Feature() FeatureNode
}
type GherkinDOMParser interface {
	GherkinParser
	GherkinDOM
	GherkinDOMWriter
	ParseFeature() (FeatureNode, error)
}

type gherkinDOMParser struct {
	gp        GherkinParser
	processed bool
	feature   *featureNode
	scenario  ScenarioNode
	outline   *outlineNode
	step      *stepNode
	pyString  *pyStringNode
	table     *tableNode
}

func NewGherkinDOMParser(content string) GherkinDOMParser {
	g := &gherkinDOMParser{gp: NewGherkinParser(content)}
	g.gp.WithNodeEventProcessor(g)
	return g
}

func (g *gherkinDOMParser) WithNodeEventProcessor(ep NodeEventProcessor) {
	g.gp.WithNodeEventProcessor(ep)
}

func (g *gherkinDOMParser) WithLogFn(logFn LogFn) {
	g.gp.WithLogFn(logFn)
}

func (g *gherkinDOMParser) Init() {
	g.gp.Init()
}

func (g *gherkinDOMParser) Parse() error {
	return g.gp.Parse()
}

func (g *gherkinDOMParser) Execute() {
	g.gp.Parse()
}

func ParseGherkinFeature(content string) (FeatureNode, error) {
	return NewGherkinDOMParser(content).ParseFeature()
}

func (g *gherkinDOMParser) Feature() FeatureNode {
	if !g.processed {
		_, err := g.ParseFeature()
		if err != nil {
			return nil
		}
	}
	return g.feature
}

func (g *gherkinDOMParser) ParseFeature() (FeatureNode, error) {
	g.processed = true
	g.gp.Init()
	if err := g.gp.Parse(); err != nil {
		return nil, err
	}
	g.gp.Execute()
	return g.feature, nil
}

func (g *gherkinDOMParser) ProcessNodeEvent(e NodeEvent) {
	et := e.EventType()
	switch node := e.Node().(type) {
	default:
		fmt.Printf("unexpected type %T", node)
	case *featureNode:
		switch et {
		case BeginNodeEventType:
			g.feature = node
		}
	case *backgroundNode:
		switch et {
		case BeginNodeEventType:
			g.scenario = node
			g.feature.background = node
		}
	case *scenarioNode:
		switch et {
		case BeginNodeEventType:
			g.scenario = node
			g.feature.scenarios = append(g.feature.scenarios, node)
		}
	case *outlineNode:
		switch et {
		case BeginNodeEventType:
			g.scenario = node
			g.feature.scenarios = append(g.feature.scenarios, node)
		}
	case *stepNode:
		switch et {
		case BeginNodeEventType:
			g.step = node
			g.scenario.addStep(g.step)
		case EndNodeEventType:
			if g.pyString != nil {
				g.step.pyString = g.pyString
				g.pyString = nil
			} else if g.table != nil {
				g.step.table = g.table
				g.table = nil
			}
		}
	case *tableNode:
		g.table = node
	case *pyStringNode:
		g.pyString = node
	}
}
<commit_msg>fix dom parser<commit_after>package gherkin

import (
	"fmt"
	"io"
)

type GherkinDOM interface {
	Feature() FeatureNode
	Format(f GherkinFormater) io.Reader
}
type GherkinDOMParser interface {
	GherkinParser
	GherkinDOM
	ParseFeature() (FeatureNode, error)
}

type gherkinDOMParser struct {
	gp        GherkinParser
	processed bool
	feature   *featureNode
	scenario  ScenarioNode
	outline   *outlineNode
	step      *stepNode
	pyString  *pyStringNode
	table     *tableNode
}

func NewGherkinDOMParser(content string) GherkinDOMParser {
	g := &gherkinDOMParser{gp: NewGherkinParser(content)}
	g.gp.WithNodeEventProcessor(g)
	return g
}

func (g *gherkinDOMParser) WithNodeEventProcessor(ep NodeEventProcessor) {
	g.gp.WithNodeEventProcessor(ep)
}

func (g *gherkinDOMParser) WithLogFn(logFn LogFn) {
	g.gp.WithLogFn(logFn)
}

func (g *gherkinDOMParser) Init() {
	g.gp.Init()
}

func (g *gherkinDOMParser) Parse() error {
	return g.gp.Parse()
}

func (g *gherkinDOMParser) Execute() {
	g.gp.Parse()
}

func ParseGherkinFeature(content string) (FeatureNode, error) {
	return NewGherkinDOMParser(content).ParseFeature()
}

func (g *gherkinDOMParser) Feature() FeatureNode {
	if !g.processed {
		_, err := g.ParseFeature()
		if err != nil {
			return nil
		}
	}
	return g.feature
}

func (g *gherkinDOMParser) ParseFeature() (FeatureNode, error) {
	g.processed = true
	g.gp.Init()
	if err := g.gp.Parse(); err != nil {
		return nil, err
	}
	g.gp.Execute()
	return g.feature, nil
}

func (g *gherkinDOMParser) ProcessNodeEvent(e NodeEvent) {
	et := e.EventType()
	switch node := e.Node().(type) {
	default:
		fmt.Printf("unexpected type %T", node)
	case *featureNode:
		switch et {
		case BeginNodeEventType:
			g.feature = node
		}
	case *backgroundNode:
		switch et {
		case BeginNodeEventType:
			g.scenario = node
			g.feature.background = node
		case EndNodeEventType:
			g.scenario = nil
			g.table = nil
		}
	case *scenarioNode:
		switch et {
		case BeginNodeEventType:
			g.scenario = node
			g.feature.scenarios = append(g.feature.scenarios, node)
		case EndNodeEventType:
			g.scenario = nil
			g.table = nil
		}
	case *outlineNode:
		switch et {
		case BeginNodeEventType:
			g.scenario = node
			g.feature.scenarios = append(g.feature.scenarios, node)
		case EndNodeEventType:
			g.scenario = nil
			g.table = nil
		}
	case *stepNode:
		switch et {
		case BeginNodeEventType:
			g.step = node
			g.scenario.addStep(g.step)
		case EndNodeEventType:
			if g.pyString != nil {
				g.step.pyString = g.pyString
				g.pyString = nil
			} else if g.table != nil {
				g.step.table = g.table
				g.table = nil
			}
			g.step = nil
		}
	case *tableNode:
		g.table = node
	case *pyStringNode:
		g.pyString = node
	}
}
<|endoftext|>