From 66379b9074b31ccbc59e14268e2019ff7ca0b996 Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Fri, 20 Sep 2024 14:41:58 +0900 Subject: [PATCH 01/10] =?UTF-8?q?=E2=9C=A8=20impl=20strings=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grpc/federation/cel/strings.go | 401 +++++++++++++++++++++++++++++++++ 1 file changed, 401 insertions(+) create mode 100644 grpc/federation/cel/strings.go diff --git a/grpc/federation/cel/strings.go b/grpc/federation/cel/strings.go new file mode 100644 index 00000000..f9a5f30f --- /dev/null +++ b/grpc/federation/cel/strings.go @@ -0,0 +1,401 @@ +package cel + +import ( + "context" + "github.com/google/cel-go/cel" + "github.com/google/cel-go/common/types" + "github.com/google/cel-go/common/types/ref" + "github.com/google/cel-go/common/types/traits" + "strings" +) + +const StringsPackageName = "strings" + +var _ cel.SingletonLibrary = new(StringsLibrary) + +type StringsLibrary struct { + typeAdapter types.Adapter +} + +func NewStringsLibrary(typeAdapter types.Adapter) *StringsLibrary { + return &StringsLibrary{ + typeAdapter: typeAdapter, + } +} + +func (lib *StringsLibrary) LibraryName() string { + return packageName(StringsPackageName) +} + +func createStringsName(name string) string { + return createName(StringsPackageName, name) +} + +func createStringsID(name string) string { + return createID(StringsPackageName, name) +} + +func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { + opts := []cel.EnvOption{} + + for _, funcOpts := range [][]cel.EnvOption{ + BindFunction( + createStringsName("clone"), + OverloadFunc(createStringsID("clone_string_string"), []*cel.Type{cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return args[0].(types.String) + }, + ), + ), + BindFunction( + createStringsName("compare"), + OverloadFunc(createStringsID("compare_string_string_int"), []*cel.Type{cel.StringType, cel.StringType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return args[0].(types.String).Compare(args[1].(types.String)) + }, + ), + ), + BindFunction( + createStringsName("contains"), + OverloadFunc(createStringsID("contains_string_string_bool"), []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Bool(strings.Contains(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("containsAny"), + OverloadFunc(createStringsID("containsAny_string_string_bool"), []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Bool(strings.ContainsAny(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("containsRune"), + OverloadFunc(createStringsID("containsRune_string_int_bool"), []*cel.Type{cel.StringType, cel.IntType}, cel.BoolType, + func(_ context.Context, args ...ref.Val) ref.Val { + str := args[0].(types.String).Value().(string) + r := rune(args[1].(types.Int).Value().(int64)) + return types.Bool(strings.ContainsRune(str, r)) + }, + ), + ), + BindFunction( + createStringsName("count"), + OverloadFunc(createStringsID("count_string_string_int"), []*cel.Type{cel.StringType, cel.StringType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.Count(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + // func Cut(s, sep string) (before, after string, found bool) + BindFunction( + createStringsName("cutPrefix"), + OverloadFunc(createStringsID("cutPrefix_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + str := args[0].(types.String).Value().(string) + prefix := args[1].(types.String).Value().(string) + after, found := strings.CutPrefix(str, prefix) + if found { + return types.String(after) + } + return types.String(str) + }, + ), + ), + BindFunction( + createStringsName("cutSuffix"), + OverloadFunc(createStringsID("cutSuffix_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + str := args[0].(types.String).Value().(string) + suffix := args[1].(types.String).Value().(string) + before, found := strings.CutSuffix(str, suffix) + if found { + return types.String(before) + } + return types.String(str) + }, + ), + ), + BindFunction( + createStringsName("equalFold"), + OverloadFunc(createStringsID("equalFold_string_string_bool"), []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Bool(strings.EqualFold(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("fields"), + OverloadFunc(createStringsID("fields_string_strings"), []*cel.Type{cel.StringType}, cel.ListType(cel.StringType), + func(_ context.Context, args ...ref.Val) ref.Val { + adapter := types.DefaultTypeAdapter + return types.NewStringList(adapter, strings.Fields(args[0].(types.String).Value().(string))) + }, + ), + ), + // func FieldsFunc(s string, f func(rune) bool) []string + BindFunction( + createStringsName("hasPrefix"), + OverloadFunc(createStringsID("hasPrefix_string_string_bool"), []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Bool(strings.HasPrefix(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("hasSuffix"), + OverloadFunc(createStringsID("hasSuffix_string_string_bool"), []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Bool(strings.HasSuffix(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("index"), + OverloadFunc(createStringsID("index_string_string_int"), []*cel.Type{cel.StringType, cel.StringType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.Index(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("indexAny"), + OverloadFunc(createStringsID("indexAny_string_string_int"), []*cel.Type{cel.StringType, cel.StringType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.IndexAny(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("indexByte"), + OverloadFunc(createStringsID("indexByte_string_byte_int"), []*cel.Type{cel.StringType, cel.BytesType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.IndexByte(args[0].(types.String).Value().(string), args[1].(types.Bytes).Value().(byte))) + }, + ), + OverloadFunc(createStringsID("indexByte_string_string_int"), []*cel.Type{cel.StringType, cel.StringType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.IndexByte(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string)[0])) + }, + ), + ), + // func IndexFunc(s string, f func(rune) bool) int + BindFunction( + createStringsName("indexRune"), + OverloadFunc(createStringsID("indexRune_string_int_int"), []*cel.Type{cel.StringType, cel.IntType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.IndexRune(args[0].(types.String).Value().(string), rune(args[1].(types.Int).Value().(int64)))) + }, + ), + ), + BindFunction( + createStringsName("join"), + OverloadFunc(createStringsID("join_strings_string_string"), []*cel.Type{cel.ListType(cel.StringType), cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + elems := args[0].(traits.Lister) + strs := make([]string, elems.Size().(types.Int)) + for i := types.IntZero; i < elems.Size().(types.Int); i++ { + strs[i] = elems.Get(i).(types.String).Value().(string) + } + return types.String(strings.Join(strs, args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("lastIndex"), + OverloadFunc(createStringsID("lastIndex_string_string_int"), []*cel.Type{cel.StringType, cel.StringType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.LastIndex(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("lastIndexAny"), + OverloadFunc(createStringsID("lastIndexAny_string_string_int"), []*cel.Type{cel.StringType, cel.StringType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.LastIndexAny(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("lastIndexByte"), + OverloadFunc(createStringsID("lastIndexByte_string_byte_int"), []*cel.Type{cel.StringType, cel.BytesType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.LastIndexByte(args[0].(types.String).Value().(string), args[1].(types.Bytes).Value().(byte))) + }, + ), + OverloadFunc(createStringsID("lastIndexByte_string_string_int"), []*cel.Type{cel.StringType, cel.StringType}, cel.IntType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.Int(strings.LastIndexByte(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string)[0])) + }, + ), + ), + // func LastIndexFunc(s string, f func(rune) bool) int + // func Map(mapping func(rune) rune, s string) string + BindFunction( + createStringsName("repeat"), + OverloadFunc(createStringsID("repeat_string_int_string"), []*cel.Type{cel.StringType, cel.IntType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.Repeat(args[0].(types.String).Value().(string), int(args[1].(types.Int).Value().(int64)))) + }, + ), + ), + BindFunction( + createStringsName("replace"), + OverloadFunc(createStringsID("replace_string_string_string_int_string"), []*cel.Type{cel.StringType, cel.StringType, cel.StringType, cel.IntType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.Replace(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string), args[2].(types.String).Value().(string), int(args[3].(types.Int).Value().(int64)))) + }, + ), + ), + BindFunction( + createStringsName("replaceAll"), + OverloadFunc(createStringsID("replaceAll_string_string_string_string"), []*cel.Type{cel.StringType, cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.ReplaceAll(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string), args[2].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("split"), + OverloadFunc(createStringsID("split_string_string_strings"), []*cel.Type{cel.StringType, cel.StringType}, cel.ListType(cel.StringType), + func(_ context.Context, args ...ref.Val) ref.Val { + adapter := types.DefaultTypeAdapter + return types.NewStringList(adapter, strings.Split(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("splitAfter"), + OverloadFunc(createStringsID("splitAfter_string_string_strings"), []*cel.Type{cel.StringType, cel.StringType}, cel.ListType(cel.StringType), + func(_ context.Context, args ...ref.Val) ref.Val { + adapter := types.DefaultTypeAdapter + return types.NewStringList(adapter, strings.SplitAfter(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("splitAfterN"), + OverloadFunc(createStringsID("splitAfterN_string_string_int_strings"), []*cel.Type{cel.StringType, cel.StringType, cel.IntType}, cel.ListType(cel.StringType), + func(_ context.Context, args ...ref.Val) ref.Val { + adapter := types.DefaultTypeAdapter + return types.NewStringList(adapter, strings.SplitAfterN(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string), int(args[2].(types.Int).Value().(int64)))) + }, + ), + ), + BindFunction( + createStringsName("splitN"), + OverloadFunc(createStringsID("splitN_string_string_int_strings"), []*cel.Type{cel.StringType, cel.StringType, cel.IntType}, cel.ListType(cel.StringType), + func(_ context.Context, args ...ref.Val) ref.Val { + adapter := types.DefaultTypeAdapter + return types.NewStringList(adapter, strings.SplitN(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string), int(args[2].(types.Int).Value().(int64)))) + }, + ), + ), + // func Title(s string) string : deprecated + BindFunction( + createStringsName("title"), + OverloadFunc(createStringsID("title_string_string"), []*cel.Type{cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.Title(args[0].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("toLower"), + OverloadFunc(createStringsID("toLower_string_string"), []*cel.Type{cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.ToLower(args[0].(types.String).Value().(string))) + }, + ), + ), + // func ToLowerSpecial(c unicode.SpecialCase, s string) string + BindFunction( + createStringsName("toTitle"), + OverloadFunc(createStringsID("toTitle_string_string"), []*cel.Type{cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.ToTitle(args[0].(types.String).Value().(string))) + }, + ), + ), + // func ToTitleSpecial(c unicode.SpecialCase, s string) string + BindFunction( + createStringsName("toUpper"), + OverloadFunc(createStringsID("toUpper_string_string"), []*cel.Type{cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.ToUpper(args[0].(types.String).Value().(string))) + }, + ), + ), + // func ToUpperSpecial(c unicode.SpecialCase, s string) string + BindFunction( + createStringsName("toValidUTF8"), + OverloadFunc(createStringsID("toValidUTF8_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.ToValidUTF8(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("trim"), + OverloadFunc(createStringsID("trim_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.Trim(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + // func TrimFunc(s string, f func(rune) bool) string + BindFunction( + createStringsName("trimLeft"), + OverloadFunc(createStringsID("trimLeft_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.TrimLeft(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + // func TrimLeftFunc(s string, f func(rune) bool) string + BindFunction( + createStringsName("trimPrefix"), + OverloadFunc(createStringsID("trimPrefix_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.TrimPrefix(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("trimRight"), + OverloadFunc(createStringsID("trimRight_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.TrimRight(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + // func TrimRightFunc(s string, f func(rune) bool) string + BindFunction( + createStringsName("trimSpace"), + OverloadFunc(createStringsID("trimSpace_string_string"), []*cel.Type{cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.TrimSpace(args[0].(types.String).Value().(string))) + }, + ), + ), + BindFunction( + createStringsName("trimSuffix"), + OverloadFunc(createStringsID("trimSuffix_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, + func(_ context.Context, args ...ref.Val) ref.Val { + return types.String(strings.TrimSuffix(args[0].(types.String).Value().(string), args[1].(types.String).Value().(string))) + }, + ), + ), + } { + opts = append(opts, funcOpts...) + } + + return opts +} + +func (lib *StringsLibrary) ProgramOptions() []cel.ProgramOption { + return []cel.ProgramOption{} +} From cc0ae759114e7012f64ada7de1fd1a110abb6d03 Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Fri, 20 Sep 2024 14:42:22 +0900 Subject: [PATCH 02/10] =?UTF-8?q?=E2=9C=85=20add=20strings=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grpc/federation/cel/strings_test.go | 649 ++++++++++++++++++++++++++++ 1 file changed, 649 insertions(+) create mode 100644 grpc/federation/cel/strings_test.go diff --git a/grpc/federation/cel/strings_test.go b/grpc/federation/cel/strings_test.go new file mode 100644 index 00000000..c1f2f606 --- /dev/null +++ b/grpc/federation/cel/strings_test.go @@ -0,0 +1,649 @@ +package cel_test + +import ( + "context" + "fmt" + "github.com/google/cel-go/cel" + "github.com/google/cel-go/common/types" + "github.com/google/cel-go/common/types/ref" + "github.com/google/cel-go/common/types/traits" + "github.com/google/go-cmp/cmp" + cellib "github.com/mercari/grpc-federation/grpc/federation/cel" + "strings" + "testing" +) + +func TestStringsFunctions(t *testing.T) { + tests := []struct { + name string + expr string + args map[string]any + cmp func(ref.Val) error + }{ + { + name: "clone", + expr: "grpc.federation.strings.clone('abc')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String("abc") + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "compare", + expr: "grpc.federation.strings.compare('abc', 'abd')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.Compare("abc", "abd")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "contains", + expr: "grpc.federation.strings.contains('abc', 'a')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Bool) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := strings.Contains("abc", "a") + if diff := cmp.Diff(bool(gotV), expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "containsAny", + expr: "grpc.federation.strings.containsAny('fail', 'ui')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Bool) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := strings.ContainsAny("fail", "ui") + if diff := cmp.Diff(bool(gotV), expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "containsRune", + expr: "grpc.federation.strings.containsRune('aardvark', 97)", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Bool) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := strings.ContainsRune("aardvark", 97) + if diff := cmp.Diff(bool(gotV), expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "count", + expr: "grpc.federation.strings.count('cheese', 'e')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.Count("cheese", "e")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "cutPrefix", + expr: "grpc.federation.strings.cutPrefix('abc', 'a')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.TrimPrefix("abc", "a")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "cutSuffix", + expr: "grpc.federation.strings.cutSuffix('abc', 'c')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.TrimSuffix("abc", "c")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "equalFold", + expr: "grpc.federation.strings.equalFold('Go', 'go')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Bool) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Bool(strings.EqualFold("Go", "go")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "fields", + expr: "grpc.federation.strings.fields('a b c')", + cmp: func(got ref.Val) error { + gotV, ok := got.(traits.Lister) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + strs := make([]string, gotV.Size().(types.Int)) + for i := 0; i < int(gotV.Size().(types.Int)); i++ { + strs[i] = gotV.Get(types.Int(i)).(types.String).Value().(string) + } + expected := strings.Fields("a b c") + if diff := cmp.Diff(strs, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "hasPrefix", + expr: "grpc.federation.strings.hasPrefix('abc', 'a')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Bool) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Bool(strings.HasPrefix("abc", "a")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "hasSuffix", + expr: "grpc.federation.strings.hasSuffix('abc', 'c')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Bool) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Bool(strings.HasSuffix("abc", "c")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "index", + expr: "grpc.federation.strings.index('chicken', 'ken')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.Index("chicken", "ken")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "indexAny", + expr: "grpc.federation.strings.indexAny('chicken', 'aeiou')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.IndexAny("chicken", "aeiou")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "indexByte", + expr: "grpc.federation.strings.indexByte('golang', 'g')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.IndexByte("golang", 'g')) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "indexRune", + expr: "grpc.federation.strings.indexRune('golang', 111)", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.IndexRune("golang", 111)) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "join", + expr: "grpc.federation.strings.join(['a', 'b', 'c'], ',')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.Join([]string{"a", "b", "c"}, ",")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "lastIndex", + expr: "grpc.federation.strings.lastIndex('go gopher', 'go')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.LastIndex("go gopher", "go")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "lastIndexAny", + expr: "grpc.federation.strings.lastIndexAny('go gopher', 'go')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.LastIndexAny("go gopher", "go")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "lastIndexByte", + expr: "grpc.federation.strings.lastIndexByte('golang', 'g')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.Int) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.Int(strings.LastIndexByte("golang", 'g')) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "repeat", + expr: "grpc.federation.strings.repeat('a', 5)", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.Repeat("a", 5)) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "replace", + expr: "grpc.federation.strings.replace('oink oink oink', 'k', 'ky', 2)", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.Replace("oink oink oink", "k", "ky", 2)) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "replaceAll", + expr: "grpc.federation.strings.replaceAll('oink oink oink', 'k', 'ky')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.ReplaceAll("oink oink oink", "k", "ky")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "split", + expr: "grpc.federation.strings.split('a,b,c', ',')", + cmp: func(got ref.Val) error { + gotV, ok := got.(traits.Lister) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + strs := make([]string, gotV.Size().(types.Int)) + for i := 0; i < int(gotV.Size().(types.Int)); i++ { + strs[i] = gotV.Get(types.Int(i)).(types.String).Value().(string) + } + expected := strings.Split("a,b,c", ",") + if diff := cmp.Diff(strs, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "splitAfter", + expr: "grpc.federation.strings.splitAfter('a,b,c', ',')", + cmp: func(got ref.Val) error { + gotV, ok := got.(traits.Lister) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + strs := make([]string, gotV.Size().(types.Int)) + for i := 0; i < int(gotV.Size().(types.Int)); i++ { + strs[i] = gotV.Get(types.Int(i)).(types.String).Value().(string) + } + expected := strings.SplitAfter("a,b,c", ",") + if diff := cmp.Diff(strs, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "splitAfterN", + expr: "grpc.federation.strings.splitAfterN('a,b,c', ',', 2)", + cmp: func(got ref.Val) error { + gotV, ok := got.(traits.Lister) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + strs := make([]string, gotV.Size().(types.Int)) + for i := 0; i < int(gotV.Size().(types.Int)); i++ { + strs[i] = gotV.Get(types.Int(i)).(types.String).Value().(string) + } + expected := strings.SplitAfterN("a,b,c", ",", 2) + if diff := cmp.Diff(strs, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "splitN", + expr: "grpc.federation.strings.splitN('a,b,c', ',', 2)", + cmp: func(got ref.Val) error { + gotV, ok := got.(traits.Lister) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + strs := make([]string, gotV.Size().(types.Int)) + for i := 0; i < int(gotV.Size().(types.Int)); i++ { + strs[i] = gotV.Get(types.Int(i)).(types.String).Value().(string) + } + expected := strings.SplitN("a,b,c", ",", 2) + if diff := cmp.Diff(strs, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "title", + expr: "grpc.federation.strings.title('her royal highness')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.Title("her royal highness")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "toLower", + expr: "grpc.federation.strings.toLower('Gopher')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.ToLower("Gopher")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "toTitle", + expr: "grpc.federation.strings.toTitle('loud noises')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.ToTitle("loud noises")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "toUpper", + expr: "grpc.federation.strings.toUpper('loud noises')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.ToUpper("loud noises")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "toValidUTF8", + expr: "grpc.federation.strings.toValidUTF8('abc', '\uFFFD')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.ToValidUTF8("abc", "\uFFFD")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "trim", + expr: "grpc.federation.strings.trim('¡¡¡Hello, Gophers!!!', '¡')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.Trim("¡¡¡Hello, Gophers!!!", "¡")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "trimLeft", + expr: "grpc.federation.strings.trimLeft('¡¡¡Hello, Gophers!!!', '¡')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.TrimLeft("¡¡¡Hello, Gophers!!!", "¡")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "trimPrefix", + expr: "grpc.federation.strings.trimPrefix('¡¡¡Hello, Gophers!!!', '¡¡¡')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.TrimPrefix("¡¡¡Hello, Gophers!!!", "¡¡¡")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "trimRight", + expr: "grpc.federation.strings.trimRight('¡¡¡Hello, Gophers!!!', '¡¡¡')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.TrimRight("¡¡¡Hello, Gophers!!!", "¡¡¡")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "trimSpace", + expr: "grpc.federation.strings.trimSpace(' \t Hello, Gophers \t\t ')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.TrimSpace(" \t Hello, Gophers \t\t ")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + { + name: "trimSuffix", + expr: "grpc.federation.strings.trimSuffix('¡¡¡Hello, Gophers!!!', '!!!')", + cmp: func(got ref.Val) error { + gotV, ok := got.(types.String) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + expected := types.String(strings.TrimSuffix("¡¡¡Hello, Gophers!!!", "!!!")) + if diff := cmp.Diff(gotV, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, + } + + reg, err := types.NewRegistry() + if err != nil { + t.Fatal(err) + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + env, err := cel.NewEnv( + cel.Variable(cellib.ContextVariableName, cel.ObjectType(cellib.ContextTypeName)), + cel.Lib(cellib.NewStringsLibrary(reg)), + ) + if err != nil { + t.Fatal(err) + } + ast, iss := env.Compile(test.expr) + if iss.Err() != nil { + t.Fatal(iss.Err()) + } + program, err := env.Program(ast) + if err != nil { + t.Fatal(err) + } + args := map[string]any{cellib.ContextVariableName: cellib.NewContextValue(context.Background())} + for k, v := range test.args { + args[k] = v + } + out, _, err := program.Eval(args) + if err != nil { + t.Fatal(err) + } + if err := test.cmp(out); err != nil { + t.Fatal(err) + } + }) + } +} From 80edc185c67ac22e6f60d6b956620d7d5518fb1e Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Fri, 20 Sep 2024 20:15:49 +0900 Subject: [PATCH 03/10] =?UTF-8?q?=E2=9C=A8=20add=20StringsLibrary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grpc/federation/cel/lib.go | 1 + 1 file changed, 1 insertion(+) diff --git a/grpc/federation/cel/lib.go b/grpc/federation/cel/lib.go index da6d74b2..54d46a9e 100644 --- a/grpc/federation/cel/lib.go +++ b/grpc/federation/cel/lib.go @@ -18,6 +18,7 @@ func NewLibrary(typeAdapter types.Adapter) *Library { return &Library{ name: "grpc.federation.static", subLibs: []cel.SingletonLibrary{ + NewStringsLibrary(typeAdapter), NewTimeLibrary(typeAdapter), NewListLibrary(typeAdapter), new(RandLibrary), From df3acb795db016ec754accba15b6fb60ea87b94b Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Fri, 20 Sep 2024 20:17:06 +0900 Subject: [PATCH 04/10] =?UTF-8?q?=E2=9C=85=20add=20strings=20examples=20te?= =?UTF-8?q?st?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../02_simple/federation/federation.pb.go | 408 +++++++++--------- .../federation_grpc_federation.pb.go | 143 +++--- _examples/02_simple/main_test.go | 1 + .../proto/federation/federation.proto | 2 + 4 files changed, 308 insertions(+), 246 deletions(-) diff --git a/_examples/02_simple/federation/federation.pb.go b/_examples/02_simple/federation/federation.pb.go index 43a7b694..25ec797a 100644 --- a/_examples/02_simple/federation/federation.pb.go +++ b/_examples/02_simple/federation/federation.pb.go @@ -205,6 +205,7 @@ type GetPostResponse struct { NullTimestamp2 *timestamppb.Timestamp `protobuf:"bytes,29,opt,name=null_timestamp2,json=nullTimestamp2,proto3" json:"null_timestamp2,omitempty"` NullTimestamp3 *timestamppb.Timestamp `protobuf:"bytes,30,opt,name=null_timestamp3,json=nullTimestamp3,proto3" json:"null_timestamp3,omitempty"` JpLoc string `protobuf:"bytes,31,opt,name=jp_loc,json=jpLoc,proto3" json:"jp_loc,omitempty"` + StringsJoin string `protobuf:"bytes,32,opt,name=strings_join,json=stringsJoin,proto3" json:"strings_join,omitempty"` } func (x *GetPostResponse) Reset() { @@ -456,6 +457,13 @@ func (x *GetPostResponse) GetJpLoc() string { return "" } +func (x *GetPostResponse) GetStringsJoin() string { + if x != nil { + return x.StringsJoin + } + return "" +} + type A struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1160,7 +1168,7 @@ var file_federation_federation_proto_rawDesc = []byte{ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x20, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xdd, 0x1c, 0x0a, 0x0f, 0x47, 0x65, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xd7, 0x1d, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x42, 0x09, 0x9a, @@ -1335,202 +1343,210 @@ var file_federation_federation_proto_rawDesc = []byte{ 0x63, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x20, 0x9a, 0x4a, 0x1d, 0x12, 0x1b, 0x6a, 0x70, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x52, 0x05, 0x6a, 0x70, 0x4c, 0x6f, 0x63, - 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0xb9, 0x06, - 0x9a, 0x4a, 0xb5, 0x06, 0x0a, 0x1a, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x6a, 0x12, 0x0a, 0x04, - 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0a, 0x0a, 0x02, 0x69, 0x64, 0x12, 0x04, 0x24, 0x2e, 0x69, 0x64, - 0x0a, 0x59, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x5a, 0x51, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, - 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x64, - 0x61, 0x74, 0x65, 0x28, 0x32, 0x30, 0x32, 0x33, 0x2c, 0x20, 0x31, 0x32, 0x2c, 0x20, 0x32, 0x35, - 0x2c, 0x20, 0x31, 0x32, 0x2c, 0x20, 0x31, 0x30, 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x30, 0x2c, 0x20, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x55, 0x54, 0x43, 0x28, 0x29, 0x29, 0x0a, 0x3a, 0x0a, 0x0b, 0x72, - 0x61, 0x6e, 0x64, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5a, 0x2b, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x72, 0x61, 0x6e, 0x64, - 0x2e, 0x6e, 0x65, 0x77, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x28, 0x64, 0x61, 0x74, 0x65, 0x2e, - 0x75, 0x6e, 0x69, 0x78, 0x28, 0x29, 0x29, 0x0a, 0x33, 0x0a, 0x0a, 0x66, 0x69, 0x78, 0x65, 0x64, - 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x5a, 0x25, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x2e, 0x6e, 0x65, 0x77, 0x28, - 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x0a, 0x3b, 0x0a, 0x04, - 0x75, 0x75, 0x69, 0x64, 0x5a, 0x33, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x75, 0x75, 0x69, 0x64, 0x2e, 0x6e, 0x65, 0x77, 0x52, - 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x46, 0x72, 0x6f, 0x6d, 0x52, 0x61, 0x6e, 0x64, 0x28, 0x66, 0x69, - 0x78, 0x65, 0x64, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x29, 0x0a, 0x36, 0x0a, 0x03, 0x6c, 0x6f, 0x63, - 0x5a, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x28, 0x27, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x27, - 0x29, 0x0a, 0x45, 0x0a, 0x07, 0x6a, 0x70, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x3a, 0x67, 0x72, - 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x74, 0x69, - 0x6d, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x65, 0x28, 0x32, 0x30, 0x32, 0x33, 0x2c, 0x20, 0x31, 0x32, - 0x2c, 0x20, 0x32, 0x35, 0x2c, 0x20, 0x31, 0x32, 0x2c, 0x20, 0x31, 0x30, 0x2c, 0x20, 0x35, 0x2c, - 0x20, 0x30, 0x2c, 0x20, 0x6c, 0x6f, 0x63, 0x29, 0x0a, 0x38, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x31, 0x5a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x69, 0x6e, 0x63, - 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x5b, 0x27, 0x6b, 0x65, 0x79, 0x31, 0x27, 0x5d, 0x5b, - 0x30, 0x5d, 0x0a, 0x08, 0x0a, 0x01, 0x61, 0x6a, 0x03, 0x0a, 0x01, 0x41, 0x0a, 0x2b, 0x0a, 0x0d, - 0x73, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5a, 0x1a, 0x5b, - 0x34, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x33, 0x2c, 0x20, 0x32, 0x5d, 0x2e, 0x73, 0x6f, 0x72, 0x74, - 0x41, 0x73, 0x63, 0x28, 0x76, 0x2c, 0x20, 0x76, 0x29, 0x0a, 0x95, 0x01, 0x0a, 0x0c, 0x73, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x5a, 0x84, 0x01, 0x5b, 0x75, 0x73, - 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x7b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x3a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x7b, 0x61, 0x64, 0x64, 0x72, 0x31, 0x3a, 0x27, 0x61, 0x27, 0x7d, 0x7d, 0x2c, - 0x20, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x7b, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x3a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7b, 0x61, 0x64, 0x64, 0x72, 0x31, 0x3a, 0x27, 0x62, 0x27, - 0x7d, 0x7d, 0x5d, 0x2e, 0x73, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x73, 0x63, 0x28, 0x76, 0x2c, 0x20, - 0x76, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x61, 0x64, 0x64, 0x72, 0x31, - 0x29, 0x0a, 0x25, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x18, - 0x7b, 0x31, 0x3a, 0x20, 0x27, 0x61, 0x27, 0x2c, 0x20, 0x32, 0x3a, 0x20, 0x27, 0x62, 0x27, 0x2c, - 0x20, 0x33, 0x3a, 0x20, 0x27, 0x63, 0x27, 0x7d, 0x0a, 0x12, 0x0a, 0x0a, 0x6e, 0x75, 0x6c, 0x6c, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x04, 0x6e, 0x75, 0x6c, 0x6c, 0x0a, 0x4b, 0x5a, 0x49, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x6c, 0x6f, 0x67, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x28, 0x27, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x20, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x67, 0x27, - 0x2c, 0x20, 0x7b, 0x27, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x27, 0x3a, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x7d, 0x29, 0x22, 0xdf, 0x03, 0x0a, 0x01, 0x41, 0x12, - 0x25, 0x0a, 0x01, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x66, 0x65, 0x64, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x2e, 0x42, 0x42, 0x06, 0x9a, 0x4a, 0x03, - 0x12, 0x01, 0x62, 0x52, 0x01, 0x62, 0x1a, 0xa1, 0x03, 0x0a, 0x01, 0x42, 0x12, 0x2d, 0x0a, 0x03, - 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x66, 0x65, 0x64, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x2e, 0x42, 0x2e, 0x43, 0x42, 0x08, 0x9a, 0x4a, - 0x05, 0x12, 0x03, 0x66, 0x6f, 0x6f, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x12, 0x2d, 0x0a, 0x03, 0x62, - 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x2e, 0x42, 0x2e, 0x43, 0x42, 0x08, 0x9a, 0x4a, 0x05, - 0x12, 0x03, 0x62, 0x61, 0x72, 0x52, 0x03, 0x62, 0x61, 0x72, 0x1a, 0x24, 0x0a, 0x01, 0x43, 0x12, - 0x1f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0b, 0x9a, - 0x4a, 0x08, 0x12, 0x06, 0x24, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x3a, 0x97, 0x02, 0x9a, 0x4a, 0x93, 0x02, 0x0a, 0x1d, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x6a, 0x16, - 0x0a, 0x05, 0x41, 0x2e, 0x42, 0x2e, 0x43, 0x12, 0x0d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x05, 0x27, 0x66, 0x6f, 0x6f, 0x27, 0x0a, 0x1d, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x6a, 0x16, 0x0a, - 0x05, 0x41, 0x2e, 0x42, 0x2e, 0x43, 0x12, 0x0d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x05, - 0x27, 0x62, 0x61, 0x72, 0x27, 0x0a, 0x89, 0x01, 0x12, 0x11, 0x66, 0x6f, 0x6f, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x66, 0x6f, 0x6f, 0x27, 0x5a, 0x74, 0x67, 0x72, 0x70, - 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, - 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x28, 0x27, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x66, 0x65, - 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x67, 0x27, 0x2c, 0x20, 0x7b, - 0x27, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x27, 0x3a, 0x20, 0x5b, 0x66, 0x6f, 0x6f, - 0x2c, 0x20, 0x62, 0x61, 0x72, 0x5d, 0x2c, 0x20, 0x27, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x5f, 0x6d, 0x61, 0x70, 0x27, 0x3a, 0x20, 0x7b, 0x27, 0x66, 0x6f, 0x6f, 0x27, 0x3a, 0x20, 0x66, - 0x6f, 0x6f, 0x2c, 0x20, 0x27, 0x62, 0x61, 0x72, 0x27, 0x3a, 0x20, 0x62, 0x61, 0x72, 0x7d, 0x7d, - 0x29, 0x0a, 0x47, 0x5a, 0x45, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x61, 0x64, 0x64, 0x28, 0x7b, 0x27, 0x66, - 0x6f, 0x6f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x27, 0x3a, 0x20, 0x66, 0x6f, 0x6f, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x2c, 0x20, 0x27, 0x62, 0x61, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x27, 0x3a, 0x20, - 0x62, 0x61, 0x72, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x7d, 0x29, 0x3a, 0x0f, 0x9a, 0x4a, 0x0c, 0x0a, - 0x0a, 0x0a, 0x01, 0x62, 0x6a, 0x05, 0x0a, 0x03, 0x41, 0x2e, 0x42, 0x22, 0xe6, 0x01, 0x0a, 0x04, - 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x42, 0x09, 0x9a, 0x4a, 0x06, 0x12, 0x04, 0x75, 0x73, 0x65, 0x72, 0x52, - 0x04, 0x75, 0x73, 0x65, 0x72, 0x3a, 0x6d, 0x9a, 0x4a, 0x6a, 0x0a, 0x3c, 0x0a, 0x03, 0x72, 0x65, - 0x73, 0x72, 0x35, 0x0a, 0x18, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0a, 0x0a, - 0x02, 0x69, 0x64, 0x12, 0x04, 0x24, 0x2e, 0x69, 0x64, 0x1a, 0x03, 0x31, 0x30, 0x73, 0x22, 0x08, - 0x0a, 0x06, 0x0a, 0x02, 0x32, 0x73, 0x10, 0x03, 0x0a, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, - 0x18, 0x01, 0x5a, 0x08, 0x72, 0x65, 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x0a, 0x16, 0x0a, 0x04, - 0x75, 0x73, 0x65, 0x72, 0x6a, 0x0e, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x06, 0x1a, 0x04, - 0x70, 0x6f, 0x73, 0x74, 0x22, 0xc8, 0x04, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x26, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x74, - 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x66, 0x65, 0x64, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x61, 0x74, 0x74, 0x72, 0x5f, 0x61, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x41, 0x48, 0x00, 0x52, 0x05, 0x61, 0x74, - 0x74, 0x72, 0x41, 0x12, 0x26, 0x0a, 0x01, 0x62, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x2e, 0x41, 0x74, 0x74, 0x72, 0x42, 0x48, 0x00, 0x52, 0x01, 0x62, 0x1a, 0x50, 0x0a, 0x0c, 0x50, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, - 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x2f, 0x0a, - 0x05, 0x41, 0x74, 0x74, 0x72, 0x41, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x3a, 0x14, 0x9a, 0x4a, 0x11, 0x1a, 0x0f, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x41, 0x1a, 0x2f, - 0x0a, 0x05, 0x41, 0x74, 0x74, 0x72, 0x42, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x62, 0x61, 0x72, 0x3a, 0x14, 0x9a, 0x4a, 0x11, 0x1a, 0x0f, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x42, 0x3a, - 0xa5, 0x01, 0x9a, 0x4a, 0xa1, 0x01, 0x0a, 0x8a, 0x01, 0x0a, 0x03, 0x72, 0x65, 0x73, 0x72, 0x82, - 0x01, 0x0a, 0x18, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0f, 0x0a, 0x02, 0x69, - 0x64, 0x12, 0x09, 0x24, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x27, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, - 0x49, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x27, - 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x31, 0x27, 0x29, 0x1a, 0x03, 0x32, - 0x30, 0x73, 0x22, 0x1f, 0x12, 0x1d, 0x0a, 0x02, 0x31, 0x73, 0x11, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0xe6, 0x3f, 0x19, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xfb, 0x3f, 0x22, 0x03, 0x33, 0x30, - 0x73, 0x28, 0x03, 0x0a, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x5a, 0x08, 0x72, - 0x65, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x42, 0x06, 0x0a, 0x04, 0x61, 0x74, 0x74, 0x72, 0x22, - 0x8d, 0x05, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x66, 0x65, 0x64, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x49, 0x74, 0x65, - 0x6d, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x12, 0x35, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0xf1, 0x02, 0x0a, 0x08, 0x4c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x31, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x61, - 0x64, 0x64, 0x72, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, - 0x32, 0x12, 0x38, 0x0a, 0x06, 0x61, 0x64, 0x64, 0x72, 0x5f, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1f, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, - 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, - 0x72, 0x41, 0x48, 0x00, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, 0x41, 0x12, 0x2f, 0x0a, 0x01, 0x62, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x42, 0x48, 0x00, 0x52, 0x01, 0x62, 0x1a, 0x38, 0x0a, 0x05, - 0x41, 0x64, 0x64, 0x72, 0x41, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x3a, 0x1d, 0x9a, 0x4a, 0x1a, 0x1a, 0x18, 0x75, 0x73, + 0x12, 0x34, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, + 0x18, 0x20, 0x20, 0x01, 0x28, 0x09, 0x42, 0x11, 0x9a, 0x4a, 0x0e, 0x12, 0x0c, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x73, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x3a, 0xfd, 0x06, 0x9a, 0x4a, 0xf9, 0x06, 0x0a, 0x1a, 0x0a, 0x04, 0x70, 0x6f, + 0x73, 0x74, 0x6a, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0a, 0x0a, 0x02, 0x69, 0x64, + 0x12, 0x04, 0x24, 0x2e, 0x69, 0x64, 0x0a, 0x42, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x73, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5a, 0x32, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x2e, + 0x6a, 0x6f, 0x69, 0x6e, 0x28, 0x5b, 0x27, 0x61, 0x27, 0x2c, 0x20, 0x27, 0x62, 0x27, 0x2c, 0x20, + 0x27, 0x63, 0x27, 0x5d, 0x2c, 0x20, 0x27, 0x2c, 0x27, 0x29, 0x0a, 0x59, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x65, 0x5a, 0x51, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x65, 0x28, 0x32, 0x30, + 0x32, 0x33, 0x2c, 0x20, 0x31, 0x32, 0x2c, 0x20, 0x32, 0x35, 0x2c, 0x20, 0x31, 0x32, 0x2c, 0x20, + 0x31, 0x30, 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, + 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x55, + 0x54, 0x43, 0x28, 0x29, 0x29, 0x0a, 0x3a, 0x0a, 0x0b, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5a, 0x2b, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x2e, 0x6e, 0x65, 0x77, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x28, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x75, 0x6e, 0x69, 0x78, 0x28, 0x29, + 0x29, 0x0a, 0x33, 0x0a, 0x0a, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x5a, + 0x25, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x2e, 0x6e, 0x65, 0x77, 0x28, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x29, 0x0a, 0x3b, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x5a, 0x33, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x75, 0x75, 0x69, 0x64, 0x2e, 0x6e, 0x65, 0x77, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x46, + 0x72, 0x6f, 0x6d, 0x52, 0x61, 0x6e, 0x64, 0x28, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x61, + 0x6e, 0x64, 0x29, 0x0a, 0x36, 0x0a, 0x03, 0x6c, 0x6f, 0x63, 0x5a, 0x2f, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x74, 0x69, 0x6d, 0x65, + 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x27, 0x41, + 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x27, 0x29, 0x0a, 0x45, 0x0a, 0x07, 0x6a, + 0x70, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x3a, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x64, 0x61, 0x74, + 0x65, 0x28, 0x32, 0x30, 0x32, 0x33, 0x2c, 0x20, 0x31, 0x32, 0x2c, 0x20, 0x32, 0x35, 0x2c, 0x20, + 0x31, 0x32, 0x2c, 0x20, 0x31, 0x30, 0x2c, 0x20, 0x35, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x6c, 0x6f, + 0x63, 0x29, 0x0a, 0x38, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x5a, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x28, + 0x29, 0x5b, 0x27, 0x6b, 0x65, 0x79, 0x31, 0x27, 0x5d, 0x5b, 0x30, 0x5d, 0x0a, 0x08, 0x0a, 0x01, + 0x61, 0x6a, 0x03, 0x0a, 0x01, 0x41, 0x0a, 0x2b, 0x0a, 0x0d, 0x73, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5a, 0x1a, 0x5b, 0x34, 0x2c, 0x20, 0x31, 0x2c, 0x20, + 0x33, 0x2c, 0x20, 0x32, 0x5d, 0x2e, 0x73, 0x6f, 0x72, 0x74, 0x41, 0x73, 0x63, 0x28, 0x76, 0x2c, + 0x20, 0x76, 0x29, 0x0a, 0x95, 0x01, 0x0a, 0x0c, 0x73, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x5a, 0x84, 0x01, 0x5b, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, + 0x6d, 0x7b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7b, 0x61, 0x64, + 0x64, 0x72, 0x31, 0x3a, 0x27, 0x61, 0x27, 0x7d, 0x7d, 0x2c, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x49, 0x74, 0x65, 0x6d, 0x7b, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x41, 0x64, 0x64, 0x72, 0x41, 0x1a, 0x38, 0x0a, 0x05, 0x41, 0x64, 0x64, 0x72, 0x42, 0x12, - 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x62, 0x61, - 0x72, 0x3a, 0x1d, 0x9a, 0x4a, 0x1a, 0x1a, 0x18, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, - 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x42, - 0x22, 0x38, 0x0a, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x31, 0x10, 0x01, 0x3a, 0x17, 0x9a, 0x4a, 0x14, 0x1a, - 0x12, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x33, 0x22, 0x71, 0x0a, 0x08, - 0x49, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x49, 0x54, 0x45, 0x4d, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x31, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x33, 0x10, 0x03, 0x1a, 0x17, 0x9a, 0x4a, 0x14, 0x0a, 0x12, 0x75, 0x73, 0x65, - 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x3a, - 0x0e, 0x9a, 0x4a, 0x0b, 0x1a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x32, - 0x5e, 0x0a, 0x11, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x12, - 0x1a, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, - 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x66, 0x65, - 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x1a, 0x03, 0x9a, 0x4a, 0x00, 0x42, - 0xad, 0x01, 0x9a, 0x4a, 0x22, 0x12, 0x0f, 0x70, 0x6f, 0x73, 0x74, 0x2f, 0x70, 0x6f, 0x73, 0x74, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x75, 0x73, 0x65, - 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x66, 0x65, 0x64, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0f, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1d, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x2f, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x66, - 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, 0x46, 0x58, 0x58, 0xaa, - 0x02, 0x0a, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xca, 0x02, 0x0a, 0x46, - 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xe2, 0x02, 0x16, 0x46, 0x65, 0x64, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x0a, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x7b, 0x61, 0x64, 0x64, 0x72, 0x31, 0x3a, 0x27, 0x62, 0x27, 0x7d, 0x7d, 0x5d, 0x2e, 0x73, 0x6f, + 0x72, 0x74, 0x44, 0x65, 0x73, 0x63, 0x28, 0x76, 0x2c, 0x20, 0x76, 0x2e, 0x6c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x61, 0x64, 0x64, 0x72, 0x31, 0x29, 0x0a, 0x25, 0x0a, 0x09, 0x6d, + 0x61, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x18, 0x7b, 0x31, 0x3a, 0x20, 0x27, 0x61, + 0x27, 0x2c, 0x20, 0x32, 0x3a, 0x20, 0x27, 0x62, 0x27, 0x2c, 0x20, 0x33, 0x3a, 0x20, 0x27, 0x63, + 0x27, 0x7d, 0x0a, 0x12, 0x0a, 0x0a, 0x6e, 0x75, 0x6c, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x5a, 0x04, 0x6e, 0x75, 0x6c, 0x6c, 0x0a, 0x4b, 0x5a, 0x49, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, + 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x69, 0x6e, + 0x66, 0x6f, 0x28, 0x27, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x66, 0x65, 0x64, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x67, 0x27, 0x2c, 0x20, 0x7b, 0x27, 0x70, 0x6f, + 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x27, 0x3a, 0x20, 0x70, 0x6f, 0x73, + 0x74, 0x7d, 0x29, 0x22, 0xdf, 0x03, 0x0a, 0x01, 0x41, 0x12, 0x25, 0x0a, 0x01, 0x62, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x41, 0x2e, 0x42, 0x42, 0x06, 0x9a, 0x4a, 0x03, 0x12, 0x01, 0x62, 0x52, 0x01, 0x62, + 0x1a, 0xa1, 0x03, 0x0a, 0x01, 0x42, 0x12, 0x2d, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x41, 0x2e, 0x42, 0x2e, 0x43, 0x42, 0x08, 0x9a, 0x4a, 0x05, 0x12, 0x03, 0x66, 0x6f, 0x6f, + 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x12, 0x2d, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x41, 0x2e, 0x42, 0x2e, 0x43, 0x42, 0x08, 0x9a, 0x4a, 0x05, 0x12, 0x03, 0x62, 0x61, 0x72, 0x52, + 0x03, 0x62, 0x61, 0x72, 0x1a, 0x24, 0x0a, 0x01, 0x43, 0x12, 0x1f, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0b, 0x9a, 0x4a, 0x08, 0x12, 0x06, 0x24, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x97, 0x02, 0x9a, 0x4a, 0x93, + 0x02, 0x0a, 0x1d, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x6a, 0x16, 0x0a, 0x05, 0x41, 0x2e, 0x42, 0x2e, + 0x43, 0x12, 0x0d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x05, 0x27, 0x66, 0x6f, 0x6f, 0x27, + 0x0a, 0x1d, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x6a, 0x16, 0x0a, 0x05, 0x41, 0x2e, 0x42, 0x2e, 0x43, + 0x12, 0x0d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x05, 0x27, 0x62, 0x61, 0x72, 0x27, 0x0a, + 0x89, 0x01, 0x12, 0x11, 0x66, 0x6f, 0x6f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, + 0x27, 0x66, 0x6f, 0x6f, 0x27, 0x5a, 0x74, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6c, 0x6f, 0x67, 0x2e, 0x69, 0x6e, 0x66, 0x6f, 0x28, + 0x27, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x67, 0x27, 0x2c, 0x20, 0x7b, 0x27, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x27, 0x3a, 0x20, 0x5b, 0x66, 0x6f, 0x6f, 0x2c, 0x20, 0x62, 0x61, 0x72, 0x5d, + 0x2c, 0x20, 0x27, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x6d, 0x61, 0x70, 0x27, 0x3a, + 0x20, 0x7b, 0x27, 0x66, 0x6f, 0x6f, 0x27, 0x3a, 0x20, 0x66, 0x6f, 0x6f, 0x2c, 0x20, 0x27, 0x62, + 0x61, 0x72, 0x27, 0x3a, 0x20, 0x62, 0x61, 0x72, 0x7d, 0x7d, 0x29, 0x0a, 0x47, 0x5a, 0x45, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6c, + 0x6f, 0x67, 0x2e, 0x61, 0x64, 0x64, 0x28, 0x7b, 0x27, 0x66, 0x6f, 0x6f, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x27, 0x3a, 0x20, 0x66, 0x6f, 0x6f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x27, 0x62, + 0x61, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x27, 0x3a, 0x20, 0x62, 0x61, 0x72, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x7d, 0x29, 0x3a, 0x0f, 0x9a, 0x4a, 0x0c, 0x0a, 0x0a, 0x0a, 0x01, 0x62, 0x6a, 0x05, + 0x0a, 0x03, 0x41, 0x2e, 0x42, 0x22, 0xe6, 0x01, 0x0a, 0x04, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x2f, + 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x66, + 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x09, + 0x9a, 0x4a, 0x06, 0x12, 0x04, 0x75, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x3a, + 0x6d, 0x9a, 0x4a, 0x6a, 0x0a, 0x3c, 0x0a, 0x03, 0x72, 0x65, 0x73, 0x72, 0x35, 0x0a, 0x18, 0x70, + 0x6f, 0x73, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, + 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0a, 0x0a, 0x02, 0x69, 0x64, 0x12, 0x04, 0x24, + 0x2e, 0x69, 0x64, 0x1a, 0x03, 0x31, 0x30, 0x73, 0x22, 0x08, 0x0a, 0x06, 0x0a, 0x02, 0x32, 0x73, + 0x10, 0x03, 0x0a, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x5a, 0x08, 0x72, 0x65, + 0x73, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x0a, 0x16, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x6a, 0x0e, + 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x06, 0x1a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x22, 0xc8, + 0x04, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x05, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x66, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, + 0x65, 0x6d, 0x73, 0x12, 0x37, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2f, 0x0a, 0x06, + 0x61, 0x74, 0x74, 0x72, 0x5f, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x66, + 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x41, + 0x74, 0x74, 0x72, 0x41, 0x48, 0x00, 0x52, 0x05, 0x61, 0x74, 0x74, 0x72, 0x41, 0x12, 0x26, 0x0a, + 0x01, 0x62, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x42, + 0x48, 0x00, 0x52, 0x01, 0x62, 0x1a, 0x50, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x2f, 0x0a, 0x05, 0x41, 0x74, 0x74, 0x72, 0x41, + 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, + 0x6f, 0x6f, 0x3a, 0x14, 0x9a, 0x4a, 0x11, 0x1a, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x41, 0x1a, 0x2f, 0x0a, 0x05, 0x41, 0x74, 0x74, 0x72, + 0x42, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, + 0x62, 0x61, 0x72, 0x3a, 0x14, 0x9a, 0x4a, 0x11, 0x1a, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x42, 0x3a, 0xa5, 0x01, 0x9a, 0x4a, 0xa1, 0x01, + 0x0a, 0x8a, 0x01, 0x0a, 0x03, 0x72, 0x65, 0x73, 0x72, 0x82, 0x01, 0x0a, 0x18, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0f, 0x0a, 0x02, 0x69, 0x64, 0x12, 0x09, 0x24, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x27, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x54, 0x79, + 0x70, 0x65, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x27, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x31, 0x27, 0x29, 0x1a, 0x03, 0x32, 0x30, 0x73, 0x22, 0x1f, 0x12, 0x1d, + 0x0a, 0x02, 0x31, 0x73, 0x11, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x3f, 0x19, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0xfb, 0x3f, 0x22, 0x03, 0x33, 0x30, 0x73, 0x28, 0x03, 0x0a, 0x12, 0x0a, + 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x5a, 0x08, 0x72, 0x65, 0x73, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x42, 0x06, 0x0a, 0x04, 0x61, 0x74, 0x74, 0x72, 0x22, 0x8d, 0x05, 0x0a, 0x04, 0x49, 0x74, + 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x6c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0xf1, 0x02, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x61, 0x64, 0x64, 0x72, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x32, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, 0x32, 0x12, 0x38, 0x0a, 0x06, 0x61, + 0x64, 0x64, 0x72, 0x5f, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x66, 0x65, + 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x41, 0x48, 0x00, 0x52, 0x05, + 0x61, 0x64, 0x64, 0x72, 0x41, 0x12, 0x2f, 0x0a, 0x01, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x74, + 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x72, + 0x42, 0x48, 0x00, 0x52, 0x01, 0x62, 0x1a, 0x38, 0x0a, 0x05, 0x41, 0x64, 0x64, 0x72, 0x41, 0x12, + 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x66, 0x6f, + 0x6f, 0x3a, 0x1d, 0x9a, 0x4a, 0x1a, 0x1a, 0x18, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, + 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x41, + 0x1a, 0x38, 0x0a, 0x05, 0x41, 0x64, 0x64, 0x72, 0x42, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x62, 0x61, 0x72, 0x3a, 0x1d, 0x9a, 0x4a, 0x1a, + 0x1a, 0x18, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x42, 0x22, 0x38, 0x0a, 0x0c, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, + 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x30, 0x10, 0x00, 0x12, + 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x31, 0x10, 0x01, 0x3a, 0x17, 0x9a, 0x4a, 0x14, 0x1a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x2e, + 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x07, 0x0a, + 0x05, 0x61, 0x64, 0x64, 0x72, 0x33, 0x22, 0x71, 0x0a, 0x08, 0x49, 0x74, 0x65, 0x6d, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, + 0x0b, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x0f, + 0x0a, 0x0b, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x32, 0x10, 0x02, 0x12, + 0x0f, 0x0a, 0x0b, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x33, 0x10, 0x03, + 0x1a, 0x17, 0x9a, 0x4a, 0x14, 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, + 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x0e, 0x9a, 0x4a, 0x0b, 0x1a, 0x09, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x32, 0x5e, 0x0a, 0x11, 0x46, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x44, + 0x0a, 0x07, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x2e, 0x66, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x1a, 0x03, 0x9a, 0x4a, 0x00, 0x42, 0xad, 0x01, 0x9a, 0x4a, 0x22, 0x12, + 0x0f, 0x70, 0x6f, 0x73, 0x74, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x42, 0x0f, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x66, 0x65, + 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0xa2, 0x02, 0x03, 0x46, 0x58, 0x58, 0xaa, 0x02, 0x0a, 0x46, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xca, 0x02, 0x0a, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0xe2, 0x02, 0x16, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0a, 0x46, + 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/_examples/02_simple/federation/federation_grpc_federation.pb.go b/_examples/02_simple/federation/federation_grpc_federation.pb.go index a7290653..3fa18222 100644 --- a/_examples/02_simple/federation/federation_grpc_federation.pb.go +++ b/_examples/02_simple/federation/federation_grpc_federation.pb.go @@ -58,6 +58,7 @@ type FederationService_Federation_GetPostResponseArgument struct { RandSource *grpcfedcel.Source SortedItems []*user.Item SortedValues []int64 + StringsJoin string Uuid *grpcfedcel.UUID Value1 string } @@ -665,7 +666,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte type localValueType struct { *grpcfed.LocalValue vars struct { - _def13 bool + _def14 bool a *A date *grpcfedcel.Time fixed_rand *grpcfedcel.Rand @@ -677,6 +678,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte rand_source *grpcfedcel.Source sorted_items []*user.Item sorted_values []int64 + strings_join string uuid *grpcfedcel.UUID value1 string } @@ -685,7 +687,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte // A tree view of message dependencies is shown below. /* post ─┐ - _def13 ─┐ + _def14 ─┐ a ─┤ loc ─┐ │ jp_time ─┤ @@ -693,6 +695,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte null_value ─┤ sorted_items ─┤ sorted_values ─┤ + strings_join ─┤ date ─┐ │ rand_source ─┐ │ fixed_rand ─┐ │ @@ -748,15 +751,15 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte // This section's codes are generated by the following proto definition. /* def { - name: "_def13" + name: "_def14" by: "grpc.federation.log.info('output federation log', {'post_message': post})" } */ if err := grpcfed.EvalDef(ctx1, value, grpcfed.Def[bool, *localValueType]{ - Name: `_def13`, + Name: `_def14`, Type: grpcfed.CELBoolType, Setter: func(value *localValueType, v bool) error { - value.vars._def13 = v + value.vars._def14 = v return nil }, By: `grpc.federation.log.info('output federation log', {'post_message': post})`, @@ -947,6 +950,31 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte return nil, nil }) + grpcfed.GoWithRecover(eg, func() (any, error) { + + // This section's codes are generated by the following proto definition. + /* + def { + name: "strings_join" + by: "grpc.federation.strings.join(['a', 'b', 'c'], ',')" + } + */ + if err := grpcfed.EvalDef(ctx1, value, grpcfed.Def[string, *localValueType]{ + Name: `strings_join`, + Type: grpcfed.CELStringType, + Setter: func(value *localValueType, v string) error { + value.vars.strings_join = v + return nil + }, + By: `grpc.federation.strings.join(['a', 'b', 'c'], ',')`, + ByCacheIndex: 20, + }); err != nil { + grpcfed.RecordErrorToSpan(ctx1, err) + return nil, err + } + return nil, nil + }) + grpcfed.GoWithRecover(eg, func() (any, error) { // This section's codes are generated by the following proto definition. @@ -964,7 +992,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte return nil }, By: `grpc.federation.time.date(2023, 12, 25, 12, 10, 5, 0, grpc.federation.time.UTC())`, - ByCacheIndex: 20, + ByCacheIndex: 21, }); err != nil { grpcfed.RecordErrorToSpan(ctx1, err) return nil, err @@ -985,7 +1013,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte return nil }, By: `grpc.federation.rand.newSource(date.unix())`, - ByCacheIndex: 21, + ByCacheIndex: 22, }); err != nil { grpcfed.RecordErrorToSpan(ctx1, err) return nil, err @@ -1006,7 +1034,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte return nil }, By: `grpc.federation.rand.new(rand_source)`, - ByCacheIndex: 22, + ByCacheIndex: 23, }); err != nil { grpcfed.RecordErrorToSpan(ctx1, err) return nil, err @@ -1027,7 +1055,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte return nil }, By: `.grpc.federation.uuid.newRandomFromRand(fixed_rand)`, - ByCacheIndex: 23, + ByCacheIndex: 24, }); err != nil { grpcfed.RecordErrorToSpan(ctx1, err) return nil, err @@ -1052,7 +1080,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte return nil }, By: `grpc.federation.metadata.incoming()['key1'][0]`, - ByCacheIndex: 24, + ByCacheIndex: 25, }); err != nil { grpcfed.RecordErrorToSpan(ctx1, err) return nil, err @@ -1076,6 +1104,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte req.RandSource = value.vars.rand_source req.SortedItems = value.vars.sorted_items req.SortedValues = value.vars.sorted_values + req.StringsJoin = value.vars.strings_join req.Uuid = value.vars.uuid req.Value1 = value.vars.value1 @@ -1087,7 +1116,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*Post]{ Value: value, Expr: `post`, - CacheIndex: 25, + CacheIndex: 26, Setter: func(v *Post) error { ret.Post = v return nil @@ -1100,7 +1129,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `'hello'`, - CacheIndex: 26, + CacheIndex: 27, Setter: func(v string) error { ret.Str = v return nil @@ -1113,7 +1142,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `uuid.string()`, - CacheIndex: 27, + CacheIndex: 28, Setter: func(v string) error { ret.Uuid = v return nil @@ -1126,7 +1155,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `loc.string()`, - CacheIndex: 28, + CacheIndex: 29, Setter: func(v string) error { ret.Loc = v return nil @@ -1139,7 +1168,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `value1`, - CacheIndex: 29, + CacheIndex: 30, Setter: func(v string) error { ret.Value1 = v return nil @@ -1152,7 +1181,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `Item.ItemType.name(Item.ItemType.ITEM_TYPE_1)`, - CacheIndex: 30, + CacheIndex: 31, Setter: func(v string) error { ret.ItemTypeName = v return nil @@ -1165,7 +1194,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `Item.Location.LocationType.name(Item.Location.LocationType.LOCATION_TYPE_1)`, - CacheIndex: 31, + CacheIndex: 32, Setter: func(v string) error { ret.LocationTypeName = v return nil @@ -1178,7 +1207,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `user.Item.ItemType.name(user.Item.ItemType.ITEM_TYPE_2)`, - CacheIndex: 32, + CacheIndex: 33, Setter: func(v string) error { ret.UserItemTypeName = v return nil @@ -1191,7 +1220,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[user.Item_ItemType]{ Value: value, Expr: `user.Item.ItemType.value('ITEM_TYPE_1')`, - CacheIndex: 33, + CacheIndex: 34, Setter: func(v user.Item_ItemType) error { itemTypeValueEnumValue, err := s.cast_User_Item_ItemType__to__Federation_Item_ItemType(v) if err != nil { @@ -1208,7 +1237,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[user.Item_ItemType]{ Value: value, Expr: `user.Item.ItemType.value('ITEM_TYPE_1')`, - CacheIndex: 34, + CacheIndex: 35, Setter: func(v user.Item_ItemType) error { itemTypeValueIntValue, err := s.cast_User_Item_ItemType__to__int32(v) if err != nil { @@ -1225,7 +1254,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[Item_ItemType]{ Value: value, Expr: `1`, - CacheIndex: 35, + CacheIndex: 36, Setter: func(v Item_ItemType) error { ret.ItemTypeValueCast = v return nil @@ -1238,7 +1267,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[Item_Location_LocationType]{ Value: value, Expr: `Item.Location.LocationType.value('LOCATION_TYPE_1')`, - CacheIndex: 36, + CacheIndex: 37, Setter: func(v Item_Location_LocationType) error { locationTypeValueValue, err := s.cast_Federation_Item_Location_LocationType__to__int32(v) if err != nil { @@ -1255,7 +1284,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[user.Item_ItemType]{ Value: value, Expr: `user.Item.ItemType.value('ITEM_TYPE_2')`, - CacheIndex: 37, + CacheIndex: 38, Setter: func(v user.Item_ItemType) error { userItemTypeValueValue, err := s.cast_User_Item_ItemType__to__int32(v) if err != nil { @@ -1272,7 +1301,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*A]{ Value: value, Expr: `a`, - CacheIndex: 38, + CacheIndex: 39, Setter: func(v *A) error { ret.A = v return nil @@ -1285,7 +1314,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[[]int32]{ Value: value, Expr: `sorted_values`, - CacheIndex: 39, + CacheIndex: 40, Setter: func(v []int32) error { ret.SortedValues = v return nil @@ -1298,7 +1327,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[[]*user.Item]{ Value: value, Expr: `sorted_items`, - CacheIndex: 40, + CacheIndex: 41, Setter: func(v []*user.Item) error { sortedItemsValue, err := s.cast_repeated_User_Item__to__repeated_Federation_Item(v) if err != nil { @@ -1315,7 +1344,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[map[int64]string]{ Value: value, Expr: `map_value`, - CacheIndex: 41, + CacheIndex: 42, Setter: func(v map[int64]string) error { mapValueValue, err := s.cast_map_int64_string__to__map_int32_string(v) if err != nil { @@ -1332,7 +1361,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.DoubleValue]{ Value: value, Expr: `google.protobuf.DoubleValue{value: 1.23}`, - CacheIndex: 42, + CacheIndex: 43, Setter: func(v *wrapperspb.DoubleValue) error { doubleWrapperValueValue, err := s.cast_Google_Protobuf_DoubleValue__to__Google_Protobuf_DoubleValue(v) if err != nil { @@ -1349,7 +1378,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.DoubleValue]{ Value: value, Expr: `google.protobuf.FloatValue{value: 3.45}`, - CacheIndex: 43, + CacheIndex: 44, Setter: func(v *wrapperspb.DoubleValue) error { floatWrapperValueValue, err := s.cast_Google_Protobuf_DoubleValue__to__Google_Protobuf_FloatValue(v) if err != nil { @@ -1366,7 +1395,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.Int64Value]{ Value: value, Expr: `google.protobuf.Int64Value{value: 1}`, - CacheIndex: 44, + CacheIndex: 45, Setter: func(v *wrapperspb.Int64Value) error { i64WrapperValueValue, err := s.cast_Google_Protobuf_Int64Value__to__Google_Protobuf_Int64Value(v) if err != nil { @@ -1383,7 +1412,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.UInt64Value]{ Value: value, Expr: `google.protobuf.UInt64Value{value: uint(2)}`, - CacheIndex: 45, + CacheIndex: 46, Setter: func(v *wrapperspb.UInt64Value) error { u64WrapperValueValue, err := s.cast_Google_Protobuf_UInt64Value__to__Google_Protobuf_UInt64Value(v) if err != nil { @@ -1400,7 +1429,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.Int64Value]{ Value: value, Expr: `google.protobuf.Int32Value{value: 3}`, - CacheIndex: 46, + CacheIndex: 47, Setter: func(v *wrapperspb.Int64Value) error { i32WrapperValueValue, err := s.cast_Google_Protobuf_Int64Value__to__Google_Protobuf_Int32Value(v) if err != nil { @@ -1417,7 +1446,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.UInt64Value]{ Value: value, Expr: `google.protobuf.UInt32Value{value: uint(4)}`, - CacheIndex: 47, + CacheIndex: 48, Setter: func(v *wrapperspb.UInt64Value) error { u32WrapperValueValue, err := s.cast_Google_Protobuf_UInt64Value__to__Google_Protobuf_UInt32Value(v) if err != nil { @@ -1434,7 +1463,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.BoolValue]{ Value: value, Expr: `google.protobuf.BoolValue{value: true}`, - CacheIndex: 48, + CacheIndex: 49, Setter: func(v *wrapperspb.BoolValue) error { boolWrapperValueValue, err := s.cast_Google_Protobuf_BoolValue__to__Google_Protobuf_BoolValue(v) if err != nil { @@ -1451,7 +1480,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.StringValue]{ Value: value, Expr: `google.protobuf.StringValue{value: 'hello'}`, - CacheIndex: 49, + CacheIndex: 50, Setter: func(v *wrapperspb.StringValue) error { stringWrapperValueValue, err := s.cast_Google_Protobuf_StringValue__to__Google_Protobuf_StringValue(v) if err != nil { @@ -1468,7 +1497,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*wrapperspb.BytesValue]{ Value: value, Expr: `google.protobuf.BytesValue{value: bytes('world')}`, - CacheIndex: 50, + CacheIndex: 51, Setter: func(v *wrapperspb.BytesValue) error { bytesWrapperValueValue, err := s.cast_Google_Protobuf_BytesValue__to__Google_Protobuf_BytesValue(v) if err != nil { @@ -1485,7 +1514,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `'hello\nworld'`, - CacheIndex: 51, + CacheIndex: 52, Setter: func(v string) error { ret.Hello = v return nil @@ -1498,7 +1527,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*timestamppb.Timestamp]{ Value: value, Expr: `null`, - CacheIndex: 52, + CacheIndex: 53, Setter: func(v *timestamppb.Timestamp) error { ret.NullTimestamp = v return nil @@ -1511,7 +1540,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*timestamppb.Timestamp]{ Value: value, Expr: `null_value`, - CacheIndex: 53, + CacheIndex: 54, Setter: func(v *timestamppb.Timestamp) error { ret.NullTimestamp2 = v return nil @@ -1524,7 +1553,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*timestamppb.Timestamp]{ Value: value, Expr: `true ? null : google.protobuf.Timestamp{}`, - CacheIndex: 54, + CacheIndex: 55, Setter: func(v *timestamppb.Timestamp) error { ret.NullTimestamp3 = v return nil @@ -1537,7 +1566,7 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `jp_time.location().string()`, - CacheIndex: 55, + CacheIndex: 56, Setter: func(v string) error { ret.JpLoc = v return nil @@ -1546,6 +1575,19 @@ func (s *FederationService) resolve_Federation_GetPostResponse(ctx context.Conte grpcfed.RecordErrorToSpan(ctx, err) return nil, err } + // (grpc.federation.field).by = "strings_join" + if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ + Value: value, + Expr: `strings_join`, + CacheIndex: 57, + Setter: func(v string) error { + ret.StringsJoin = v + return nil + }, + }); err != nil { + grpcfed.RecordErrorToSpan(ctx, err) + return nil, err + } grpcfed.Logger(ctx).DebugContext(ctx, "resolved federation.GetPostResponse", slog.Any("federation.GetPostResponse", s.logvalue_Federation_GetPostResponse(ret))) return ret, nil @@ -1591,7 +1633,7 @@ func (s *FederationService) resolve_Federation_Post(ctx context.Context, req *Fe if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `$.id`, - CacheIndex: 56, + CacheIndex: 58, Setter: func(v string) error { args.Id = v return nil @@ -1607,7 +1649,7 @@ func (s *FederationService) resolve_Federation_Post(ctx context.Context, req *Fe return grpcfed.WithRetry(ctx, &grpcfed.RetryParam[post.GetPostResponse]{ Value: value, If: `true`, - CacheIndex: 57, + CacheIndex: 59, BackOff: b, Body: func() (*post.GetPostResponse, error) { return s.client.Post_PostServiceClient.GetPost(ctx, args) @@ -1642,7 +1684,7 @@ func (s *FederationService) resolve_Federation_Post(ctx context.Context, req *Fe return nil }, By: `res.post`, - ByCacheIndex: 58, + ByCacheIndex: 60, }); err != nil { grpcfed.RecordErrorToSpan(ctx, err) return nil, err @@ -1671,7 +1713,7 @@ func (s *FederationService) resolve_Federation_Post(ctx context.Context, req *Fe if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*post.Post]{ Value: value, Expr: `post`, - CacheIndex: 59, + CacheIndex: 61, Setter: func(v *post.Post) error { args.Id = v.GetId() args.Title = v.GetTitle() @@ -1709,7 +1751,7 @@ func (s *FederationService) resolve_Federation_Post(ctx context.Context, req *Fe if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[*User]{ Value: value, Expr: `user`, - CacheIndex: 60, + CacheIndex: 62, Setter: func(v *User) error { ret.User = v return nil @@ -1765,7 +1807,7 @@ func (s *FederationService) resolve_Federation_User(ctx context.Context, req *Fe if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[string]{ Value: value, Expr: `$.user_id`, - CacheIndex: 61, + CacheIndex: 63, Setter: func(v string) error { args.Id = v return nil @@ -1777,7 +1819,7 @@ func (s *FederationService) resolve_Federation_User(ctx context.Context, req *Fe if err := grpcfed.SetCELValue(ctx, &grpcfed.SetCELValueParam[user.Item_ItemType]{ Value: value, Expr: `user.Item.ItemType.value('ITEM_TYPE_1')`, - CacheIndex: 62, + CacheIndex: 64, Setter: func(v user.Item_ItemType) error { typeValue, err := s.cast_User_Item_ItemType__to__int32(v) if err != nil { @@ -1803,7 +1845,7 @@ func (s *FederationService) resolve_Federation_User(ctx context.Context, req *Fe return grpcfed.WithRetry(ctx, &grpcfed.RetryParam[user.GetUserResponse]{ Value: value, If: `true`, - CacheIndex: 63, + CacheIndex: 65, BackOff: b, Body: func() (*user.GetUserResponse, error) { return s.client.User_UserServiceClient.GetUser(ctx, args) @@ -1838,7 +1880,7 @@ func (s *FederationService) resolve_Federation_User(ctx context.Context, req *Fe return nil }, By: `res.user`, - ByCacheIndex: 64, + ByCacheIndex: 66, }); err != nil { grpcfed.RecordErrorToSpan(ctx, err) return nil, err @@ -2343,6 +2385,7 @@ func (s *FederationService) logvalue_Federation_GetPostResponse(v *GetPostRespon slog.Any("null_timestamp2", s.logvalue_Google_Protobuf_Timestamp(v.GetNullTimestamp2())), slog.Any("null_timestamp3", s.logvalue_Google_Protobuf_Timestamp(v.GetNullTimestamp3())), slog.String("jp_loc", v.GetJpLoc()), + slog.String("strings_join", v.GetStringsJoin()), ) } diff --git a/_examples/02_simple/main_test.go b/_examples/02_simple/main_test.go index 350538ca..05c702e4 100644 --- a/_examples/02_simple/main_test.go +++ b/_examples/02_simple/main_test.go @@ -316,6 +316,7 @@ func TestFederation(t *testing.T) { NullTimestamp2: nil, NullTimestamp3: nil, JpLoc: "JST", + StringsJoin: "a,b,c", }, cmpopts.IgnoreUnexported( federation.GetPostResponse{}, federation.Post{}, diff --git a/_examples/02_simple/proto/federation/federation.proto b/_examples/02_simple/proto/federation/federation.proto index 0b861b40..d22b788d 100644 --- a/_examples/02_simple/proto/federation/federation.proto +++ b/_examples/02_simple/proto/federation/federation.proto @@ -31,6 +31,7 @@ message GetPostResponse { args { name: "id", by: "$.id" } } } + def { name: "strings_join" by: "grpc.federation.strings.join(['a', 'b', 'c'], ',')" } def { name: "date" by: "grpc.federation.time.date(2023, 12, 25, 12, 10, 5, 0, grpc.federation.time.UTC())" } def { name: "rand_source" by: "grpc.federation.rand.newSource(date.unix())" } def { name: "fixed_rand" by: "grpc.federation.rand.new(rand_source)" } @@ -76,6 +77,7 @@ message GetPostResponse { google.protobuf.Timestamp null_timestamp2 = 29 [(grpc.federation.field).by = "null_value"]; google.protobuf.Timestamp null_timestamp3 = 30 [(grpc.federation.field).by = "true ? null : google.protobuf.Timestamp{}"]; string jp_loc = 31 [(grpc.federation.field).by = "jp_time.location().string()"]; + string strings_join = 32 [(grpc.federation.field).by = "strings_join"]; } message A { From 4ec156e0b23241e28dd9110678c6e03cffd5c9c9 Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Fri, 20 Sep 2024 20:17:41 +0900 Subject: [PATCH 05/10] =?UTF-8?q?=F0=9F=93=9D=20add=20strings.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/cel/strings.md | 716 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 716 insertions(+) create mode 100644 docs/cel/strings.md diff --git a/docs/cel/strings.md b/docs/cel/strings.md new file mode 100644 index 00000000..9d002d6b --- /dev/null +++ b/docs/cel/strings.md @@ -0,0 +1,716 @@ +# grpc.federation.strings APIs + +The API for this package was created based on Go's [`strings`](https://pkg.go.dev/strings) package. + +# Index + +## Functions + +- [`clone`](#clone) +- [`compare`](#compare) +- [`contains`](#contains) +- [`containsAny`](#containsAny) +- [`containsRune`](#containsRune) +- [`count`](#count) +- [`cutPrefix`](#cutPrefix) +- [`cutSuffix`](#cutSuffix) +- [`equalFold`](#equalFold) +- [`fields`](#fields) +- [`hasPrefix`](#hasPrefix) +- [`hasSuffix`](#hasSuffix) +- [`index`](#index) +- [`indexAny`](#indexAny) +- [`indexByte`](#indexByte) +- [`indexRune`](#indexRune) +- [`join`](#join) +- [`lastIndex`](#lastIndex) +- [`lastIndexAny`](#lastIndexAny) +- [`lastIndexByte`](#lastIndexByte) +- [`repeat`](#repeat) +- [`replace`](#replace) +- [`replaceAll`](#replaceAll) +- [`split`](#split) +- [`splitAfter`](#splitAfter) +- [`splitAfterN`](#splitAfterN) +- [`splitN`](#splitN) +- [`title`](#title) +- [`toLower`](#toLower) +- [`toTitle`](#toTitle) +- [`toUpper`](#toUpper) +- [`toValidUTF8`](#toValidUTF8) +- [`trim`](#trim) +- [`trimLeft`](#trimLeft) +- [`trimPrefix`](#trimPrefix) +- [`trimRight`](#trimRight) +- [`trimSpace`](#trimSpace) +- [`trimSuffix`](#trimSuffix) + +# Functions + +## clone + +`clone` returns a copy of the input string. + +### Parameters + +`clone(s string) string` + +- `s`: the input string to be cloned. + +### Examples + +```cel +grpc.federation.strings.clone("hello") //=> "hello" +``` + +## compare + +`compare` compares two strings lexicographically. It returns an integer comparing `a` and `b` lexicographically. + +### Parameters + +`compare(a string, b string) int` + +- `a`: first string. +- `b`: second string. + +### Examples + +```cel +grpc.federation.strings.compare("a", "b") //=> -1 +grpc.federation.strings.compare("a", "a") //=> 0 +grpc.federation.strings.compare("b", "a") //=> 1 +``` + +## contains + +`contains` reports whether `substr` is within `s`. + +### Parameters + +`contains(s string, substr string) bool` + +- `s`: the string to search within. +- `substr`: the substring to search for. + +### Examples + +```cel +grpc.federation.strings.contains("hello", "ll") //=> true +grpc.federation.strings.contains("hello", "world") //=> false +``` + +## containsAny + +`containsAny` reports whether any of the Unicode code points in `chars` are within `s`. + +### Parameters + +`containsAny(s string, chars string) bool` + +- `s`: the string to search within. +- `chars`: the set of characters to search for. + +### Examples + +```cel +grpc.federation.strings.containsAny("hello", "xyz") //=> false +grpc.federation.strings.containsAny("hello", "e") //=> true +``` + +## containsRune + +`containsRune` reports whether the Unicode code point `r` is within `s`. + +### Parameters + +`containsRune(s string, r int) bool` + +- `s`: the string to search within. +- `r`: the rune (Unicode code point) to search for. + +### Examples + +```cel +grpc.federation.strings.containsRune("hello", 101) //=> true ('e') +grpc.federation.strings.containsRune("hello", 120) //=> false ('x') +``` + +## count + +`count` returns the number of non-overlapping instances of `substr` in `s`. + +### Parameters + +`count(s string, substr string) int` + +- `s`: the string to search within. +- `substr`: the substring to search for. + +### Examples + +```cel +grpc.federation.strings.count("cheese", "e") //=> 3 +grpc.federation.strings.count("five", "ve") //=> 1 +``` + +## cutPrefix + +`cutPrefix` returns the string `s` after removing the provided `prefix`. If the string doesn't start with `prefix`, `s` is returned unchanged. + +### Parameters + +`cutPrefix(s string, prefix string) string` + +- `s`: the string to cut the prefix from. +- `prefix`: the prefix to cut. + +### Examples + +```cel +grpc.federation.strings.cutPrefix("hello", "he") //=> "llo" +grpc.federation.strings.cutPrefix("hello", "wo") //=> "hello" +``` + +## cutSuffix + +`cutSuffix` returns the string `s` after removing the provided `suffix`. If the string doesn't end with `suffix`, `s` is returned unchanged. + +### Parameters + +`cutSuffix(s string, suffix string) string` + +- `s`: the string to cut the suffix from. +- `suffix`: the suffix to cut. + +### Examples + +```cel +grpc.federation.strings.cutSuffix("hello", "lo") //=> "hel" +grpc.federation.strings.cutSuffix("hello", "wo") //=> "hello" +``` + +## equalFold + +`equalFold` reports whether `s` and `t` are equal under Unicode case-folding. + +### Parameters + +`equalFold(s string, t string) bool` + +- `s`: first string. +- `t`: second string. + +### Examples + +```cel +grpc.federation.strings.equalFold("Go", "go") //=> true +grpc.federation.strings.equalFold("Go", "Java") //=> false +``` + +## fields + +`fields` splits the string `s` around each instance of one or more consecutive white space characters, returning a slice of substrings. + +### Parameters + +`fields(s string) []string` + +- `s`: the string to split into fields. + +### Examples + +```cel +grpc.federation.strings.fields("hello world") //=> ["hello", "world"] +grpc.federation.strings.fields(" leading spaces") //=> ["leading", "spaces"] +``` + +## hasPrefix + +`hasPrefix` tests whether the string `s` begins with `prefix`. + +### Parameters + +`hasPrefix(s string, prefix string) bool` + +- `s`: the string to check. +- `prefix`: the prefix to check for. + +### Examples + +```cel +grpc.federation.strings.hasPrefix("hello", "he") //=> true +grpc.federation.strings.hasPrefix("hello", "wo") //=> false +``` + +## hasSuffix + +`hasSuffix` tests whether the string `s` ends with `suffix`. + +### Parameters + +`hasSuffix(s string, suffix string) bool` + +- `s`: the string to check. +- `suffix`: the suffix to check for. + +### Examples + +```cel +grpc.federation.strings.hasSuffix("hello", "lo") //=> true +grpc.federation.strings.hasSuffix("hello", "he") //=> false +``` + +## index + +`index` returns the index of the first instance of `substr` in `s`, or `-1` if `substr` is not present in `s`. + +### Parameters + +`index(s string, substr string) int` + +- `s`: the string to search within. +- `substr`: the substring to search for. + +### Examples + +```cel +grpc.federation.strings.index("hello", "ll") //=> 2 +grpc.federation.strings.index("hello", "xx") //=> -1 +``` + +## indexAny + +`indexAny` returns the index of the first instance of any Unicode code point from `chars` in `s`, or `-1` if no Unicode code point from `chars` is present in `s`. + +### Parameters + +`indexAny(s string, chars string) int` + +- `s`: the string to search within. +- `chars`: the string containing characters to search for. + +### Examples + +```cel +grpc.federation.strings.indexAny("hello", "aeiou") //=> 1 +grpc.federation.strings.indexAny("hello", "xyz") //=> -1 +``` + +## indexByte + +`indexByte` returns the index of the first instance of `byte` in `s`, or `-1` if `byte` is not present. + +### Parameters + +`indexByte(s string, b byte) int` + +- `s`: the string to search within. +- `b`: the byte to search for. + +### Examples + +```cel +grpc.federation.strings.indexByte("hello", 'e') //=> 1 +grpc.federation.strings.indexByte("hello", 'x') //=> -1 +``` + +## indexRune + +`indexRune` returns the index of the first instance of the rune `r` in `s`, or `-1` if `r` is not present. + +### Parameters + +`indexRune(s string, r int) int` + +- `s`: the string to search within. +- `r`: the rune (Unicode code point) to search for. + +### Examples + +```cel +grpc.federation.strings.indexRune("hello", 101) //=> 1 ('e') +grpc.federation.strings.indexRune("hello", 120) //=> -1 ('x') +``` + +## join + +`join` concatenates the elements of the list `elems` to create a single string. The separator string `sep` is placed between elements in the resulting string. + +### Parameters + +`join(elems []string, sep string) string` + +- `elems`: the list of strings to join. +- `sep`: the separator string. + +### Examples + +```cel +grpc.federation.strings.join(["foo", "bar", "baz"], ", ") //=> "foo, bar, baz" +``` + +## lastIndex + +`lastIndex` returns the index of the last instance of `substr` in `s`, or `-1` if `substr` is not present. + +### Parameters + +`lastIndex(s string, substr string) int` + +- `s`: the string to search within. +- `substr`: the substring to search for. + +### Examples + +```cel +grpc.federation.strings.lastIndex("go gophers", "go") //=> 3 +grpc.federation.strings.lastIndex("hello", "world") //=> -1 +``` + +## lastIndexAny + +`lastIndexAny` returns the index of the last instance of any Unicode code point from `chars` in `s`, or `-1` if no Unicode code point from `chars` is present in `s`. + +### Parameters + +`lastIndexAny(s string, chars string) int` + +- `s`: the string to search within. +- `chars`: the string containing characters to search for. + +### Examples + +```cel +grpc.federation.strings.lastIndexAny("hello", "aeiou") //=> 4 +grpc.federation.strings.lastIndexAny("hello", "xyz") //=> -1 +``` + +## lastIndexByte + +`lastIndexByte` returns the index of the last instance of `byte` in `s`, or `-1` if `byte` is not present. + +### Parameters + +`lastIndexByte(s string, b byte) int` + +- `s`: the string to search within. +- `b`: the byte to search for. + +### Examples + +```cel +grpc.federation.strings.lastIndexByte("hello", 'e') //=> 1 +grpc.federation.strings.lastIndexByte("hello", 'x') //=> -1 +``` + +## repeat + +`repeat` returns a new string consisting of `count` copies of the string `s`. + +### Parameters + +`repeat(s string, count int) string` + +- `s`: the string to repeat. +- `count`: the number of times to repeat the string. + +### Examples + +```cel +grpc.federation.strings.repeat("ha", 3) //=> "hahaha" +grpc.federation.strings.repeat("ha", 0) //=> "" +``` + +## replace + +`replace` returns a copy of the string `s` with the first `n` non-overlapping instances of `old` replaced by `new`. If `n` is negative, all instances are replaced. + +### Parameters + +`replace(s string, old string, new string, n int) string` + +- `s`: the string to modify. +- `old`: the substring to replace. +- `new`: the replacement substring. +- `n`: the number of instances to replace (or -1 for all). + +### Examples + +```cel +grpc.federation.strings.replace("foo bar foo", "foo", "baz", 1) //=> "baz bar foo" +grpc.federation.strings.replace("foo bar foo", "foo", "baz", -1) //=> "baz bar baz" +``` + +## replaceAll + +`replaceAll` returns a copy of the string `s` with all non-overlapping instances of `old` replaced by `new`. + +### Parameters + +`replaceAll(s string, old string, new string) string` + +- `s`: the string to modify. +- `old`: the substring to replace. +- `new`: the replacement substring. + +### Examples + +```cel +grpc.federation.strings.replaceAll("foo bar foo", "foo", "baz") //=> "baz bar baz" +``` + +## split + +`split` slices `s` into all substrings separated by `sep` and returns a slice of the substrings. + +### Parameters + +`split(s string, sep string) []string` + +- `s`: the string to split. +- `sep`: the separator string. + +### Examples + +```cel +grpc.federation.strings.split("a,b,c", ",") //=> ["a", "b", "c"] +grpc.federation.strings.split("a b c", " ") //=> ["a", "b", "c"] +``` + +## splitAfter + +`splitAfter` slices `s` into all substrings after each instance of `sep` and returns a slice of the substrings. + +### Parameters + +`splitAfter(s string, sep string) []string` + +- `s`: the string to split. +- `sep`: the separator string. + +### Examples + +```cel +grpc.federation.strings.splitAfter("a,b,c", ",") //=> ["a,", "b,", "c"] +``` + +## splitAfterN + +`splitAfterN` slices `s` into `n` substrings after each instance of `sep` and returns a slice of the substrings. + +### Parameters + +`splitAfterN(s string, sep string, n int) []string` + +- `s`: the string to split. +- `sep`: the separator string. +- `n`: the maximum number of substrings to return. + +### Examples + +```cel +grpc.federation.strings.splitAfterN("a,b,c", ",", 2) //=> ["a,", "b,c"] +``` + +## splitN + +`splitN` slices `s` into `n` substrings separated by `sep` and returns a slice of the substrings. + +### Parameters + +`splitN(s string, sep string, n int) []string` + +- `s`: the string to split. +- `sep`: the separator string. +- `n`: the maximum number of substrings to return. + +### Examples + +```cel +grpc.federation.strings.splitN("a,b,c", ",", 2) //=> ["a", "b,c"] +``` + +## title + +`title` returns a copy of the string `s` with all Unicode letters that begin words mapped to their title case. + +### Parameters + +`title(s string) string` + +- `s`: the string to convert to title case. + +### Examples + +```cel +grpc.federation.strings.title("hello world") //=> "Hello World" +``` + +## toLower + +`toLower` returns a copy of the string `s` with all Unicode letters mapped to their lower case. + +### Parameters + +`toLower(s string) string` + +- `s`: the string to convert to lower case. + +### Examples + +```cel +grpc.federation.strings.toLower("HELLO") //=> "hello" +``` + +## toTitle + +`toTitle` returns a copy of the string `s` with all Unicode letters mapped to their title case. + +### Parameters + +`toTitle(s string) string` + +- `s`: the string to convert to title case. + +### Examples + +```cel +grpc.federation.strings.toTitle("hello") //=> "Hello" +``` + +## toUpper + +`toUpper` returns a copy of the string `s` with all Unicode letters mapped to their upper case. + +### Parameters + +`toUpper(s string) string` + +- `s`: the string to convert to upper case. + +### Examples + +```cel +grpc.federation.strings.toUpper("hello") //=> "HELLO" +``` + +## toValidUTF8 + +`toValidUTF8` returns a copy of the string `s` with each run of invalid UTF-8 byte sequences replaced by the replacement string, which may be empty. + +### Parameters + +`toValidUTF8(s string, replacement string) string` + +- `s`: the string to check. +- `replacement`: the string to replace invalid sequences with. + +### Examples + +```cel +grpc.federation.strings.toValidUTF8("hello\x80world", "?") //=> "hello?world" +``` + +## trim + +`trim` returns a slice of the string `s` with all leading and trailing Unicode code points contained in `cutset` removed. + +### Parameters + +`trim(s string, cutset string) string` + +- `s`: the string to trim. +- `cutset`: the characters to remove from the string. + +### Examples + +```cel +grpc.federation.strings.trim("!!!hello!!!", "!") //=> "hello" +``` + +## trimLeft + +`trimLeft` returns a slice of the string `s` with all leading Unicode code points contained in `cutset` removed. + +### Parameters + +`trimLeft(s string, cutset string) string` + +- `s`: the string to trim. +- `cutset`: the characters to remove from the start of the string. + +### Examples + +```cel +grpc.federation.strings.trimLeft("!!!hello!!!", "!") //=> "hello!!!" +``` + +## trimPrefix + +`trimPrefix` returns a slice of the string `s` without the provided leading `prefix`. If `s` doesn't start with `prefix`, it returns `s` unchanged. + +### Parameters + +`trimPrefix(s string, prefix string) string` + +- `s`: the string to trim. +- `prefix`: the prefix to remove. + +### Examples + +```cel +grpc.federation.strings.trimPrefix("hello world", "hello") //=> " world" +grpc.federation.strings.trimPrefix("hello world", "world") //=> "hello world" +``` + +## trimRight + +`trimRight` returns a slice of the string `s` with all trailing Unicode code points contained in `cutset` removed. + +### Parameters + +`trimRight(s string, cutset string) string` + +- `s`: the string to trim. +- `cutset`: the characters to remove from the end of the string. + +### Examples + +```cel +grpc.federation.strings.trimRight("!!!hello!!!", "!") //=> "!!!hello" +``` + +## trimSpace + +`trimSpace` returns a slice of the string `s` with all leading and trailing white space removed, as defined by Unicode. + +### Parameters + +`trimSpace(s string) string` + +- `s`: the string to trim. + +### Examples + +```cel +grpc.federation.strings.trimSpace(" hello ") //=> "hello" +``` + +## trimSuffix + +`trimSuffix` returns a slice of the string `s` without the provided trailing `suffix`. If `s` doesn't end with `suffix`, it returns `s` unchanged. + +### Parameters + +`trimSuffix(s string, suffix string) string` + +- `s`: the string to trim. +- `suffix`: the suffix to remove. + +### Examples + +```cel +grpc.federation.strings.trimSuffix("hello world", "world") //=> "hello " +grpc.federation.strings.trimSuffix("hello world", "hello") //=> "hello world" +``` From 819ebb5150df3d12843c091df8878886cc868ab3 Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Fri, 20 Sep 2024 21:08:02 +0900 Subject: [PATCH 06/10] =?UTF-8?q?=F0=9F=9A=A8=20fix=20lint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grpc/federation/cel/strings.go | 8 ++++++-- grpc/federation/cel/strings_test.go | 15 ++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/grpc/federation/cel/strings.go b/grpc/federation/cel/strings.go index f9a5f30f..0afe6420 100644 --- a/grpc/federation/cel/strings.go +++ b/grpc/federation/cel/strings.go @@ -2,11 +2,14 @@ package cel import ( "context" + "strings" + "github.com/google/cel-go/cel" "github.com/google/cel-go/common/types" "github.com/google/cel-go/common/types/ref" "github.com/google/cel-go/common/types/traits" - "strings" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) const StringsPackageName = "strings" @@ -299,7 +302,8 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { createStringsName("title"), OverloadFunc(createStringsID("title_string_string"), []*cel.Type{cel.StringType}, cel.StringType, func(_ context.Context, args ...ref.Val) ref.Val { - return types.String(strings.Title(args[0].(types.String).Value().(string))) + c := cases.Title(language.English) + return types.String(c.String(args[0].(types.String).Value().(string))) }, ), ), diff --git a/grpc/federation/cel/strings_test.go b/grpc/federation/cel/strings_test.go index c1f2f606..cb7f6c8a 100644 --- a/grpc/federation/cel/strings_test.go +++ b/grpc/federation/cel/strings_test.go @@ -3,14 +3,18 @@ package cel_test import ( "context" "fmt" + "strings" + "testing" + "github.com/google/cel-go/cel" "github.com/google/cel-go/common/types" "github.com/google/cel-go/common/types/ref" "github.com/google/cel-go/common/types/traits" "github.com/google/go-cmp/cmp" + "golang.org/x/text/cases" + "golang.org/x/text/language" + cellib "github.com/mercari/grpc-federation/grpc/federation/cel" - "strings" - "testing" ) func TestStringsFunctions(t *testing.T) { @@ -453,7 +457,8 @@ func TestStringsFunctions(t *testing.T) { if !ok { return fmt.Errorf("invalid result type: %T", got) } - expected := types.String(strings.Title("her royal highness")) + c := cases.Title(language.English) + expected := types.String(c.String("her royal highness")) if diff := cmp.Diff(gotV, expected); diff != "" { return fmt.Errorf("(-got, +want)\n%s", diff) } @@ -567,13 +572,13 @@ func TestStringsFunctions(t *testing.T) { }, { name: "trimRight", - expr: "grpc.federation.strings.trimRight('¡¡¡Hello, Gophers!!!', '¡¡¡')", + expr: "grpc.federation.strings.trimRight('¡¡¡Hello, Gophers!!!', '¡')", cmp: func(got ref.Val) error { gotV, ok := got.(types.String) if !ok { return fmt.Errorf("invalid result type: %T", got) } - expected := types.String(strings.TrimRight("¡¡¡Hello, Gophers!!!", "¡¡¡")) + expected := types.String(strings.TrimRight("¡¡¡Hello, Gophers!!!", "¡")) if diff := cmp.Diff(gotV, expected); diff != "" { return fmt.Errorf("(-got, +want)\n%s", diff) } From 116a9597df27e3d58dbbe530c6ae80e77c53991d Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Wed, 25 Sep 2024 19:18:19 +0900 Subject: [PATCH 07/10] =?UTF-8?q?=F0=9F=92=A1=20fix=20ambiguous=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grpc/federation/cel/strings.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/grpc/federation/cel/strings.go b/grpc/federation/cel/strings.go index 0afe6420..c8c8ad12 100644 --- a/grpc/federation/cel/strings.go +++ b/grpc/federation/cel/strings.go @@ -92,7 +92,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func Cut(s, sep string) (before, after string, found bool) + // func Cut(s, sep string) (before, after string, found bool) is not implemented because it has multiple return values. BindFunction( createStringsName("cutPrefix"), OverloadFunc(createStringsID("cutPrefix_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, @@ -138,7 +138,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func FieldsFunc(s string, f func(rune) bool) []string + // func FieldsFunc(s string, f func(rune) bool) []string is not implemented because it has a function argument. BindFunction( createStringsName("hasPrefix"), OverloadFunc(createStringsID("hasPrefix_string_string_bool"), []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType, @@ -184,7 +184,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func IndexFunc(s string, f func(rune) bool) int + // func IndexFunc(s string, f func(rune) bool) int is not implemented because it has a function argument. BindFunction( createStringsName("indexRune"), OverloadFunc(createStringsID("indexRune_string_int_int"), []*cel.Type{cel.StringType, cel.IntType}, cel.IntType, @@ -235,8 +235,8 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func LastIndexFunc(s string, f func(rune) bool) int - // func Map(mapping func(rune) rune, s string) string + // func LastIndexFunc(s string, f func(rune) bool) int is not implemented because it has a function argument. + // func Map(mapping func(rune) rune, s string) string is not implemented because it has a function argument. BindFunction( createStringsName("repeat"), OverloadFunc(createStringsID("repeat_string_int_string"), []*cel.Type{cel.StringType, cel.IntType}, cel.StringType, @@ -297,7 +297,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func Title(s string) string : deprecated + // strings.Title is deprecated. So, we use golang.org/x/text/cases.Title instead. BindFunction( createStringsName("title"), OverloadFunc(createStringsID("title_string_string"), []*cel.Type{cel.StringType}, cel.StringType, @@ -315,7 +315,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func ToLowerSpecial(c unicode.SpecialCase, s string) string + // func ToLowerSpecial(c unicode.SpecialCase, s string) string is not implemented because unicode.SpecialCase is not supported. BindFunction( createStringsName("toTitle"), OverloadFunc(createStringsID("toTitle_string_string"), []*cel.Type{cel.StringType}, cel.StringType, @@ -324,7 +324,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func ToTitleSpecial(c unicode.SpecialCase, s string) string + // func ToTitleSpecial(c unicode.SpecialCase, s string) string is not implemented because unicode.SpecialCase is not supported. BindFunction( createStringsName("toUpper"), OverloadFunc(createStringsID("toUpper_string_string"), []*cel.Type{cel.StringType}, cel.StringType, @@ -333,7 +333,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func ToUpperSpecial(c unicode.SpecialCase, s string) string + // func ToUpperSpecial(c unicode.SpecialCase, s string) string is not implemented because unicode.SpecialCase is not supported. BindFunction( createStringsName("toValidUTF8"), OverloadFunc(createStringsID("toValidUTF8_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, @@ -350,7 +350,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func TrimFunc(s string, f func(rune) bool) string + // func TrimFunc(s string, f func(rune) bool) string is not implemented because it has a function argument. BindFunction( createStringsName("trimLeft"), OverloadFunc(createStringsID("trimLeft_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, @@ -359,7 +359,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func TrimLeftFunc(s string, f func(rune) bool) string + // func TrimLeftFunc(s string, f func(rune) bool) string is not implemented because it has a function argument. BindFunction( createStringsName("trimPrefix"), OverloadFunc(createStringsID("trimPrefix_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, @@ -376,7 +376,7 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func TrimRightFunc(s string, f func(rune) bool) string + // func TrimRightFunc(s string, f func(rune) bool) string is not implemented because it has a function argument. BindFunction( createStringsName("trimSpace"), OverloadFunc(createStringsID("trimSpace_string_string"), []*cel.Type{cel.StringType}, cel.StringType, From 543d60b0216e884e3d05f73b9186e3a241c2fbf0 Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Thu, 26 Sep 2024 18:44:16 +0900 Subject: [PATCH 08/10] =?UTF-8?q?=F0=9F=94=A5=20remove=20typeAdapter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grpc/federation/cel/lib.go | 2 +- grpc/federation/cel/strings.go | 7 ++----- grpc/federation/cel/strings_test.go | 6 +----- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/grpc/federation/cel/lib.go b/grpc/federation/cel/lib.go index 54d46a9e..24f55c10 100644 --- a/grpc/federation/cel/lib.go +++ b/grpc/federation/cel/lib.go @@ -18,7 +18,7 @@ func NewLibrary(typeAdapter types.Adapter) *Library { return &Library{ name: "grpc.federation.static", subLibs: []cel.SingletonLibrary{ - NewStringsLibrary(typeAdapter), + NewStringsLibrary(), NewTimeLibrary(typeAdapter), NewListLibrary(typeAdapter), new(RandLibrary), diff --git a/grpc/federation/cel/strings.go b/grpc/federation/cel/strings.go index c8c8ad12..025d7103 100644 --- a/grpc/federation/cel/strings.go +++ b/grpc/federation/cel/strings.go @@ -17,13 +17,10 @@ const StringsPackageName = "strings" var _ cel.SingletonLibrary = new(StringsLibrary) type StringsLibrary struct { - typeAdapter types.Adapter } -func NewStringsLibrary(typeAdapter types.Adapter) *StringsLibrary { - return &StringsLibrary{ - typeAdapter: typeAdapter, - } +func NewStringsLibrary() *StringsLibrary { + return &StringsLibrary{} } func (lib *StringsLibrary) LibraryName() string { diff --git a/grpc/federation/cel/strings_test.go b/grpc/federation/cel/strings_test.go index cb7f6c8a..aba84e3c 100644 --- a/grpc/federation/cel/strings_test.go +++ b/grpc/federation/cel/strings_test.go @@ -617,15 +617,11 @@ func TestStringsFunctions(t *testing.T) { }, } - reg, err := types.NewRegistry() - if err != nil { - t.Fatal(err) - } for _, test := range tests { t.Run(test.name, func(t *testing.T) { env, err := cel.NewEnv( cel.Variable(cellib.ContextVariableName, cel.ObjectType(cellib.ContextTypeName)), - cel.Lib(cellib.NewStringsLibrary(reg)), + cel.Lib(cellib.NewStringsLibrary()), ) if err != nil { t.Fatal(err) From bc513b753c0a91dbfe1d5fa39ac0a3cfffc0b807 Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Thu, 26 Sep 2024 19:04:29 +0900 Subject: [PATCH 09/10] =?UTF-8?q?=E2=9C=A8=20impl=20cut=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- grpc/federation/cel/strings.go | 26 +++++++++++++++----------- grpc/federation/cel/strings_test.go | 26 ++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/grpc/federation/cel/strings.go b/grpc/federation/cel/strings.go index 025d7103..d072676c 100644 --- a/grpc/federation/cel/strings.go +++ b/grpc/federation/cel/strings.go @@ -89,18 +89,25 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { }, ), ), - // func Cut(s, sep string) (before, after string, found bool) is not implemented because it has multiple return values. + BindFunction( + createStringsName("cut"), + OverloadFunc(createStringsID("cut_string_string_strings"), []*cel.Type{cel.StringType, cel.StringType}, cel.ListType(cel.StringType), + func(_ context.Context, args ...ref.Val) ref.Val { + str := args[0].(types.String).Value().(string) + sep := args[1].(types.String).Value().(string) + before, after, _ := strings.Cut(str, sep) + return types.NewStringList(types.DefaultTypeAdapter, []string{before, after}) + }, + ), + ), BindFunction( createStringsName("cutPrefix"), OverloadFunc(createStringsID("cutPrefix_string_string_string"), []*cel.Type{cel.StringType, cel.StringType}, cel.StringType, func(_ context.Context, args ...ref.Val) ref.Val { str := args[0].(types.String).Value().(string) prefix := args[1].(types.String).Value().(string) - after, found := strings.CutPrefix(str, prefix) - if found { - return types.String(after) - } - return types.String(str) + after, _ := strings.CutPrefix(str, prefix) + return types.String(after) }, ), ), @@ -110,11 +117,8 @@ func (lib *StringsLibrary) CompileOptions() []cel.EnvOption { func(_ context.Context, args ...ref.Val) ref.Val { str := args[0].(types.String).Value().(string) suffix := args[1].(types.String).Value().(string) - before, found := strings.CutSuffix(str, suffix) - if found { - return types.String(before) - } - return types.String(str) + before, _ := strings.CutSuffix(str, suffix) + return types.String(before) }, ), ), diff --git a/grpc/federation/cel/strings_test.go b/grpc/federation/cel/strings_test.go index aba84e3c..32175413 100644 --- a/grpc/federation/cel/strings_test.go +++ b/grpc/federation/cel/strings_test.go @@ -114,6 +114,26 @@ func TestStringsFunctions(t *testing.T) { return nil }, }, + { + name: "cut", + expr: "grpc.federation.strings.cut('abc', 'b')", + cmp: func(got ref.Val) error { + gotV, ok := got.(traits.Lister) + if !ok { + return fmt.Errorf("invalid result type: %T", got) + } + strs := make([]string, gotV.Size().(types.Int)) + for i := 0; i < int(gotV.Size().(types.Int)); i++ { + strs[i] = gotV.Get(types.Int(i)).(types.String).Value().(string) + } + before, after, _ := strings.Cut("abc", "b") + expected := []string{before, after} + if diff := cmp.Diff(strs, expected); diff != "" { + return fmt.Errorf("(-got, +want)\n%s", diff) + } + return nil + }, + }, { name: "cutPrefix", expr: "grpc.federation.strings.cutPrefix('abc', 'a')", @@ -122,7 +142,8 @@ func TestStringsFunctions(t *testing.T) { if !ok { return fmt.Errorf("invalid result type: %T", got) } - expected := types.String(strings.TrimPrefix("abc", "a")) + c, _ := strings.CutPrefix("abc", "a") + expected := types.String(c) if diff := cmp.Diff(gotV, expected); diff != "" { return fmt.Errorf("(-got, +want)\n%s", diff) } @@ -137,7 +158,8 @@ func TestStringsFunctions(t *testing.T) { if !ok { return fmt.Errorf("invalid result type: %T", got) } - expected := types.String(strings.TrimSuffix("abc", "c")) + c, _ := strings.CutSuffix("abc", "c") + expected := types.String(c) if diff := cmp.Diff(gotV, expected); diff != "" { return fmt.Errorf("(-got, +want)\n%s", diff) } From 8116ee6e3bc1af78d22d67d08b64d92eee3c0a47 Mon Sep 17 00:00:00 2001 From: pikachu0310 Date: Thu, 26 Sep 2024 19:06:13 +0900 Subject: [PATCH 10/10] =?UTF-8?q?=F0=9F=93=9D=20add=20description=20for=20?= =?UTF-8?q?cut=20function=20in=20strings.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/cel/strings.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/cel/strings.md b/docs/cel/strings.md index 9d002d6b..4291f532 100644 --- a/docs/cel/strings.md +++ b/docs/cel/strings.md @@ -12,6 +12,7 @@ The API for this package was created based on Go's [`strings`](https://pkg.go.de - [`containsAny`](#containsAny) - [`containsRune`](#containsRune) - [`count`](#count) +- [`cut`](#cut) - [`cutPrefix`](#cutPrefix) - [`cutSuffix`](#cutSuffix) - [`equalFold`](#equalFold) @@ -154,6 +155,30 @@ grpc.federation.strings.count("cheese", "e") //=> 3 grpc.federation.strings.count("five", "ve") //=> 1 ``` +## cut + +`cut` slices the input string `s` into two substrings, `before` and `after`, separated by the first occurrence of the separator `sep`. If `sep` is not found, `before` will be set to `s` and `after` will be empty. + +### Parameters + +`cut(s string, sep string) []string` + +- `s`: the string to cut. +- `sep`: the separator string. + +### Returns + +A list of two strings: +- The part of `s` before the first occurrence of `sep`. +- The part of `s` after the first occurrence of `sep`. + +### Examples + +```cel +grpc.federation.strings.cut("gophers", "ph") //=> ["go", "ers"] +grpc.federation.strings.cut("gophers", "x") //=> ["gophers", ""] +``` + ## cutPrefix `cutPrefix` returns the string `s` after removing the provided `prefix`. If the string doesn't start with `prefix`, `s` is returned unchanged.