text:
package builder

import (
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strings"
	"testing"

	"github.com/golang/protobuf/proto"
	dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
	"github.com/golang/protobuf/ptypes/any"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/golang/protobuf/ptypes/timestamp"
	"github.com/jhump/protoreflect/desc/protoparse"

	"github.com/jhump/protoreflect/desc"
	"github.com/jhump/protoreflect/dynamic"
	_ "github.com/jhump/protoreflect/internal/testprotos"
	"github.com/jhump/protoreflect/internal/testutil"
)

func TestSimpleDescriptorsFromScratch(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*empty.Empty)(nil))
	testutil.Ok(t, err)

	file := NewFile("foo/bar.proto").SetPackageName("foo.bar")
	en := NewEnum("Options").
		AddValue(NewEnumValue("OPTION_1")).
		AddValue(NewEnumValue("OPTION_2")).
		AddValue(NewEnumValue("OPTION_3"))
	file.AddEnum(en)

	msg := NewMessage("FooRequest").
		AddField(NewField("id", FieldTypeInt64())).
		AddField(NewField("name", FieldTypeString())).
		AddField(NewField("options", FieldTypeEnum(en)).
			SetRepeated())
	file.AddMessage(msg)

	sb := NewService("FooService").
		AddMethod(NewMethod("DoSomething", RpcTypeMessage(msg, false), RpcTypeMessage(msg, false))).
		AddMethod(NewMethod("ReturnThings", RpcTypeImportedMessage(md, false), RpcTypeMessage(msg, true)))
	file.AddService(sb)

	fd, err := file.Build()
	testutil.Ok(t, err)

	testutil.Eq(t, []*desc.FileDescriptor{md.GetFile()}, fd.GetDependencies())
	testutil.Require(t, fd.FindEnum("foo.bar.Options") != nil)
	testutil.Eq(t, 3, len(fd.FindEnum("foo.bar.Options").GetValues()))
	testutil.Require(t, fd.FindMessage("foo.bar.FooRequest") != nil)
	testutil.Eq(t, 3, len(fd.FindMessage("foo.bar.FooRequest").GetFields()))
	testutil.Require(t, fd.FindService("foo.bar.FooService") != nil)
	testutil.Eq(t, 2, len(fd.FindService("foo.bar.FooService").GetMethods()))

	// building the others produces same results
	ed, err := en.Build()
	testutil.Ok(t, err)
	testutil.Require(t, proto.Equal(ed.AsProto(), fd.FindEnum("foo.bar.Options").AsProto()))

	md, err = msg.Build()
	testutil.Ok(t, err)
	testutil.Require(t, proto.Equal(md.AsProto(), fd.FindMessage("foo.bar.FooRequest").AsProto()))

	sd, err := sb.Build()
	testutil.Ok(t, err)
	testutil.Require(t, proto.Equal(sd.AsProto(), fd.FindService("foo.bar.FooService").AsProto()))
}

func TestSimpleDescriptorsFromScratch_SyntheticFiles(t *testing.T) {
	md, err := desc.LoadMessageDescriptorForMessage((*empty.Empty)(nil))
	testutil.Ok(t, err)

	en := NewEnum("Options")
	en.AddValue(NewEnumValue("OPTION_1"))
	en.AddValue(NewEnumValue("OPTION_2"))
	en.AddValue(NewEnumValue("OPTION_3"))

	msg := NewMessage("FooRequest")
	msg.AddField(NewField("id", FieldTypeInt64()))
	msg.AddField(NewField("name", FieldTypeString()))
	msg.AddField(NewField("options", FieldTypeEnum(en)).
		SetRepeated())

	sb := NewService("FooService")
	sb.AddMethod(NewMethod("DoSomething", RpcTypeMessage(msg, false), RpcTypeMessage(msg, false)))
	sb.AddMethod(NewMethod("ReturnThings", RpcTypeImportedMessage(md, false), RpcTypeMessage(msg, true)))

	sd, err := sb.Build()
	testutil.Ok(t, err)
	testutil.Eq(t, "FooService", sd.GetFullyQualifiedName())
	testutil.Eq(t, 2, len(sd.GetMethods()))

	// it imports google/protobuf/empty.proto and a synthetic file that has message
	testutil.Eq(t, 2, len(sd.GetFile().GetDependencies()))
	fd := sd.GetFile().GetDependencies()[0]
	testutil.Eq(t, "google/protobuf/empty.proto", fd.GetName())
	testutil.Eq(t, md.GetFile(), fd)
	fd = sd.GetFile().GetDependencies()[1]
	testutil.Require(t, strings.Contains(fd.GetName(), "generated"))
	testutil.Require(t, fd.FindMessage("FooRequest") != nil)
	testutil.Eq(t, 3, len(fd.FindMessage("FooRequest").GetFields()))

	// this one imports only a synthetic file that has enum
	testutil.Eq(t, 1, len(fd.GetDependencies()))
	fd2 := fd.GetDependencies()[0]
	testutil.Require(t, fd2.FindEnum("Options") != nil)
	testutil.Eq(t, 3, len(fd2.FindEnum("Options").GetValues()))

	// building the others produces same results
	ed, err := en.Build()
	testutil.Ok(t, err)
	testutil.Require(t, proto.Equal(ed.AsProto(), fd2.FindEnum("Options").AsProto()))

	md, err = msg.Build()
	testutil.Ok(t, err)
	testutil.Require(t, proto.Equal(md.AsProto(), fd.FindMessage("FooRequest").AsProto()))
}

func TestComplexDescriptorsFromScratch(t *testing.T) {
	mdEmpty, err := desc.LoadMessageDescriptorForMessage((*empty.Empty)(nil))
	testutil.Ok(t, err)
	mdAny, err := desc.LoadMessageDescriptorForMessage((*any.Any)(nil))
	testutil.Ok(t, err)
	mdTimestamp, err := desc.LoadMessageDescriptorForMessage((*timestamp.Timestamp)(nil))
	testutil.Ok(t, err)
	mbAny, err := FromMessage(mdAny)
	testutil.Ok(t, err)

	msgA := NewMessage("FooA").
		AddField(NewField("id", FieldTypeUInt64())).
		AddField(NewField("when", FieldTypeImportedMessage(mdTimestamp))).
		AddField(NewField("extras", FieldTypeImportedMessage(mdAny)).
			SetRepeated()).
		AddField(NewField("builder", FieldTypeMessage(mbAny))).
		SetExtensionRanges([]*dpb.DescriptorProto_ExtensionRange{{Start: proto.Int32(100), End: proto.Int32(201)}})
	msgA2 := NewMessage("Nnn").
		AddField(NewField("uid1", FieldTypeFixed64())).
		AddField(NewField("uid2", FieldTypeFixed64()))
	NewFile("").
		SetPackageName("foo.bar").
		AddMessage(msgA).
		AddMessage(msgA2)

	msgB := NewMessage("FooB").
		AddField(NewField("foo_a", FieldTypeMessage(msgA)).
			SetRepeated()).
		AddField(NewField("name", FieldTypeString()))
	NewFile("").
		SetPackageName("foo.bar").
		AddMessage(msgB)

	enC := NewEnum("Vals").
		AddValue(NewEnumValue("DEFAULT")).
		AddValue(NewEnumValue("VALUE_A")).
		AddValue(NewEnumValue("VALUE_B")).
		AddValue(NewEnumValue("VALUE_C"))
	msgC := NewMessage("BarBaz").
		AddOneOf(NewOneOf("bbb").
			AddChoice(NewField("b1", FieldTypeMessage(msgA))).
			AddChoice(NewField("b2", FieldTypeMessage(msgB)))).
		AddField(NewField("v", FieldTypeEnum(enC)))
	NewFile("some/path/file.proto").
		SetPackageName("foo.baz").
		AddEnum(enC).
		AddMessage(msgC)

	enD := NewEnum("Ppp").
		AddValue(NewEnumValue("P0")).
		AddValue(NewEnumValue("P1")).
		AddValue(NewEnumValue("P2")).
		AddValue(NewEnumValue("P3"))
	exD := NewExtension("ppp", 123, FieldTypeEnum(enD), msgA)
	NewFile("some/other/path/file.proto").
		SetPackageName("foo.biz").
		AddEnum(enD).
		AddExtension(exD)

	msgE := NewMessage("Ppp").
		AddField(NewField("p", FieldTypeEnum(enD))).
		AddField(NewField("n", FieldTypeMessage(msgA2)))
	fd, err := NewFile("").
		SetPackageName("foo.bar").
		AddMessage(msgE).
		AddService(NewService("PppSvc").
			AddMethod(NewMethod("Method1", RpcTypeMessage(msgE, false), RpcTypeImportedMessage(mdEmpty, false))).
			AddMethod(NewMethod("Method2", RpcTypeMessage(msgB, false), RpcTypeMessage(msgC, true)))).
		Build()

	testutil.Ok(t, err)

	testutil.Eq(t, 5, len(fd.GetDependencies()))
	// dependencies sorted; those with generated names come last
	depEmpty := fd.GetDependencies()[0]
	testutil.Eq(t, "google/protobuf/empty.proto", depEmpty.GetName())
	testutil.Eq(t, mdEmpty.GetFile(), depEmpty)
	depD := fd.GetDependencies()[1]
	testutil.Eq(t, "some/other/path/file.proto", depD.GetName())
	depC := fd.GetDependencies()[2]
	testutil.Eq(t, "some/path/file.proto", depC.GetName())
	depA := fd.GetDependencies()[3]
	testutil.Require(t, strings.Contains(depA.GetName(), "generated"))
	depB := fd.GetDependencies()[4]
	testutil.Require(t, strings.Contains(depB.GetName(), "generated"))

	// check contents of files
	testutil.Require(t, depA.FindMessage("foo.bar.FooA") != nil)
	testutil.Eq(t, 4, len(depA.FindMessage("foo.bar.FooA").GetFields()))
	testutil.Require(t, depA.FindMessage("foo.bar.Nnn") != nil)
	testutil.Eq(t, 2, len(depA.FindMessage("foo.bar.Nnn").GetFields()))
	testutil.Eq(t, 2, len(depA.GetDependencies()))

	testutil.Require(t, depB.FindMessage("foo.bar.FooB") != nil)
	testutil.Eq(t, 2, len(depB.FindMessage("foo.bar.FooB").GetFields()))
	testutil.Eq(t, 1, len(depB.GetDependencies()))

	testutil.Require(t, depC.FindMessage("foo.baz.BarBaz") != nil)
	testutil.Eq(t, 3, len(depC.FindMessage("foo.baz.BarBaz").GetFields()))
	testutil.Require(t, depC.FindEnum("foo.baz.Vals") != nil)
	testutil.Eq(t, 4, len(depC.FindEnum("foo.baz.Vals").GetValues()))
	testutil.Eq(t, 2, len(depC.GetDependencies()))

	testutil.Require(t, depD.FindEnum("foo.biz.Ppp") != nil)
	testutil.Eq(t, 4, len(depD.FindEnum("foo.biz.Ppp").GetValues()))
	testutil.Require(t, depD.FindExtensionByName("foo.biz.ppp") != nil)
	testutil.Eq(t, 1, len(depD.GetDependencies()))

	testutil.Require(t, fd.FindMessage("foo.bar.Ppp") != nil)
	testutil.Eq(t, 2, len(fd.FindMessage("foo.bar.Ppp").GetFields()))
	testutil.Require(t, fd.FindService("foo.bar.PppSvc") != nil)
	testutil.Eq(t, 2, len(fd.FindService("foo.bar.PppSvc").GetMethods()))
}

func TestCreatingGroupField(t *testing.T) {
	grpMb := NewMessage("GroupA").
		AddField(NewField("name", FieldTypeString())).
		AddField(NewField("id", FieldTypeInt64()))
	grpFlb := NewGroupField(grpMb)

	mb := NewMessage("TestMessage").
		AddField(NewField("foo", FieldTypeBool())).
		AddField(grpFlb)
	md, err := mb.Build()
	testutil.Ok(t, err)

	testutil.Require(t, md.FindFieldByName("groupa") != nil)
	testutil.Eq(t, dpb.FieldDescriptorProto_TYPE_GROUP, md.FindFieldByName("groupa").GetType())
	nmd := md.GetNestedMessageTypes()[0]
	testutil.Eq(t, "GroupA", nmd.GetName())
	testutil.Eq(t, nmd, md.FindFieldByName("groupa").GetMessageType())

	// try a rename that will fail
	err = grpMb.TrySetName("fooBarBaz")
	testutil.Require(t, err != nil)
	testutil.Eq(t, "group name fooBarBaz must start with capital letter", err.Error())
	// failed rename should not have modified any state
	md2, err := mb.Build()
	testutil.Ok(t, err)
	testutil.Require(t, proto.Equal(md.AsProto(), md2.AsProto()))
	// another attempt that will fail
	err = grpFlb.TrySetName("foobarbaz")
	testutil.Require(t, err != nil)
	testutil.Eq(t, "cannot change name of group field TestMessage.groupa; change name of group instead", err.Error())
	// again, no state should have been modified
	md2, err = mb.Build()
	testutil.Ok(t, err)
	testutil.Require(t, proto.Equal(md.AsProto(), md2.AsProto()))

	// and a rename that succeeds
	err = grpMb.TrySetName("FooBarBaz")
	testutil.Ok(t, err)
	md, err = mb.Build()
	testutil.Ok(t, err)

	// field also renamed
	testutil.Require(t, md.FindFieldByName("foobarbaz") != nil)
	testutil.Eq(t, dpb.FieldDescriptorProto_TYPE_GROUP, md.FindFieldByName("foobarbaz").GetType())
	nmd = md.GetNestedMessageTypes()[0]
	testutil.Eq(t, "FooBarBaz", nmd.GetName())
	testutil.Eq(t, nmd, md.FindFieldByName("foobarbaz").GetMessageType())
}

func TestCreatingMapField(t *testing.T) {
	mapFlb := NewMapField("countsByName", FieldTypeString(), FieldTypeUInt64())
	testutil.Require(t, mapFlb.IsMap())

	mb := NewMessage("TestMessage").
		AddField(NewField("foo", FieldTypeBool())).
		AddField(mapFlb)
	md, err := mb.Build()
	testutil.Ok(t, err)

	testutil.Require(t, md.FindFieldByName("countsByName") != nil)
	testutil.Require(t, md.FindFieldByName("countsByName").IsMap())
	nmd := md.GetNestedMessageTypes()[0]
	testutil.Eq(t, "CountsByNameEntry", nmd.GetName())
	testutil.Eq(t, nmd, md.FindFieldByName("countsByName").GetMessageType())

	// try a rename that will fail
	err = mapFlb.GetType().localMsgType.TrySetName("fooBarBaz")
	testutil.Require(t, err != nil)
	testutil.Eq(t, "cannot change name of map entry TestMessage.CountsByNameEntry; change name of field instead", err.Error())
	// failed rename should not have modified any state
	md2, err := mb.Build()
	testutil.Ok(t, err)
	testutil.Require(t, proto.Equal(md.AsProto(), md2.AsProto()))

	// and a rename that succeeds
	err = mapFlb.TrySetName("fooBarBaz")
	testutil.Ok(t, err)
	md, err = mb.Build()
	testutil.Ok(t, err)

	// map entry also renamed
	testutil.Require(t, md.FindFieldByName("fooBarBaz") != nil)
	testutil.Require(t, md.FindFieldByName("fooBarBaz").IsMap())
	nmd = md.GetNestedMessageTypes()[0]
	testutil.Eq(t, "FooBarBazEntry", nmd.GetName())
	testutil.Eq(t, nmd, md.FindFieldByName("fooBarBaz").GetMessageType())
}

func TestProto3Optional(t *testing.T) {
	mb := NewMessage("Foo")
	flb := NewField("bar", FieldTypeBool()).SetProto3Optional(true)
	mb.AddField(flb)

	_, err := flb.Build()
	testutil.Nok(t, err) // file does not have proto3 syntax

	fb := NewFile("foo.proto").SetProto3(true)
	fb.AddMessage(mb)

	fld, err := flb.Build()
	testutil.Ok(t, err)

	testutil.Require(t, fld.IsProto3Optional())
	testutil.Require(t, fld.GetOneOf() != nil)
	testutil.Require(t, fld.GetOneOf().IsSynthetic())
	testutil.Eq(t, "_bar", fld.GetOneOf().GetName())
}

func TestBuildersFromDescriptors(t *testing.T) {
	for _, s := range []string{"desc_test1.proto", "desc_test2.proto", "desc_test_defaults.proto", "desc_test_options.proto", "desc_test_proto3.proto", "desc_test_wellknowntypes.proto", "nopkg/desc_test_nopkg.proto", "nopkg/desc_test_nopkg_new.proto", "pkg/desc_test_pkg.proto"} {
		fd, err := desc.LoadFileDescriptor(s)
		testutil.Ok(t, err)
		roundTripFile(t, fd)
	}
}

func TestBuildersFromDescriptors_PreserveComments(t *testing.T) {
	fd, err := loadProtoset("../../internal/testprotos/desc_test1.protoset")
	testutil.Ok(t, err)

	fb, err := FromFile(fd)
	testutil.Ok(t, err)

	count := 0
	var checkBuilderComments func(b Builder)
	checkBuilderComments = func(b Builder) {
		hasComment := true
		switch b := b.(type) {
		case *FileBuilder:
			hasComment = false
		case *FieldBuilder:
			// comments for groups are on the message, not the field
			hasComment = b.GetType().GetType() != dpb.FieldDescriptorProto_TYPE_GROUP
		case *MessageBuilder:
			// comments for maps are on the field, not the entry message
			if b.Options.GetMapEntry() {
				// we just return to also skip checking child elements
				// (map entry child elements are synthetic and have no comments)
				return
			}
		}

		if hasComment {
			count++
			testutil.Eq(t, fmt.Sprintf(" Comment for %s\n", b.GetName()), b.GetComments().LeadingComment,
				"wrong comment for builder %s", GetFullyQualifiedName(b))
		}
		for _, ch := range b.GetChildren() {
			checkBuilderComments(ch)
		}
	}

	checkBuilderComments(fb)
	// sanity check that we didn't accidentally short-circuit above and fail to check comments
	testutil.Require(t, count > 30, "too few elements checked")

	// now check that they also come out in the resulting descriptor
	fd, err = fb.Build()
	testutil.Ok(t, err)

	descCount := 0
	var checkDescriptorComments func(d desc.Descriptor)
	checkDescriptorComments = func(d desc.Descriptor) {
		switch d := d.(type) {
		case *desc.FileDescriptor:
			for _, ch := range d.GetMessageTypes() {
				checkDescriptorComments(ch)
			}
			for _, ch := range d.GetEnumTypes() {
				checkDescriptorComments(ch)
			}
			for _, ch := range d.GetExtensions() {
				checkDescriptorComments(ch)
			}
			for _, ch := range d.GetServices() {
				checkDescriptorComments(ch)
			}
			// files don't have comments, so bail out before check below
			return
		case *desc.MessageDescriptor:
			if d.IsMapEntry() {
				// map entry messages have no comments (and neither do their child fields)
				return
			}
			for _, ch := range d.GetFields() {
				checkDescriptorComments(ch)
			}
			for _, ch := range d.GetNestedMessageTypes() {
				checkDescriptorComments(ch)
			}
			for _, ch := range d.GetNestedEnumTypes() {
				checkDescriptorComments(ch)
			}
			for _, ch := range d.GetNestedExtensions() {
				checkDescriptorComments(ch)
			}
			for _, ch := range d.GetOneOfs() {
				checkDescriptorComments(ch)
			}
		case *desc.FieldDescriptor:
			if d.GetType() == dpb.FieldDescriptorProto_TYPE_GROUP {
				// groups comments are on the message, not hte field; so bail out before check below
				return
			}
		case *desc.EnumDescriptor:
			for _, ch := range d.GetValues() {
				checkDescriptorComments(ch)
			}
		case *desc.ServiceDescriptor:
			for _, ch := range d.GetMethods() {
				checkDescriptorComments(ch)
			}
		}

		descCount++
		testutil.Eq(t, fmt.Sprintf(" Comment for %s\n", d.GetName()), d.GetSourceInfo().GetLeadingComments(),
			"wrong comment for descriptor %s", d.GetFullyQualifiedName())
	}

	checkDescriptorComments(fd)
	testutil.Eq(t, count, descCount)
}

func TestBuilder_PreserveAllCommentsAfterBuild(t *testing.T) {
	files := map[string]string{"test.proto": `
syntax = "proto3";

// Leading detached comment for SimpleEnum

// Leading comment for SimpleEnum
enum SimpleEnum {
// Trailing comment for SimpleEnum

  // Leading detached comment for VALUE0

  // Leading comment for VALUE0
  VALUE0 = 0; // Trailing comment for VALUE0
}

// Leading detached comment for SimpleMessage

// Leading comment for SimpleMessage
message SimpleMessage {
// Trailing comment for SimpleMessage

  // Leading detached comment for field1

  // Leading comment for field1
  optional SimpleEnum field1 = 1; // Trailing comment for field1
}
`}

	pa := &protoparse.Parser{
		Accessor:              protoparse.FileContentsFromMap(files),
		IncludeSourceCodeInfo: true,
	}
	fds, err := pa.ParseFiles("test.proto")
	testutil.Ok(t, err)

	fb, err := FromFile(fds[0])
	testutil.Ok(t, err)

	fd, err := fb.Build()
	testutil.Ok(t, err)

	var checkDescriptorComments func(d desc.Descriptor)
	checkDescriptorComments = func(d desc.Descriptor) {
		// fmt.Println(d.GetFullyQualifiedName(), d.GetSourceInfo().GetLeadingDetachedComments(), d.GetSourceInfo().GetLeadingComments(), d.GetSourceInfo().GetTrailingComments())
		switch d := d.(type) {
		case *desc.FileDescriptor:
			for _, ch := range d.GetMessageTypes() {
				checkDescriptorComments(ch)
			}
			for _, ch := range d.GetEnumTypes() {
				checkDescriptorComments(ch)
			}
			// files don't have comments, so bail out before check below
			return
		case *desc.MessageDescriptor:
			if d.IsMapEntry() {
				// map entry messages have no comments (and neither do their child fields)
				return
			}
			for _, ch := range d.GetFields() {
				checkDescriptorComments(ch)
			}
		case *desc.FieldDescriptor:
			if d.GetType() == dpb.FieldDescriptorProto_TYPE_GROUP {
				// groups comments are on the message, not hte field; so bail out before check below
				return
			}
		case *desc.EnumDescriptor:
			for _, ch := range d.GetValues() {
				checkDescriptorComments(ch)
			}
		}
		testutil.Eq(t, 1, len(d.GetSourceInfo().GetLeadingDetachedComments()),
			"wrong number of leading detached comments for %s", d.GetFullyQualifiedName())
		testutil.Eq(t, fmt.Sprintf(" Leading detached comment for %s\n", d.GetName()), d.GetSourceInfo().GetLeadingDetachedComments()[0],
			"wrong leading detached comment for descriptor %s", d.GetFullyQualifiedName())
		testutil.Eq(t, fmt.Sprintf(" Leading comment for %s\n", d.GetName()), d.GetSourceInfo().GetLeadingComments(),
			"wrong leading comment for descriptor %s", d.GetFullyQualifiedName())
		testutil.Eq(t, fmt.Sprintf(" Trailing comment for %s\n", d.GetName()), d.GetSourceInfo().GetTrailingComments(),
			"wrong trailing comment for descriptor %s", d.GetFullyQualifiedName())
	}

	checkDescriptorComments(fd)
}

func loadProtoset(path string) (*desc.FileDescriptor, error) {
	var fds dpb.FileDescriptorSet
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	bb, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	if err = proto.Unmarshal(bb, &fds); err != nil {
		return nil, err
	}
	return desc.CreateFileDescriptorFromSet(&fds)
}

func roundTripFile(t *testing.T, fd *desc.FileDescriptor) {
	// First, recursively verify that every child element can be converted to a
	// Builder and back without loss of fidelity.
	for _, md := range fd.GetMessageTypes() {
		roundTripMessage(t, md)
	}
	for _, ed := range fd.GetEnumTypes() {
		roundTripEnum(t, ed)
	}
	for _, exd := range fd.GetExtensions() {
		roundTripField(t, exd)
	}
	for _, sd := range fd.GetServices() {
		roundTripService(t, sd)
	}

	// Finally, we check the whole file itself.
	fb, err := FromFile(fd)
	testutil.Ok(t, err)

	roundTripped, err := fb.Build()
	testutil.Ok(t, err)

	// Round tripping from a file descriptor to a builder and back will
	// experience some minor changes (that do not impact the semantics of
	// any of the file's contents):
	//  1. The builder sorts dependencies. However the original file
	//     descriptor has dependencies in the order they appear in import
	//     statements in the source file.
	//  2. The builder imports the actual source of all elements and never
	//     uses public imports. The original file, on the other hand, could
	//     used public imports and "indirectly" import other files that way.
	//  3. The builder never emits weak imports.
	//  4. The builder tries to preserve SourceCodeInfo, but will not preserve
	//     position information. So that info does not survive round-tripping
	//     (though comments do: there is a separate test for that). Also, the
	//     round-tripped version will have source code info (even though it
	//     may have no comments and zero position info), even if the original
	//     descriptor had none.
	// So we're going to modify the original descriptor in the same ways.
	// That way, a simple proto.Equal() check will suffice to confirm that
	// the file descriptor survived the round trip.

	// The files we are testing have one occurrence of a public import. The
	// file nopkg/desc_test_nopkg.proto declares nothing and public imports
	// nopkg/desc_test_nopkg_new.proto. So any file that depends on the
	// former will be updated to instead depend on the latter (since it is
	// the actual file that declares used elements).
	fdp := fd.AsFileDescriptorProto()
	needsNopkgNew := false
	hasNoPkgNew := false
	for _, dep := range fdp.Dependency {
		if dep == "nopkg/desc_test_nopkg.proto" {
			needsNopkgNew = true
		}
		if dep == "nopkg/desc_test_nopkg_new.proto" {
			hasNoPkgNew = false
		}
	}
	if needsNopkgNew && !hasNoPkgNew {
		fdp.Dependency = append(fdp.Dependency, "nopkg/desc_test_nopkg_new.proto")
	}

	// Strip any public and weak imports. (The step above should have "fixed"
	// files to handle any actual public import encountered.)
	fdp.PublicDependency = nil
	fdp.WeakDependency = nil

	// Remove source code info: what the builder generates is not expected to
	// match the original source.
	fdp.SourceCodeInfo = nil
	roundTripped.AsFileDescriptorProto().SourceCodeInfo = nil

	// Finally, sort the imports. That way they match the built result (which
	// is always sorted).
	sort.Strings(fdp.Dependency)

	// Now (after tweaking) the original should match the round-tripped descriptor:
	testutil.Require(t, proto.Equal(fdp, roundTripped.AsProto()), "File %q failed round trip.\nExpecting: %s\nGot: %s\n",
		fd.GetName(), proto.MarshalTextString(fdp), proto.MarshalTextString(roundTripped.AsProto()))
}

func roundTripMessage(t *testing.T, md *desc.MessageDescriptor) {
	// first recursively validate all nested elements
	for _, fld := range md.GetFields() {
		roundTripField(t, fld)
	}
	for _, ood := range md.GetOneOfs() {
		oob, err := FromOneOf(ood)
		testutil.Ok(t, err)
		roundTripped, err := oob.Build()
		testutil.Ok(t, err)
		checkDescriptors(t, ood, roundTripped)
	}
	for _, nmd := range md.GetNestedMessageTypes() {
		roundTripMessage(t, nmd)
	}
	for _, ed := range md.GetNestedEnumTypes() {
		roundTripEnum(t, ed)
	}
	for _, exd := range md.GetNestedExtensions() {
		roundTripField(t, exd)
	}

	mb, err := FromMessage(md)
	testutil.Ok(t, err)
	roundTripped, err := mb.Build()
	testutil.Ok(t, err)
	checkDescriptors(t, md, roundTripped)
}

func roundTripEnum(t *testing.T, ed *desc.EnumDescriptor) {
	// first recursively validate all nested elements
	for _, evd := range ed.GetValues() {
		evb, err := FromEnumValue(evd)
		testutil.Ok(t, err)
		roundTripped, err := evb.Build()
		testutil.Ok(t, err)
		checkDescriptors(t, evd, roundTripped)
	}

	eb, err := FromEnum(ed)
	testutil.Ok(t, err)
	roundTripped, err := eb.Build()
	testutil.Ok(t, err)
	checkDescriptors(t, ed, roundTripped)
}

func roundTripField(t *testing.T, fld *desc.FieldDescriptor) {
	flb, err := FromField(fld)
	testutil.Ok(t, err)
	roundTripped, err := flb.Build()
	testutil.Ok(t, err)
	checkDescriptors(t, fld, roundTripped)
}

func roundTripService(t *testing.T, sd *desc.ServiceDescriptor) {
	// first recursively validate all nested elements
	for _, mtd := range sd.GetMethods() {
		mtb, err := FromMethod(mtd)
		testutil.Ok(t, err)
		roundTripped, err := mtb.Build()
		testutil.Ok(t, err)
		checkDescriptors(t, mtd, roundTripped)
	}

	sb, err := FromService(sd)
	testutil.Ok(t, err)
	roundTripped, err := sb.Build()
	testutil.Ok(t, err)
	checkDescriptors(t, sd, roundTripped)
}

func checkDescriptors(t *testing.T, d1, d2 desc.Descriptor) {
	testutil.Eq(t, d1.GetFullyQualifiedName(), d2.GetFullyQualifiedName())
	testutil.Require(t, proto.Equal(d1.AsProto(), d2.AsProto()), "%s failed round trip.\nExpecting: %s\nGot: %s\n",
		d1.GetFullyQualifiedName(), proto.MarshalTextString(d1.AsProto()), proto.MarshalTextString(d2.AsProto()))
}

func TestAddRemoveMoveBuilders(t *testing.T) {
	// add field to one-of
	fld1 := NewField("foo", FieldTypeInt32())
	oo1 := NewOneOf("oofoo")
	oo1.AddChoice(fld1)
	checkChildren(t, oo1, fld1)
	testutil.Eq(t, oo1.GetChoice("foo"), fld1)

	// add one-of w/ field to a message
	msg1 := NewMessage("foo")
	msg1.AddOneOf(oo1)
	checkChildren(t, msg1, oo1)
	testutil.Eq(t, msg1.GetOneOf("oofoo"), oo1)
	// field remains unchanged
	testutil.Eq(t, fld1.GetParent(), oo1)
	testutil.Eq(t, oo1.GetChoice("foo"), fld1)
	// field also now registered with msg1
	testutil.Eq(t, msg1.GetField("foo"), fld1)

	// add empty one-of to message
	oo2 := NewOneOf("oobar")
	msg1.AddOneOf(oo2)
	checkChildren(t, msg1, oo1, oo2)
	testutil.Eq(t, msg1.GetOneOf("oobar"), oo2)
	// now add field to that one-of
	fld2 := NewField("bar", FieldTypeInt32())
	oo2.AddChoice(fld2)
	checkChildren(t, oo2, fld2)
	testutil.Eq(t, oo2.GetChoice("bar"), fld2)
	// field also now registered with msg1
	testutil.Eq(t, msg1.GetField("bar"), fld2)

	// add fails due to name collisions
	fld1dup := NewField("foo", FieldTypeInt32())
	err := oo1.TryAddChoice(fld1dup)
	checkFailedAdd(t, err, oo1, fld1dup, "already contains field")
	fld2 = NewField("bar", FieldTypeInt32())
	err = msg1.TryAddField(fld2)
	checkFailedAdd(t, err, msg1, fld2, "already contains element")
	msg2 := NewMessage("oofoo")
	// name collision can be different type
	// (here, nested message conflicts with a one-of)
	err = msg1.TryAddNestedMessage(msg2)
	checkFailedAdd(t, err, msg1, msg2, "already contains element")

	msg2 = NewMessage("baz")
	msg1.AddNestedMessage(msg2)
	checkChildren(t, msg1, oo1, oo2, msg2)
	testutil.Eq(t, msg1.GetNestedMessage("baz"), msg2)

	// can't add extension or map fields to one-of
	ext1 := NewExtension("abc", 123, FieldTypeInt32(), msg1)
	err = oo1.TryAddChoice(ext1)
	checkFailedAdd(t, err, oo1, ext1, "is an extension, not a regular field")
	err = msg1.TryAddField(ext1)
	checkFailedAdd(t, err, msg1, ext1, "is an extension, not a regular field")
	mapField := NewMapField("abc", FieldTypeInt32(), FieldTypeString())
	err = oo1.TryAddChoice(mapField)
	checkFailedAdd(t, err, oo1, mapField, "cannot add a map field")
	// can add group field though
	groupMsg := NewMessage("Group")
	groupField := NewGroupField(groupMsg)
	oo1.AddChoice(groupField)
	checkChildren(t, oo1, fld1, groupField)
	// adding map and group to msg succeeds
	msg1.AddField(groupField)
	msg1.AddField(mapField)
	checkChildren(t, msg1, oo1, oo2, msg2, groupField, mapField)
	// messages associated with map and group fields are not children of the
	// message, but are in its scope and accessible via GetNestedMessage
	testutil.Eq(t, msg1.GetNestedMessage("Group"), groupMsg)
	testutil.Eq(t, msg1.GetNestedMessage("AbcEntry"), mapField.GetType().localMsgType)

	// adding extension to message
	ext2 := NewExtension("xyz", 234, FieldTypeInt32(), msg1)
	msg1.AddNestedExtension(ext2)
	checkChildren(t, msg1, oo1, oo2, msg2, groupField, mapField, ext2)
	err = msg1.TryAddNestedExtension(ext1) // name collision
	checkFailedAdd(t, err, msg1, ext1, "already contains element")
	fld3 := NewField("ijk", FieldTypeString())
	err = msg1.TryAddNestedExtension(fld3)
	checkFailedAdd(t, err, msg1, fld3, "is not an extension")

	// add enum values to enum
	enumVal1 := NewEnumValue("A")
	enum1 := NewEnum("bazel")
	enum1.AddValue(enumVal1)
	checkChildren(t, enum1, enumVal1)
	testutil.Eq(t, enum1.GetValue("A"), enumVal1)
	enumVal2 := NewEnumValue("B")
	enum1.AddValue(enumVal2)
	checkChildren(t, enum1, enumVal1, enumVal2)
	testutil.Eq(t, enum1.GetValue("B"), enumVal2)
	// fail w/ name collision
	enumVal3 := NewEnumValue("B")
	err = enum1.TryAddValue(enumVal3)
	checkFailedAdd(t, err, enum1, enumVal3, "already contains value")

	msg2.AddNestedEnum(enum1)
	checkChildren(t, msg2, enum1)
	testutil.Eq(t, msg2.GetNestedEnum("bazel"), enum1)
	ext3 := NewExtension("bazel", 987, FieldTypeString(), msg2)
	err = msg2.TryAddNestedExtension(ext3)
	checkFailedAdd(t, err, msg2, ext3, "already contains element")

	// services and methods
	mtd1 := NewMethod("foo", RpcTypeMessage(msg1, false), RpcTypeMessage(msg1, false))
	svc1 := NewService("FooService")
	svc1.AddMethod(mtd1)
	checkChildren(t, svc1, mtd1)
	testutil.Eq(t, svc1.GetMethod("foo"), mtd1)
	mtd2 := NewMethod("foo", RpcTypeMessage(msg1, false), RpcTypeMessage(msg1, false))
	err = svc1.TryAddMethod(mtd2)
	checkFailedAdd(t, err, svc1, mtd2, "already contains method")

	// finally, test adding things to  a file
	fb := NewFile("")
	fb.AddMessage(msg1)
	checkChildren(t, fb, msg1)
	testutil.Eq(t, fb.GetMessage("foo"), msg1)
	fb.AddService(svc1)
	checkChildren(t, fb, msg1, svc1)
	testutil.Eq(t, fb.GetService("FooService"), svc1)
	enum2 := NewEnum("fizzle")
	fb.AddEnum(enum2)
	checkChildren(t, fb, msg1, svc1, enum2)
	testutil.Eq(t, fb.GetEnum("fizzle"), enum2)
	ext3 = NewExtension("foosball", 123, FieldTypeInt32(), msg1)
	fb.AddExtension(ext3)
	checkChildren(t, fb, msg1, svc1, enum2, ext3)
	testutil.Eq(t, fb.GetExtension("foosball"), ext3)

	// errors and name collisions
	err = fb.TryAddExtension(fld3)
	checkFailedAdd(t, err, fb, fld3, "is not an extension")
	msg3 := NewMessage("fizzle")
	err = fb.TryAddMessage(msg3)
	checkFailedAdd(t, err, fb, msg3, "already contains element")
	enum3 := NewEnum("foosball")
	err = fb.TryAddEnum(enum3)
	checkFailedAdd(t, err, fb, enum3, "already contains element")

	// TODO: test moving and removing, too
}

func checkChildren(t *testing.T, parent Builder, children ...Builder) {
	testutil.Eq(t, len(children), len(parent.GetChildren()), "Wrong number of children for %s (%T)", GetFullyQualifiedName(parent), parent)
	ch := map[Builder]struct{}{}
	for _, child := range children {
		testutil.Eq(t, child.GetParent(), parent, "Child %s (%T) does not report %s (%T) as its parent", child.GetName(), child, GetFullyQualifiedName(parent), parent)
		ch[child] = struct{}{}
	}
	for _, child := range parent.GetChildren() {
		_, ok := ch[child]
		testutil.Require(t, ok, "Child %s (%T) does appear in list of children for %s (%T)", child.GetName(), child, GetFullyQualifiedName(parent), parent)
	}
}

func checkFailedAdd(t *testing.T, err error, parent Builder, child Builder, errorMsg string) {
	testutil.Require(t, err != nil, "Expecting error assigning %s (%T) to %s (%T)", child.GetName(), child, GetFullyQualifiedName(parent), parent)
	testutil.Require(t, strings.Contains(err.Error(), errorMsg), "Expecting error assigning %s (%T) to %s (%T) to contain text %q: %q", child.GetName(), child, GetFullyQualifiedName(parent), parent, errorMsg, err.Error())
	testutil.Eq(t, nil, child.GetParent(), "Child %s (%T) should not have a parent after failed add", child.GetName(), child)
	for _, ch := range parent.GetChildren() {
		testutil.Require(t, ch != child, "Child %s (%T) should not appear in list of children for %s (%T) but does", child.GetName(), child, GetFullyQualifiedName(parent), parent)
	}
}

func TestRenamingBuilders(t *testing.T) {
	// TODO
}

func TestRenumberingFields(t *testing.T) {
	// TODO
}

var (
	fileOptionsDesc, msgOptionsDesc, fieldOptionsDesc, oneofOptionsDesc, extRangeOptionsDesc,
	enumOptionsDesc, enumValOptionsDesc, svcOptionsDesc, mtdOptionsDesc *desc.MessageDescriptor
)

func init() {
	var err error
	fileOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.FileOptions)(nil))
	if err != nil {
		panic(err)
	}
	msgOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.MessageOptions)(nil))
	if err != nil {
		panic(err)
	}
	fieldOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.FieldOptions)(nil))
	if err != nil {
		panic(err)
	}
	oneofOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.OneofOptions)(nil))
	if err != nil {
		panic(err)
	}
	extRangeOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.ExtensionRangeOptions)(nil))
	if err != nil {
		panic(err)
	}
	enumOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.EnumOptions)(nil))
	if err != nil {
		panic(err)
	}
	enumValOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.EnumValueOptions)(nil))
	if err != nil {
		panic(err)
	}
	svcOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.ServiceOptions)(nil))
	if err != nil {
		panic(err)
	}
	mtdOptionsDesc, err = desc.LoadMessageDescriptorForMessage((*dpb.MethodOptions)(nil))
	if err != nil {
		panic(err)
	}
}

func TestCustomOptionsDiscoveredInSameFile(t *testing.T) {
	// Add option for every type to file
	file := NewFile("foo.proto")

	fileOpt := NewExtensionImported("file_foo", 54321, FieldTypeString(), fileOptionsDesc)
	file.AddExtension(fileOpt)

	msgOpt := NewExtensionImported("msg_foo", 54321, FieldTypeString(), msgOptionsDesc)
	file.AddExtension(msgOpt)

	fieldOpt := NewExtensionImported("field_foo", 54321, FieldTypeString(), fieldOptionsDesc)
	file.AddExtension(fieldOpt)

	oneofOpt := NewExtensionImported("oneof_foo", 54321, FieldTypeString(), oneofOptionsDesc)
	file.AddExtension(oneofOpt)

	extRangeOpt := NewExtensionImported("ext_range_foo", 54321, FieldTypeString(), extRangeOptionsDesc)
	file.AddExtension(extRangeOpt)

	enumOpt := NewExtensionImported("enum_foo", 54321, FieldTypeString(), enumOptionsDesc)
	file.AddExtension(enumOpt)

	enumValOpt := NewExtensionImported("enum_val_foo", 54321, FieldTypeString(), enumValOptionsDesc)
	file.AddExtension(enumValOpt)

	svcOpt := NewExtensionImported("svc_foo", 54321, FieldTypeString(), svcOptionsDesc)
	file.AddExtension(svcOpt)

	mtdOpt := NewExtensionImported("mtd_foo", 54321, FieldTypeString(), mtdOptionsDesc)
	file.AddExtension(mtdOpt)

	// Now we can test referring to these and making sure they show up correctly
	// in built descriptors

	t.Run("file options", func(t *testing.T) {
		fb := clone(t, file)
		fb.Options = &dpb.FileOptions{}
		ext, err := fileOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(fb.Options, ext, "fubar")
		testutil.Ok(t, err)
		checkBuildWithLocalExtensions(t, fb)
	})

	t.Run("message options", func(t *testing.T) {
		mb := NewMessage("Foo")
		mb.Options = &dpb.MessageOptions{}
		ext, err := msgOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(mb.Options, ext, "fubar")
		testutil.Ok(t, err)

		fb := clone(t, file)
		fb.AddMessage(mb)
		checkBuildWithLocalExtensions(t, mb)
	})

	t.Run("field options", func(t *testing.T) {
		flb := NewField("foo", FieldTypeString())
		flb.Options = &dpb.FieldOptions{}
		// fields must be connected to a message
		mb := NewMessage("Foo").AddField(flb)
		ext, err := fieldOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(flb.Options, ext, "fubar")
		testutil.Ok(t, err)

		fb := clone(t, file)
		fb.AddMessage(mb)
		checkBuildWithLocalExtensions(t, flb)
	})

	t.Run("oneof options", func(t *testing.T) {
		oob := NewOneOf("oo")
		oob.Options = &dpb.OneofOptions{}
		// oneofs must be connected to a message
		mb := NewMessage("Foo").AddOneOf(oob)
		ext, err := oneofOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(oob.Options, ext, "fubar")
		testutil.Ok(t, err)

		fb := clone(t, file)
		fb.AddMessage(mb)
		checkBuildWithLocalExtensions(t, oob)
	})

	t.Run("extension range options", func(t *testing.T) {
		var erOpts dpb.ExtensionRangeOptions
		ext, err := extRangeOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(&erOpts, ext, "fubar")
		testutil.Ok(t, err)
		mb := NewMessage("foo").AddExtensionRangeWithOptions(100, 200, &erOpts)

		fb := clone(t, file)
		fb.AddMessage(mb)
		checkBuildWithLocalExtensions(t, mb)
	})

	t.Run("enum options", func(t *testing.T) {
		eb := NewEnum("Foo")
		eb.Options = &dpb.EnumOptions{}
		ext, err := enumOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(eb.Options, ext, "fubar")
		testutil.Ok(t, err)

		fb := clone(t, file)
		fb.AddEnum(eb)
		checkBuildWithLocalExtensions(t, eb)
	})

	t.Run("enum val options", func(t *testing.T) {
		evb := NewEnumValue("FOO")
		// enum values must be connected to an enum
		eb := NewEnum("Foo").AddValue(evb)
		evb.Options = &dpb.EnumValueOptions{}
		ext, err := enumValOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(evb.Options, ext, "fubar")
		testutil.Ok(t, err)

		fb := clone(t, file)
		fb.AddEnum(eb)
		checkBuildWithLocalExtensions(t, evb)
	})

	t.Run("service options", func(t *testing.T) {
		sb := NewService("Foo")
		sb.Options = &dpb.ServiceOptions{}
		ext, err := svcOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(sb.Options, ext, "fubar")
		testutil.Ok(t, err)

		fb := clone(t, file)
		fb.AddService(sb)
		checkBuildWithLocalExtensions(t, sb)
	})

	t.Run("method options", func(t *testing.T) {
		req := NewMessage("Request")
		resp := NewMessage("Response")
		mtb := NewMethod("Foo",
			RpcTypeMessage(req, false),
			RpcTypeMessage(resp, false))
		// methods must be connected to a service
		sb := NewService("Bar").AddMethod(mtb)
		mtb.Options = &dpb.MethodOptions{}
		ext, err := mtdOpt.Build()
		testutil.Ok(t, err)
		err = dynamic.SetExtension(mtb.Options, ext, "fubar")
		testutil.Ok(t, err)

		fb := clone(t, file)
		fb.AddService(sb).AddMessage(req).AddMessage(resp)
		checkBuildWithLocalExtensions(t, mtb)
	})
}

func checkBuildWithLocalExtensions(t *testing.T, builder Builder) {
	// requiring options and succeeding (since they are defined locally)
	var opts BuilderOptions
	opts.RequireInterpretedOptions = true
	d, err := opts.Build(builder)
	testutil.Ok(t, err)
	// since they are defined locally, no extra imports
	testutil.Eq(t, []string{"google/protobuf/descriptor.proto"}, d.GetFile().AsFileDescriptorProto().GetDependency())
}

func TestCustomOptionsDiscoveredInDependencies(t *testing.T) {
	// Add option for every type to file
	file := NewFile("options.proto")

	fileOpt := NewExtensionImported("file_foo", 54321, FieldTypeString(), fileOptionsDesc)
	file.AddExtension(fileOpt)

	msgOpt := NewExtensionImported("msg_foo", 54321, FieldTypeString(), msgOptionsDesc)
	file.AddExtension(msgOpt)

	fieldOpt := NewExtensionImported("field_foo", 54321, FieldTypeString(), fieldOptionsDesc)
	file.AddExtension(fieldOpt)

	oneofOpt := NewExtensionImported("oneof_foo", 54321, FieldTypeString(), oneofOptionsDesc)
	file.AddExtension(oneofOpt)

	extRangeOpt := NewExtensionImported("ext_range_foo", 54321, FieldTypeString(), extRangeOptionsDesc)
	file.AddExtension(extRangeOpt)

	enumOpt := NewExtensionImported("enum_foo", 54321, FieldTypeString(), enumOptionsDesc)
	file.AddExtension(enumOpt)

	enumValOpt := NewExtensionImported("enum_val_foo", 54321, FieldTypeString(), enumValOptionsDesc)
	file.AddExtension(enumValOpt)

	svcOpt := NewExtensionImported("svc_foo", 54321, FieldTypeString(), svcOptionsDesc)
	file.AddExtension(svcOpt)

	mtdOpt := NewExtensionImported("mtd_foo", 54321, FieldTypeString(), mtdOptionsDesc)
	file.AddExtension(mtdOpt)

	fileDesc, err := file.Build()
	testutil.Ok(t, err)

	// Now we can test referring to these and making sure they show up correctly
	// in built descriptors
	for name, useBuilder := range map[string]bool{"descriptor": false, "builder": true} {
		newFile := func() *FileBuilder {
			fb := NewFile("foo.proto")
			if useBuilder {
				fb.AddDependency(file)
			} else {
				fb.AddImportedDependency(fileDesc)
			}
			return fb
		}
		t.Run(name, func(t *testing.T) {
			t.Run("file options", func(t *testing.T) {
				fb := newFile()
				fb.Options = &dpb.FileOptions{}
				ext, err := fileOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(fb.Options, ext, "fubar")
				testutil.Ok(t, err)
				checkBuildWithImportedExtensions(t, fb)
			})

			t.Run("message options", func(t *testing.T) {
				mb := NewMessage("Foo")
				mb.Options = &dpb.MessageOptions{}
				ext, err := msgOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(mb.Options, ext, "fubar")
				testutil.Ok(t, err)

				fb := newFile()
				fb.AddMessage(mb)
				checkBuildWithImportedExtensions(t, mb)
			})

			t.Run("field options", func(t *testing.T) {
				flb := NewField("foo", FieldTypeString())
				flb.Options = &dpb.FieldOptions{}
				// fields must be connected to a message
				mb := NewMessage("Foo").AddField(flb)
				ext, err := fieldOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(flb.Options, ext, "fubar")
				testutil.Ok(t, err)

				fb := newFile()
				fb.AddMessage(mb)
				checkBuildWithImportedExtensions(t, flb)
			})

			t.Run("oneof options", func(t *testing.T) {
				oob := NewOneOf("oo")
				oob.Options = &dpb.OneofOptions{}
				// oneofs must be connected to a message
				mb := NewMessage("Foo").AddOneOf(oob)
				ext, err := oneofOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(oob.Options, ext, "fubar")
				testutil.Ok(t, err)

				fb := newFile()
				fb.AddMessage(mb)
				checkBuildWithImportedExtensions(t, oob)
			})

			t.Run("extension range options", func(t *testing.T) {
				var erOpts dpb.ExtensionRangeOptions
				ext, err := extRangeOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(&erOpts, ext, "fubar")
				testutil.Ok(t, err)
				mb := NewMessage("foo").AddExtensionRangeWithOptions(100, 200, &erOpts)

				fb := newFile()
				fb.AddMessage(mb)
				checkBuildWithImportedExtensions(t, mb)
			})

			t.Run("enum options", func(t *testing.T) {
				eb := NewEnum("Foo")
				eb.Options = &dpb.EnumOptions{}
				ext, err := enumOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(eb.Options, ext, "fubar")
				testutil.Ok(t, err)

				fb := newFile()
				fb.AddEnum(eb)
				checkBuildWithImportedExtensions(t, eb)
			})

			t.Run("enum val options", func(t *testing.T) {
				evb := NewEnumValue("FOO")
				// enum values must be connected to an enum
				eb := NewEnum("Foo").AddValue(evb)
				evb.Options = &dpb.EnumValueOptions{}
				ext, err := enumValOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(evb.Options, ext, "fubar")
				testutil.Ok(t, err)

				fb := newFile()
				fb.AddEnum(eb)
				checkBuildWithImportedExtensions(t, evb)
			})

			t.Run("service options", func(t *testing.T) {
				sb := NewService("Foo")
				sb.Options = &dpb.ServiceOptions{}
				ext, err := svcOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(sb.Options, ext, "fubar")
				testutil.Ok(t, err)

				fb := newFile()
				fb.AddService(sb)
				checkBuildWithImportedExtensions(t, sb)
			})

			t.Run("method options", func(t *testing.T) {
				req := NewMessage("Request")
				resp := NewMessage("Response")
				mtb := NewMethod("Foo",
					RpcTypeMessage(req, false),
					RpcTypeMessage(resp, false))
				// methods must be connected to a service
				sb := NewService("Bar").AddMethod(mtb)
				mtb.Options = &dpb.MethodOptions{}
				ext, err := mtdOpt.Build()
				testutil.Ok(t, err)
				err = dynamic.SetExtension(mtb.Options, ext, "fubar")
				testutil.Ok(t, err)

				fb := newFile()
				fb.AddService(sb).AddMessage(req).AddMessage(resp)
				checkBuildWithImportedExtensions(t, mtb)
			})
		})
	}
}

func checkBuildWithImportedExtensions(t *testing.T, builder Builder) {
	// requiring options and succeeding (since they are defined in explicit import)
	var opts BuilderOptions
	opts.RequireInterpretedOptions = true
	d, err := opts.Build(builder)
	testutil.Ok(t, err)
	// the only import is for the custom options
	testutil.Eq(t, []string{"options.proto"}, d.GetFile().AsFileDescriptorProto().GetDependency())
}

func TestUseOfExtensionRegistry(t *testing.T) {
	// Add option for every type to extension registry
	var exts dynamic.ExtensionRegistry

	fileOpt, err := NewExtensionImported("file_foo", 54321, FieldTypeString(), fileOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(fileOpt)
	testutil.Ok(t, err)

	msgOpt, err := NewExtensionImported("msg_foo", 54321, FieldTypeString(), msgOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(msgOpt)
	testutil.Ok(t, err)

	fieldOpt, err := NewExtensionImported("field_foo", 54321, FieldTypeString(), fieldOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(fieldOpt)
	testutil.Ok(t, err)

	oneofOpt, err := NewExtensionImported("oneof_foo", 54321, FieldTypeString(), oneofOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(oneofOpt)
	testutil.Ok(t, err)

	extRangeOpt, err := NewExtensionImported("ext_range_foo", 54321, FieldTypeString(), extRangeOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(extRangeOpt)
	testutil.Ok(t, err)

	enumOpt, err := NewExtensionImported("enum_foo", 54321, FieldTypeString(), enumOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(enumOpt)
	testutil.Ok(t, err)

	enumValOpt, err := NewExtensionImported("enum_val_foo", 54321, FieldTypeString(), enumValOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(enumValOpt)
	testutil.Ok(t, err)

	svcOpt, err := NewExtensionImported("svc_foo", 54321, FieldTypeString(), svcOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(svcOpt)
	testutil.Ok(t, err)

	mtdOpt, err := NewExtensionImported("mtd_foo", 54321, FieldTypeString(), mtdOptionsDesc).Build()
	testutil.Ok(t, err)
	err = exts.AddExtension(mtdOpt)
	testutil.Ok(t, err)

	// Now we can test referring to these and making sure they show up correctly
	// in built descriptors

	t.Run("file options", func(t *testing.T) {
		fb := NewFile("foo.proto")
		fb.Options = &dpb.FileOptions{}
		err = dynamic.SetExtension(fb.Options, fileOpt, "fubar")
		testutil.Ok(t, err)
		checkBuildWithExtensions(t, &exts, fileOpt.GetFile(), fb)
	})

	t.Run("message options", func(t *testing.T) {
		mb := NewMessage("Foo")
		mb.Options = &dpb.MessageOptions{}
		err = dynamic.SetExtension(mb.Options, msgOpt, "fubar")
		testutil.Ok(t, err)
		checkBuildWithExtensions(t, &exts, msgOpt.GetFile(), mb)
	})

	t.Run("field options", func(t *testing.T) {
		flb := NewField("foo", FieldTypeString())
		flb.Options = &dpb.FieldOptions{}
		// fields must be connected to a message
		NewMessage("Foo").AddField(flb)
		err = dynamic.SetExtension(flb.Options, fieldOpt, "fubar")
		testutil.Ok(t, err)
		checkBuildWithExtensions(t, &exts, fieldOpt.GetFile(), flb)
	})

	t.Run("oneof options", func(t *testing.T) {
		oob := NewOneOf("oo")
		oob.Options = &dpb.OneofOptions{}
		// oneofs must be connected to a message
		NewMessage("Foo").AddOneOf(oob)
		err = dynamic.SetExtension(oob.Options, oneofOpt, "fubar")
		testutil.Ok(t, err)
		checkBuildWithExtensions(t, &exts, oneofOpt.GetFile(), oob)
	})

	t.Run("extension range options", func(t *testing.T) {
		var erOpts dpb.ExtensionRangeOptions
		err = dynamic.SetExtension(&erOpts, extRangeOpt, "fubar")
		testutil.Ok(t, err)
		mb := NewMessage("foo").AddExtensionRangeWithOptions(100, 200, &erOpts)
		checkBuildWithExtensions(t, &exts, extRangeOpt.GetFile(), mb)
	})

	t.Run("enum options", func(t *testing.T) {
		eb := NewEnum("Foo")
		eb.Options = &dpb.EnumOptions{}
		err = dynamic.SetExtension(eb.Options, enumOpt, "fubar")
		testutil.Ok(t, err)
		checkBuildWithExtensions(t, &exts, enumOpt.GetFile(), eb)
	})

	t.Run("enum val options", func(t *testing.T) {
		evb := NewEnumValue("FOO")
		// enum values must be connected to an enum
		NewEnum("Foo").AddValue(evb)
		evb.Options = &dpb.EnumValueOptions{}
		err = dynamic.SetExtension(evb.Options, enumValOpt, "fubar")
		testutil.Ok(t, err)
		checkBuildWithExtensions(t, &exts, enumValOpt.GetFile(), evb)
	})

	t.Run("service options", func(t *testing.T) {
		sb := NewService("Foo")
		sb.Options = &dpb.ServiceOptions{}
		err = dynamic.SetExtension(sb.Options, svcOpt, "fubar")
		testutil.Ok(t, err)
		checkBuildWithExtensions(t, &exts, svcOpt.GetFile(), sb)
	})

	t.Run("method options", func(t *testing.T) {
		mtb := NewMethod("Foo",
			RpcTypeMessage(NewMessage("Request"), false),
			RpcTypeMessage(NewMessage("Response"), false))
		// methods must be connected to a service
		NewService("Bar").AddMethod(mtb)
		mtb.Options = &dpb.MethodOptions{}
		err = dynamic.SetExtension(mtb.Options, mtdOpt, "fubar")
		testutil.Ok(t, err)
		checkBuildWithExtensions(t, &exts, mtdOpt.GetFile(), mtb)
	})
}

func checkBuildWithExtensions(t *testing.T, exts *dynamic.ExtensionRegistry, expected *desc.FileDescriptor, builder Builder) {
	// without interpreting custom option
	d, err := builder.BuildDescriptor()
	testutil.Ok(t, err)
	for _, dep := range d.GetFile().GetDependencies() {
		testutil.Neq(t, expected, dep)
	}
	numDeps := len(d.GetFile().GetDependencies())

	// requiring options (and failing)
	var opts BuilderOptions
	opts.RequireInterpretedOptions = true
	_, err = opts.Build(builder)
	testutil.Require(t, err != nil)

	// able to interpret options via extension registry
	opts.Extensions = exts
	d, err = opts.Build(builder)
	testutil.Ok(t, err)
	testutil.Eq(t, numDeps+1, len(d.GetFile().GetDependencies()))
	found := false
	for _, dep := range d.GetFile().GetDependencies() {
		if expected == dep {
			found = true
			break
		}
	}
	testutil.Require(t, found)
}

func TestRemoveField(t *testing.T) {
	msg := NewMessage("FancyMessage").
		AddField(NewField("one", FieldTypeInt64())).
		AddField(NewField("two", FieldTypeString())).
		AddField(NewField("three", FieldTypeString()))

	ok := msg.TryRemoveField("two")
	children := msg.GetChildren()

	testutil.Require(t, ok)
	testutil.Eq(t, 2, len(children))
	testutil.Eq(t, "one", children[0].GetName())
	testutil.Eq(t, "three", children[1].GetName())
}

func TestInterleavedFieldNumbers(t *testing.T) {
	msg := NewMessage("MessageWithInterleavedFieldNumbers").
		AddField(NewField("one", FieldTypeInt64()).SetNumber(1)).
		AddField(NewField("two", FieldTypeInt64())).
		AddField(NewField("three", FieldTypeString()).SetNumber(3)).
		AddField(NewField("four", FieldTypeInt64())).
		AddField(NewField("five", FieldTypeString()).SetNumber(5))

	md, err := msg.Build()
	testutil.Ok(t, err)

	testutil.Require(t, md.FindFieldByName("one") != nil)
	testutil.Eq(t, int32(1), md.FindFieldByName("one").GetNumber())

	testutil.Require(t, md.FindFieldByName("two") != nil)
	testutil.Eq(t, int32(2), md.FindFieldByName("two").GetNumber())

	testutil.Require(t, md.FindFieldByName("three") != nil)
	testutil.Eq(t, int32(3), md.FindFieldByName("three").GetNumber())

	testutil.Require(t, md.FindFieldByName("four") != nil)
	testutil.Eq(t, int32(4), md.FindFieldByName("four").GetNumber())

	testutil.Require(t, md.FindFieldByName("five") != nil)
	testutil.Eq(t, int32(5), md.FindFieldByName("five").GetNumber())
}

func clone(t *testing.T, fb *FileBuilder) *FileBuilder {
	fd, err := fb.Build()
	testutil.Ok(t, err)
	fb, err = FromFile(fd)
	testutil.Ok(t, err)
	return fb
}

func TestPruneDependencies(t *testing.T) {
	msgOpts := &dpb.MessageOptions{}
	msgOptsDesc, err := desc.LoadMessageDescriptorForMessage(msgOpts)
	testutil.Ok(t, err)
	extDesc, err := NewExtensionImported("foo", 20001, FieldTypeString(), msgOptsDesc).Build()
	testutil.Ok(t, err)

	dm := dynamic.NewMessage(msgOptsDesc)
	dm.SetField(extDesc, "bar")
	err = dm.ConvertTo(msgOpts)
	testutil.Ok(t, err)

	emptyDesc, err := desc.LoadMessageDescriptorForMessage(&empty.Empty{})
	testutil.Ok(t, err)

	// we have to explicitly import the file for the custom option
	fileB := NewFile("").AddImportedDependency(extDesc.GetFile())
	msgB := NewMessage("Foo").
		AddField(NewField("a", FieldTypeImportedMessage(emptyDesc))).
		SetOptions(msgOpts)
	fileDesc, err := fileB.AddMessage(msgB).Build()
	testutil.Ok(t, err)

	// The file for msgDesc should have two imports: one for the custom option and
	//   one for empty.proto.
	testutil.Eq(t, 2, len(fileDesc.GetDependencies()))
	testutil.Eq(t, "google/protobuf/empty.proto", fileDesc.GetDependencies()[0].GetName())
	testutil.Eq(t, extDesc.GetFile().GetName(), fileDesc.GetDependencies()[1].GetName())

	// If we now remove the message's field, both imports are still there even
	// though the import for empty.proto is now unused.
	fileB, err = FromFile(fileDesc)
	testutil.Ok(t, err)
	fileB.GetMessage("Foo").RemoveField("a")
	newFileDesc, err := fileB.Build()
	testutil.Ok(t, err)
	testutil.Eq(t, 2, len(newFileDesc.GetDependencies()))
	testutil.Eq(t, "google/protobuf/empty.proto", newFileDesc.GetDependencies()[0].GetName())
	testutil.Eq(t, extDesc.GetFile().GetName(), newFileDesc.GetDependencies()[1].GetName())

	// But if we prune unused dependencies, we'll see the import for empty.proto
	// gone. The other import for the custom option should be preserved.
	fileB, err = FromFile(fileDesc)
	testutil.Ok(t, err)
	fileB.GetMessage("Foo").RemoveField("a")
	newFileDesc, err = fileB.PruneUnusedDependencies().Build()
	testutil.Ok(t, err)
	testutil.Eq(t, 1, len(newFileDesc.GetDependencies()))
	testutil.Eq(t, extDesc.GetFile().GetName(), newFileDesc.GetDependencies()[0].GetName())
}


text:
package seedu.address.ui;

import java.util.Date;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.logging.Logger;

import com.google.common.eventbus.Subscribe;

import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SplitPane;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import seedu.address.commons.core.LogsCenter;
import seedu.address.commons.events.model.TaskManagerChangedEvent;
import seedu.address.commons.events.ui.LeftPanelTodaySelectionChangedEvent;
import seedu.address.commons.events.ui.ShowAllSelectionChangedEvent;
import seedu.address.commons.util.DateTimeUtil;
import seedu.address.commons.util.FxViewUtil;
import seedu.address.model.label.Label;
import seedu.address.model.task.ReadOnlyTask;

//@@author @A0140042A
/**
 *  Controller class for the LeftPanel of Ui
 */
public class LeftPanel extends UiPart<Region> {

    private final Logger logger = LogsCenter.getLogger(TaskListPanel.class);
    private static final String FXML = "LeftPanel.fxml";
    private HashMap<Label, Integer> labelCount;
    private ObservableList<ReadOnlyTask> taskList;
    private ObservableList<Label> labels;

    @FXML
    private javafx.scene.control.Label appTitleLabel;

    @FXML
    private javafx.scene.control.Label todayLabel;

    @FXML
    private javafx.scene.control.Label todayCounterLabel;

    @FXML
    private javafx.scene.control.Label showAllLabel;

    @FXML
    private javafx.scene.control.Label labelCounterLabel;

    @FXML
    private javafx.scene.control.Label labelTitleLabel;

    @FXML
    private FontAwesomeIconView todayIconLabel;

    @FXML
    private FontAwesomeIconView showAllIconLabel;

    @FXML
    private FontAwesomeIconView labelArrow;

    @FXML
    private FontAwesomeIconView labelIconLabel;

    @FXML
    private ListView<Label> labelListView;

    @FXML
    private HBox todayHeader;

    @FXML
    private HBox showAllHeader;

    public LeftPanel(AnchorPane leftListPlaceholder,
            ObservableList<ReadOnlyTask> taskList) {
        super(FXML);
        this.taskList = taskList;
        initIcons();
        updateLabelCount();
        setTodayListView(taskList);
        initializeShowAllLabel(taskList);
        addToPlaceholder(leftListPlaceholder);
        registerAsAnEventHandler(this);
    }

    /**
     * Updates the count in the LeftPanel labelList
     */
    public void updateLabelCount() {
        labelCount = new HashMap<Label, Integer>();

        for (ReadOnlyTask task : taskList) {
            for (Label label : task.getLabels()) {
                int currentCount = labelCount.get(label) == null ? 0 : labelCount.get(label);
                labelCount.put(label, currentCount + 1);
            }
        }

        setConnections(labelCount);
    }

    /**
     * Initializes the icons on the LeftPanel
     */
    private void initIcons() {
        todayIconLabel.setIcon(FontAwesomeIcon.CALENDAR_ALT);
        showAllIconLabel.setIcon(FontAwesomeIcon.LIST);
        labelIconLabel.setIcon(FontAwesomeIcon.HASHTAG);
        labelArrow.setIcon(FontAwesomeIcon.ANGLE_UP);
    }

    /**
     * Sets the counter beside the today button with tasks that start after today midnight
     */
    public void setTodayListView(ObservableList<ReadOnlyTask> taskList) {
        todayLabel.setText("Today");
        int count = 0;
        Date endTime = DateTimeUtil.getEndDate();
        Date startDate = DateTimeUtil.getStartDate();

        // Add all tasks that is not completed and deadline is after today
        for (ReadOnlyTask task : taskList) {
            if (!task.isCompleted() && task.getDeadline().isPresent() && task.getStartTime().isPresent()) {
                if ((task.getDeadline().get().getDateTime().before(endTime)
                        && task.getDeadline().get().getDateTime().after(startDate))
                        || task.getDeadline().get().getDateTime().equals(endTime)) {
                    count++;
                }
            } else if (!task.isCompleted() && task.getDeadline().isPresent() &&
                        (task.getDeadline().get().getDateTime().before(endTime)
                                || task.getDeadline().get().getDateTime().equals(endTime))) {
                count++;
            }
        }
        todayCounterLabel.setText(Integer.toString(count));
        setEventHandlerForTodaySelectionChangeEvent();
    }

    /**
     * Sets the showAll label as well as the event handler for it
     */
    public void initializeShowAllLabel(ObservableList<ReadOnlyTask> taskList) {
        showAllLabel.setText("Show All");
        setEventHandlerForCalendarSelectionChangeEvent();
    }

    /**
     * Sets the connections for the label list and the counter
     */
    public void setConnections(HashMap<Label, Integer> labelList) {
        labels = getLabelsWithCount(labelList);
        labelCounterLabel.setText(Integer.toString(labelList.size()));
        labelListView.setItems(labels);
        labelListView.setCellFactory(listView -> new LabelListViewCell());
    }

    /**
     * Returns labels with count more than 0, ignoring all empty labels
     */
    private ObservableList<Label> getLabelsWithCount(HashMap<Label, Integer> labelList) {
        labels = FXCollections.observableArrayList();
        for (Entry<Label, Integer> entry : labelList.entrySet()) {
            if (entry.getValue() > 0) {
                labels.add(entry.getKey());
            }
        }
        FXCollections.sort(labels);
        return labels;
    }

    /**
     * Sets the task list to the given task list
     */
    public void setTaskList(ObservableList<ReadOnlyTask> taskList) {
        this.taskList = taskList;
    }

    /**
     * Toggles the visibility of the labelList
     */
    @FXML
    private void toggleLabelList() {
        labelListView.setVisible(!labelListView.isVisible());
        if (labelListView.isVisible()) {
            labelArrow.setIcon(FontAwesomeIcon.ANGLE_UP);
        } else {
            labelArrow.setIcon(FontAwesomeIcon.ANGLE_DOWN);
        }
    }

    /**
     * Adds this item to the placeHolderPane
     */
    private void addToPlaceholder(AnchorPane placeHolderPane) {
        SplitPane.setResizableWithParent(placeHolderPane, false);
        FxViewUtil.applyAnchorBoundaryParameters(getRoot(), 0.0, 0.0, 0.0, 0.0);
        placeHolderPane.getChildren().add(getRoot());
    }

    /**
     * Creates an event handler to show all task that
     */
    private void setEventHandlerForTodaySelectionChangeEvent() {
        todayHeader.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                logger.fine("Selection in label left list panel changed to : 'Today'");
                raise(new LeftPanelTodaySelectionChangedEvent());
            }
        });
    }

    /**
     * Creates an event handler to show all the incomplete task on the task panel
     */
    private void setEventHandlerForCalendarSelectionChangeEvent() {
        showAllHeader.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                logger.fine("Clicked on show all menu");
                raise(new ShowAllSelectionChangedEvent());
            }
        });
    }

    /**
     * Scrolls to the index of the task
     */
    public void scrollTo(int index) {
        Platform.runLater(() -> {
            labelListView.scrollTo(index);
            labelListView.getSelectionModel().clearAndSelect(index);
        });
    }

    /**
     *  Updates the label counts and today counts when the task manager has been changed
     */
    @Subscribe
    public void handleTaskManagerChangedEvent(TaskManagerChangedEvent tmce) {
        updateLabelCount();
        setTodayListView(taskList);
        logger.info(LogsCenter.getEventHandlingLogMessage(tmce,
                "Updating label list count and total number of tasks for today"));
    }

    class LabelListViewCell extends ListCell<Label> {

        @Override
        protected void updateItem(Label label, boolean empty) {
            super.updateItem(label, empty);
            if (empty || label == null) {
                setGraphic(null);
                setText(null);
            } else {
                Integer newCount = labelCount.get(label);
                if (newCount == null) {
                    newCount = 1;
                }
                setGraphic(new LabelCard(label, newCount).getRoot());
            }
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
package com.github.twitch4j.eventsub.subscriptions;

import com.github.twitch4j.eventsub.condition.ChannelSubscriptionGiftCondition;
import com.github.twitch4j.eventsub.events.ChannelSubscriptionGiftEvent;

/**
 * The channel.subscription.gift subscription type sends a notification when a user gives one or more gifted subscriptions in a channel.
 * <p>
 * Must have channel:read:subscriptions scope.
 */
public class ChannelSubscriptionGiftType implements SubscriptionType<ChannelSubscriptionGiftCondition, ChannelSubscriptionGiftCondition.ChannelSubscriptionGiftConditionBuilder<?, ?>, ChannelSubscriptionGiftEvent> {

    @Override
    public String getName() {
        return "channel.subscription.gift";
    }

    @Override
    public String getVersion() {
        return "1";
    }

    @Override
    public ChannelSubscriptionGiftCondition.ChannelSubscriptionGiftConditionBuilder<?, ?> getConditionBuilder() {
        return ChannelSubscriptionGiftCondition.builder();
    }

    @Override
    public Class<ChannelSubscriptionGiftEvent> getEventClass() {
        return ChannelSubscriptionGiftEvent.class;
    }

}


text:
title: Quick Start
permalink: /docs/en/quick-start
key: docs-quick-start
---

TeXt Theme is 100% compatible with GitHub Pages and it has been developed as a [gem-based themes](https://jekyllrb.com/docs/themes/) for easier use.

In this document, you will learn how to **install the theme**, **setup your site**, **local preview** for development, **build** and **publish**.

```mermaid
graph LR;
    A0[Installing TeXt]
    B0[Common Method]
    B1[Ruby Gem Method]
    C0[Fork this repo]
    C1[Clone from GitHub]
    C2[Download]
    D0[Setup Your Site]
    E0[Installing Development Environment]
    F0[Installing Directly]
    F1[Docker]
    A0-->B0;
    A0-->B1;
    B0-->C0;
    B0-->C1;
    B0-->C2;
    B1-->D0;
    C1-->E0
    C2-->E0
    D0-->E0
    E0-->F0
    E0-->F1
```

## Installing the Theme

### Common Method

To install it with common method, all you need to do is copying all the theme files to your project. There are several ways to do so:

1. Clone [jekyll-TeXt-theme](https://github.com/kitian616/jekyll-TeXt-theme) from github.

   **Clone with HTTPS:**

   ```bash
   git clone https://github.com/kitian616/jekyll-TeXt-theme.git
   ```

   **Clone with SSH:**

   ```bash
   git clone git@github.com:kitian616/jekyll-TeXt-theme.git
   ```

2. Download and unzip the file to your Jekyll site directory.

    Download TeXt Theme

3. If you host your site on GitHub Pages, you can just fork [jekyll-TeXt-theme](https://github.com/kitian616/jekyll-TeXt-theme), then rename the repository to **USERNAME.github.io** — replacing **USERNAME** with your GitHub username.

   ![Fork](https://raw.githubusercontent.com/kitian616/jekyll-TeXt-theme/master/docs/assets/images/github-fork.jpg)

   ![Rename](https://raw.githubusercontent.com/kitian616/jekyll-TeXt-theme/master/docs/assets/images/github-rename-repo.jpg)

### Ruby Gem Method

1. Add this line to your Jekyll site's *Gemfile*:

   ```ruby
   gem "jekyll-text-theme"
   ```

2. Add this line to your Jekyll site's *_config.yml* file:

   ```yaml
   theme: jekyll-text-theme
   ```

## Setup Your Site

If you install the theme with common method, you can go straight to the next step. But **if you install the theme with ruby gem method, you have to do some extra jobs**.

With gem-based themes, some of the site's directories (such as the *assets*, *_layouts*, *_includes* and *_sass* directories) are stored in the theme's gem, hidden from your immediate view. You need add some files in your Jekyll site directory:

```bash
├── 404.html
├── Gemfile
├── _config.yml
├── _data
│   └── locale.yml
├── _posts
│   └── ...
├── about.md
├── archive.html
└── index.html
```

You can refer to the [/test folder](https://github.com/kitian616/jekyll-TeXt-theme/tree/master/test), this is a example with gem-based themes.

## Installing Development Environment

If you want to run them them locally, you need first install Ruby and Jekyll, see [Installation](https://jekyllrb.com/docs/installation/) for details.

After that, run bundler to install the dependencies:

```bash
bundle install --path vendor/bundle
```

And also, TeXt offer [Docker](https://www.docker.com/) support for development and public, this make it easier to setup environment.

![Docker](https://raw.githubusercontent.com/kitian616/jekyll-TeXt-theme/master/docs/assets/images/docker.jpg){:width="400px"}

All you need todo is these 3 steps:

1. [Install Docker](https://docs.docker.com/install/).

2. Generate *Gemfile.lock*:

   ```bash
   docker run --rm -v "$PWD":/usr/src/app -w /usr/src/app ruby:2.6 bundle install
   ```

3. Build Docker image:

   ```bash
   docker-compose -f ./docker/docker-compose.build-image.yml build
   ```

## Local Preview

Run `bundle exec jekyll serve` to start the development server, then you can visit [http://localhost:4000/](http://localhost:4000/) to preview your site.

For Docker, run `docker-compose -f ./docker/docker-compose.default.yml up` to start the development server.

## Build and Publish

If you host your site on GitHub Pages, just push the source to the master branch of your USERNAME.github.io repository, GitHub would build automatically. You can visit your site on **https://USERNAME.github.io** several minutes later.

If you host your site on your server, you need first run `JEKYLL_ENV=production bundle exec jekyll build` to generated your site, then update the files in *_site* folder to your server.


text:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml"
	schematypens="http://purl.oclc.org/dsdl/schematron"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0">
   <teiHeader>
      <fileDesc>
         <titleStmt>
            <title>Tierra Mia Coffee</title>
            <author>Gabriel Chan</author>
         </titleStmt>
         <publicationStmt>
            <publisher></publisher>
            <date when="2015">Winter 2016</date>
         </publicationStmt>
         <notesStmt>
            <relatedItem>
               <bibl>
                  <author></author>
               </bibl>
            </relatedItem>
         </notesStmt>
         <sourceDesc>
            <bibl/>
         </sourceDesc>
      </fileDesc>
   </teiHeader>

   <text>

Ulysses Romero founded Tierra Mia Coffee in 2008. The coffee shop specializes in Latino-inspired flavors. Their signature drink is their Horchata Latte. Unlike other specialty coffee businesses that established themselves in white middle to higher income neighborhoods, Romero wanted to serve the growing community of Latinos in LA. His stores have been strategically placed in lower and working class neighborhoods where there are also large numbers of Latinos. The stores serve as community gathering places for families and friends in traditionally underserved parts of LA. Recently, Romero launched his own foundation, "Tierra Mia Cares," which attempts to improve early childhood literacy with nearby schools. This business model is an example of the growing Latino middle class as a source of capital. Romero proves that it is possible to run both a successful and socially-conscious business within the socio-economically diverse Latino community in LA.

      <back>

         <note type="mapmarker">
            <placeName type="Gabriel Chan">Huntington Park</placeName>
            <geo>-118.2249218 33.9785049</geo>

Tierra Mia Coffee's success is evidence of the growing purchasing power of Latinos. The stores also act as community gathering places.

         </note>

            <listBibl>
               <bibl>Silva, Valentina. "Bringing It All Back Home: The Rise of the Latino Coffeehouse in Los Angeles." The Guardian. Guardian News and Media, 25 Jan. 2016. Web. 24 Feb. 2016.</bibl>
               <bibl>Wolfson, Julie. "A Coffee Crawl With Tierra Mia's Ulysses Romero." Sprudge. Sprudge Media Network, 11 Dec. 2015. Web. 24 Feb. 2016.</bibl>
               <bibl>Citation 3...</bibl>
            </listBibl>

               <graphic url="boxlink.jpg"/>

               <note type="attribution">CREATOR, DATE. IMAGE COURTESY OF . . . </note>
               <figDesc></figDesc>

      </back>
   </text>
</TEI>


text:
/**
 *    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 org.cdlflex.ui.util.convert.date;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;

/**
 * This does not test the java <-> momentjs date format token mapping, only the basic functionality.
 */
public class MomentJsDateFormatConverterTest {
    DateFormatConverter converter;

    @Before
    public void setUp() throws Exception {
        converter = new MomentJsDateFormatConverter();
    }

    @Test
    public void convert_convertsCorrectly() throws Exception {
        // 1999-01-23 19:03
        assertEquals("YYYY-MM-DD HH:mm", converter.convert("y-MM-dd HH:mm"));
    }

    @Test
    public void convert_escapedString() throws Exception {
        assertEquals("YYYY [escaped] YYYY", converter.convert("y 'escaped' yyyy"));
    }

    @Test(expected = UnsupportedOperationException.class)
    public void convert_unknownToken_throwsException() throws Exception {
        converter.convert("F");
    }

}


text:
<?php
namespace Inventory\Domain\Service\Search;

use Application\Application\Service\Search\Contracts\QueryFilterInterface;

/**
 * Purchase Order Search
 *
 * @author Nguyen Mau Tri - ngmautri@gmail.com
 *
 */
Interface ItemSearchQueryInterface
{

    public function search($q, QueryFilterInterface $filter = null);

    public function queryForAutoCompletion($q, QueryFilterInterface $filter, $maxHit = 10, $returnDetail = true);
}


text:
require 'spec_helper'

module CancanUnitTest
  describe StubFinder do
    let_double(:controller)
    let_double(:method)
    let_double(:resource)
    let_double(:options)
    let_double(:block)

    let(:finder) { StubFinder.new(controller, method) }

    describe "#find_by_singleton" do
      subject { finder.find_by_singleton(resource, options) }

      before do
        controller.
          stub(:_get_cancan_unit_test_stubs).
          with(method).
          and_return(results)
      end

      context "the controller has no stubs" do
        let(:results) { [] }
        it { should be_nil }
      end

      context "the controller has a stub for the method" do
        context "with no matching resource" do
          let(:results) { [{ resource_type: :singleton, resource: double(:other_resource), options: options, block: block }] }
          it { should be_nil }
        end

        context "with no matching options" do
          let(:results) { [{ resource_type: :singleton, resource: resource, options: double(:other_options), block: block }] }
          it { should be_nil }
        end

        context "with matching resource and options" do
          let(:results) { [{ resource_type: :singleton, resource: resource, options: options, block: block }] }
          it { should == block }
        end
      end

      context "the controller has more than one matching stub" do
        context "with a different resource type" do
          let(:results) do
            [
              { resource_type: :collection, resource: resource, options: options, block: -> {} },
              { resource_type: :singleton, resource: resource, options: options, block: block }
            ]
          end

          it { should == block }
        end

        context "with the same resource type" do
          let(:results) do
            [
              { resource_type: :singleton, resource: resource, options: options, block: block },
              { resource_type: :singleton, resource: resource, options: options, block: block }
            ]
          end

          it "raises an exception" do
            expect { finder.find_by_singleton(resource, options) }.to raise_error
          end
        end
      end

    end

    describe "#find_by_collection" do
      subject { finder.find_by_collection(resource, options) }

      before do
        controller.
          stub(:_get_cancan_unit_test_stubs).
          with(method).
          and_return(results)
      end

      context "with a different resource type" do
        let(:results) do
          [
            { resource_type: :singleton, resource: resource, options: options, block: -> {} },
            { resource_type: :collection, resource: resource, options: options, block: block }
          ]
        end

        it { should == block }
      end
    end

  end
end


text:
if (this.importScripts) {
    importScripts('../../../fast/js/resources/js-test-pre.js');
    importScripts('shared.js');
}

description("Test IndexedDB's IDBCursor.continue() with a primary key parameter.");

indexedDBTest(prepareDatabase, verifyContinueCalls);
function prepareDatabase(evt)
{
    preamble(evt);

    evalAndLog("db = event.target.result");
    evalAndLog("store = db.createObjectStore('store')");
    evalAndLog("index = store.createIndex('index', 'indexKey', {multiEntry: true})");

    evalAndLog("store.put({indexKey: ['a', 'b']}, 1)");
    evalAndLog("store.put({indexKey: ['a', 'b']}, 2)");
    evalAndLog("store.put({indexKey: ['a', 'b']}, 3)");
    evalAndLog("store.put({indexKey: ['b']}, 4)");

    var indexExpected = [
        {key: "a", primaryKey: 1},
        {key: "a", primaryKey: 2},
        {key: "a", primaryKey: 3},
        {key: "b", primaryKey: 1},
        {key: "b", primaryKey: 2},
        {key: "b", primaryKey: 3},
        {key: "b", primaryKey: 4}
    ];
    debug("checking index structure...");
    debug("");
    debug("index key  primary key");
    debug("=========  ===========");
    var quiet = true;
    evalAndLog("request = index.openCursor()", quiet);
    request.onerror = unexpectedErrorCallback;
    request.onsuccess = function onCursorSuccess() {
        evalAndLog("cursor = request.result", quiet);
        var expectedEntry = indexExpected.shift();
        if (expectedEntry) {
            shouldBe("cursor.key", JSON.stringify(expectedEntry.key), quiet);
            shouldBe("cursor.primaryKey", JSON.stringify(expectedEntry.primaryKey), quiet);
            debug(cursor.key + "          " + cursor.primaryKey);
            evalAndLog("cursor.continue()", quiet);
        } else {
            shouldBeNull("cursor", quiet);
        }
    };
}

var testCases = [
    // Continuing index key
    { call: "cursor.continue()", result: { key: "a", primaryKey: 2 } },
    { call: "cursor.continue('a')", exception: 'DataError' },
    { call: "cursor.continue('b')", result: { key: "b", primaryKey: 1 } },
    { call: "cursor.continue('c')", result: null },

    // Called w/ index key and primary key:
    { call: "cursor.continuePrimaryKey('a', 3)", result: {key: 'a', primaryKey: 3} },
    { call: "cursor.continuePrimaryKey('a', 4)", result: {key: 'b', primaryKey: 1} },
    { call: "cursor.continuePrimaryKey('b', 1)", result: {key: 'b', primaryKey: 1} },
    { call: "cursor.continuePrimaryKey('b', 4)", result: {key: 'b', primaryKey: 4} },
    { call: "cursor.continuePrimaryKey('b', 5)", result: null },
    { call: "cursor.continuePrimaryKey('c', 1)", result: null },

    // Called w/ primary key but w/o index key
    { call: "cursor.continuePrimaryKey(null, 1)", exception: 'DataError' },
    { call: "cursor.continuePrimaryKey(null, 2)", exception: 'DataError' },
    { call: "cursor.continuePrimaryKey(null, 3)", exception: 'DataError' },
    { call: "cursor.continuePrimaryKey(null, 4)", exception: 'DataError' },
    { call: "cursor.continuePrimaryKey(null, 5)", exception: 'DataError' },

    // Called w/ index key but w/o primary key
    { call: "cursor.continuePrimaryKey('a', null)", exception: 'DataError' },
 ];

function verifyContinueCalls() {
    debug("");
    if (!testCases.length) {
        finishJSTest();
        return;
    }

    var quiet = true;
    testCase = testCases.shift();
    debug("Test case: " + testCase.call);
    debug("");
    evalAndLog("tx = db.transaction('store')");
    evalAndLog("request = tx.objectStore('store').index('index').openCursor()");
    var i = 0;
    request.onsuccess = function() {
        ++i;
        evalAndLog("cursor = request.result", true);
        if (i === 1) {
            if ('exception' in testCase) {
                evalAndExpectException(testCase.call, "0", "'DataError'");
            } else {
                evalAndLog(testCase.call);
            }
            return;
        }

        if (i === 2) {
            if (testCase.result) {
                shouldBe("cursor.key", JSON.stringify(testCase.result.key));
                shouldBe("cursor.primaryKey", JSON.stringify(testCase.result.primaryKey));
            } else {
                shouldBeNull("cursor");
            }
        }
    };

    tx.oncomplete = verifyContinueCalls;
}


text:
require('pp')
require('optparse')
require('simple_twitter')

class InterfaceUser
  def initialize
    @searcher = SimpleTwitter::Search.new

    OptionParser.new do |parser|
      parser.banner = "Usage: simple-twitter [options] search-query"

      parser.on('-h', '--help', 'This message') do
        $stdout.puts(parser)
        exit
      end

      parser.on('-r', '--results-per-page=COUNT', 'Return COUNT tweets') do |rpp|
        @searcher.results_per_page = rpp.to_i
      end
    end.parse!(ARGV)
  end
    if ARGV.empty?
      $stderr.puts("Please put what you want to search in your command
      line")
      exit(1)
    end

    ARGV.each do |query|
      pp(@searcher.search(query))
    end
  end

################################################################################
UserInterface.new.run


text:
var class2type = {
	'[object Boolean]': 'boolean',
	'[object Number]': 'number',
	'[object String]': 'string',
	'[object Function]': 'function',
	'[object Array]': 'array',
	'[object Date]': 'date',
	'[object RegExp]': 'regexp',
	'[object Object]': 'object'
};

jQuery = {
	type: function( obj ) {
		return obj == null ?
			String( obj ) :
			class2type[ toString.call(obj) ] || "object";
	},

	isFunction: function( obj ) {
		return jQuery.type(obj) === "function";
	},

	extend: function(target, options) {
		var options, name, src, copy,
			target = target || {},
			i = 1,
			options = options || {};

		// Extend the base object
		for ( name in options ) {
			src = target[ name ];
			copy = options[ name ];

			// Prevent never-ending loop
			if ( target === copy ) {
				continue;
			}

			// Don't bring in undefined values
			if ( copy !== undefined ) {
				target[ name ] = copy;
			}
		}

		// Return the modified object
		return target;
	}
};

module.exports = jQuery;


text:
package com.fuzz.indicator;

import android.graphics.drawable.ColorDrawable;
import android.support.annotation.NonNull;

/**
 * Extension of {@link ColorDrawable} with positive width and height.
 *
 * @author Philip Cohn-Cort (Fuzz)
 * @see #setIntrinsicHeight(int)
 * @see #setIntrinsicWidth(int)
 */
public class ResizeableColorDrawable extends ColorDrawable {
    private int intrinsicHeight = 1;
    private int intrinsicWidth = 1;

    /**
     * See the {@link ResizeableColorDrawable class javadoc}.
     *
     * @param drawable    use this to provide a preferred color
     */
    public ResizeableColorDrawable(@NonNull ColorDrawable drawable) {
        super(drawable.getColor());
    }

    @Override
    public int getIntrinsicHeight() {
        return intrinsicHeight;
    }

    @Override
    public int getIntrinsicWidth() {
        return intrinsicWidth;
    }

    public void setIntrinsicHeight(int intrinsicHeight) {
        this.intrinsicHeight = intrinsicHeight;
    }

    public void setIntrinsicWidth(int intrinsicWidth) {
        this.intrinsicWidth = intrinsicWidth;
    }
}


text:
namespace Google.Cloud.StorageTransfer.V1.Snippets
{
    // [START storagetransfer_v1_generated_StorageTransferService_GetGoogleServiceAccount_sync]
    using Google.Cloud.StorageTransfer.V1;

    public sealed partial class GeneratedStorageTransferServiceClientSnippets
    {
        /// <summary>Snippet for GetGoogleServiceAccount</summary>
        /// <remarks>
        /// This snippet has been automatically generated for illustrative purposes only.
        /// It may require modifications to work in your environment.
        /// </remarks>
        public void GetGoogleServiceAccountRequestObject()
        {
            // Create client
            StorageTransferServiceClient storageTransferServiceClient = StorageTransferServiceClient.Create();
            // Initialize request argument(s)
            GetGoogleServiceAccountRequest request = new GetGoogleServiceAccountRequest { ProjectId = "", };
            // Make the request
            GoogleServiceAccount response = storageTransferServiceClient.GetGoogleServiceAccount(request);
        }
    }
    // [END storagetransfer_v1_generated_StorageTransferService_GetGoogleServiceAccount_sync]
}


text:
package com.cookpad.puree.outputs;

import com.google.gson.JsonObject;

import com.cookpad.puree.PureeFilter;

import org.json.JSONException;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicReference;

import javax.annotation.Nonnull;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

public class PureeOutputTest {
    @Test
    public void discardLog() {
        final PureeOutput output = new PureeOutput() {
            @Override
            public void emit(JsonObject jsonLog) {
                // because first filter discards log.
                fail("log should be discarded by first filter");
            }

            @Nonnull
            @Override
            public OutputConfiguration configure(OutputConfiguration conf) {
                return conf;
            }

            @Nonnull
            @Override
            public String type() {
                return "output";
            }
        };
        output.registerFilter(new PureeFilter() {
            @Override
            public JsonObject apply(JsonObject jsonLog) {
                // discard log
                return null;
            }
        });
        output.registerFilter(new PureeFilter() {
            @Override
            public JsonObject apply(JsonObject jsonLog) {
                jsonLog.addProperty("event_time", System.currentTimeMillis());
                return jsonLog;
            }
        });

        output.receive(new JsonObject());
    }

    @Test
    public void testFilter_multipleModifications() throws JSONException {

        final AtomicReference<JsonObject> result = new AtomicReference<>();

        final PureeOutput output = new PureeOutput() {
            @Override
            public void emit(JsonObject jsonLog) {
                result.set(jsonLog);
            }

            @Nonnull
            @Override
            public OutputConfiguration configure(OutputConfiguration conf) {
                return conf;
            }

            @Nonnull
            @Override
            public String type() {
                return "output";
            }
        };
        output.registerFilter(new PureeFilter() {
            @Override
            public JsonObject apply(JsonObject jsonLog) {
                JsonObject jsonObject = new JsonObject();
                jsonObject.addProperty("filter1", "foo");
                return jsonObject;
            }
        });
        output.registerFilter(new PureeFilter() {
            @Override
            public JsonObject apply(JsonObject jsonLog) {
                final JsonObject jsonObject = new JsonObject();
                if (jsonLog.has("filter1")) {
                    jsonObject.addProperty("filter1", jsonLog.get("filter1").getAsString());
                }
                jsonLog.addProperty("filter2", "bar");
                return jsonLog;
            }
        });

        output.receive(new JsonObject());

        final JsonObject resultObject = result.get();
        assertThat(resultObject.has("filter1"), is(true));
        assertThat(resultObject.get("filter1").getAsString(), is("foo"));
        assertThat(resultObject.has("filter2"), is(true));
        assertThat(resultObject.get("filter2").getAsString(), is("bar"));
    }
}


text:
"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = Prefix;

var _react = _interopRequireDefault(require("react"));

var _ = require("../..");

function Prefix() {
  return _react["default"].createElement(_.ChipButton, {
    prefix: "role"
  }, "admin");
}
//# sourceMappingURL=Prefix.js.map


text:
package org.income.expense.data.entity;

import lombok.Getter;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import java.util.HashSet;
import java.util.Set;

@Entity(name = "CATEGORY_EXPRESSION")
public class CategoryExpression extends IEEntity {

    @Column(name = "CATEGORY_NAME")
    private String categoryName;

    @Column(name = "SUBCATEGORY_ONE")
    private String subCategoryOne;

    @Column(name = "SUBCATEGORY_TWO")
    private String subCategoryTwo;

    @Column(name = "EXPRESSION")
    private String expression;

    @OneToMany(mappedBy = "category")
    @Getter
    private Set<Activity> activity = new HashSet<Activity>();

}


text:
<?php namespace houdunwang\response;

//请求处理
use houdunwang\response\build\Base;

class Response
{
    protected $link;

    protected function driver()
    {
        $this->link = new Base();

        return $this;
    }

    public function __call($method, $params)
    {
        if (is_null($this->link)) {
            $this->driver();
        }

        return call_user_func_array([$this->link, $method], $params);
    }

    public static function single()
    {
        static $link;
        if (is_null($link)) {
            $link = new static();
        }

        return $link;
    }

    public static function __callStatic($name, $arguments)
    {
        return call_user_func_array([static::single(), $name], $arguments);
    }
}


text:
${library.name}

  <% print library.url.isEmpty() ? "" : """
${library.url}
""" %>

${library.copyrightStatement}

      Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
      following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following
        disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
        disclaimer in the documentation and/or other materials provided with the distribution.

      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
      INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


text:
@interface NSDate (LJExtension)

- (NSDateComponents *)compareTimeFrom : (NSDate *)from;

- (BOOL)isThisYear;
- (BOOL)isThisDay;
- (BOOL)isYesterDay;
@end


text:
<?php

namespace CmsDoctrineORM\Mapping\Translatable\Repository;

use Doctrine\ORM\AbstractQuery,
    Doctrine\ORM\Query,
    Doctrine\ORM\QueryBuilder,
    Gedmo\Translatable\Query\TreeWalker\TranslationWalker,
    CmsDoctrine\Mapping\Translatable\TranslatableSubscriber;

/**
 * @author Dmitry Popov <d.popov@altgraphic.com>
 */
trait TranslatableRepositoryTrait
{
    /**
     * @var string Locale
     */
    protected $translatableLocale;

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function findQuery($id, $locale = null)
    {
        $qb = $this->findQueryBuilder($id);
        return $this->getTranslatableQuery($qb, $locale);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getFindQuery($id, $locale = null)
    {
        return $this->findQuery($id, $locale);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function find($id, $hydrationMode = AbstractQuery::HYDRATE_OBJECT, $locale = null)
    {
        return $this->findQuery($id, $locale)->getOneOrNullResult($hydrationMode);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function findOneByQuery(array $criteria, array $orderBy = null, $locale = null)
    {
        $qb = $this->getFindOneByQueryBuilder($criteria, $orderBy);
        return $this->getTranslatableQuery($qb, $locale);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getFindOneByQuery(array $criteria, array $orderBy = null, $locale = null)
    {
        return $this->findOneByQuery($criteria, $orderBy, $locale);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function findOneBy(array $criteria, array $orderBy = null,
            $hydrationMode = AbstractQuery::HYDRATE_OBJECT, $locale = null)
    {
        return $this->findOneByQuery($criteria, $orderBy, $locale)->getOneOrNullResult($hydrationMode);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function findByQuery(array $criteria, array $orderBy = null, $limit = null, $offset = null, $locale = null)
    {
        $qb = $this->findByQueryBuilder($criteria, $orderBy, $limit, $offset);
        return $this->getTranslatableQuery($qb, $locale);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getFindByQuery(array $criteria, array $orderBy = null, $limit = null, $offset = null, $locale = null)
    {
        return $this->findByQuery($criteria, $orderBy, $limit, $offset, $locale);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function findBy(array $criteria, array $orderBy = null, $limit = null,
            $offset = null, $hydrationMode = AbstractQuery::HYDRATE_OBJECT, $locale = null)
    {
        return $this->findByQuery($criteria, $orderBy, $limit, $offset, $locale)->getResult($hydrationMode);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function findAllQuery($locale = null)
    {
        $qb = $this->getFindAllQueryBuilder();
        return $this->getTranslatableQuery($qb, $locale);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getFindAllQuery($locale = null)
    {
        return $this->findAllQuery($locale);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function findAll($hydrationMode = AbstractQuery::HYDRATE_OBJECT, $locale = null)
    {
        return $this->findAllQuery($locale)->getResult($hydrationMode);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getOneOrNullResult(QueryBuilder $qb, $hydrationMode = null, $locale = null)
    {
        return $this->getTranslatableQuery($qb, $locale)->getOneOrNullResult($hydrationMode);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getResult(QueryBuilder $qb, $hydrationMode = AbstractQuery::HYDRATE_OBJECT, $locale = null)
    {
        return $this->getTranslatableQuery($qb, $locale)->getResult($hydrationMode);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getArrayResult(QueryBuilder $qb, $locale = null)
    {
        return $this->getTranslatableQuery($qb, $locale)->getArrayResult();
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getSingleResult(QueryBuilder $qb, $hydrationMode = null, $locale = null)
    {
        return $this->getTranslatableQuery($qb, $locale)->getSingleResult($hydrationMode);
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getScalarResult(QueryBuilder $qb, $locale = null)
    {
        return $this->getTranslatableQuery($qb, $locale)->getScalarResult();
    }

    /**
     * {@inheritDoc}
     *
     * @param string|null   $locale A locale name
     */
    public function getSingleScalarResult(QueryBuilder $qb, $locale = null)
    {
        return $this->getTranslatableQuery($qb, $locale)->getSingleScalarResult();
    }

    /**
     * @param string $locale
     */
    public function setTranslatableLocale($locale)
    {
        $this->translatableLocale = $locale;
    }

    /**
     * @return string
     */
    public function getTranslatableLocale()
    {
        if (null === $this->translatableLocale) {
            return \Locale::getDefault();
        }

        return $this->translatableLocale;
    }

    /**
     * Returns translated Doctrine query instance
     *
     * @param QueryBuilder $qb     A Doctrine query builder instance
     * @param string       $locale A locale name
     * @return AbstractQuery
     */
    public function getTranslatableQuery(QueryBuilder $qb, $locale = null)
    {
        $query  = $qb->getQuery();
        $locale = $locale ?: $this->getTranslatableLocale();

        if ($locale) {
            // Use Translation Walker
            $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class)
            // Force the locale
                ->setHint(TranslatableSubscriber::HINT_TRANSLATABLE_LOCALE, $locale);
        }

        return $query;
    }
}


text:
var appData = require('../data/appData.json');
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', appData);
});

module.exports = router;