diff --git a/cli/cli.go b/cli/cli.go index ce97b96b..e0f5f381 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -18,6 +18,25 @@ // integrated client. package cli +import ( + "net/http" + + "connectrpc.com/connect" + "github.com/oxisto/money-gopher/gen/portfoliov1connect" +) + // Session holds all necessary information about the current CLI session. type Session struct { + PortfolioClient portfoliov1connect.PortfolioServiceClient +} + +func NewSession() *Session { + var s Session + + s.PortfolioClient = portfoliov1connect.NewPortfolioServiceClient( + http.DefaultClient, "http://localhost:8080", + connect.WithHTTPGet(), + ) + + return &s } diff --git a/cli/commands/account.go b/cli/commands/account.go new file mode 100644 index 00000000..3ab123b9 --- /dev/null +++ b/cli/commands/account.go @@ -0,0 +1,37 @@ +package commands + +import ( + "context" + "fmt" + + "connectrpc.com/connect" + "github.com/oxisto/money-gopher/cli" + portfoliov1 "github.com/oxisto/money-gopher/gen" +) + +type BankAccountCmd struct { + Create CreateBankAccountCmd `cmd:"" help:"Creates a new bank account."` +} + +type CreateBankAccountCmd struct { + Name string `help:"The identifier of the portfolio, e.g. mybank/myportfolio" required:""` + DisplayName string `help:"The display name of the portfolio"` +} + +func (cmd *CreateBankAccountCmd) Run(s *cli.Session) error { + res, err := s.PortfolioClient.CreateBankAccount( + context.Background(), + connect.NewRequest(&portfoliov1.CreateBankAccountRequest{ + BankAccount: &portfoliov1.BankAccount{ + Name: cmd.Name, + DisplayName: cmd.DisplayName, + }, + }), + ) + if err != nil { + return err + } + + fmt.Println(res.Msg) + return nil +} diff --git a/cli/commands/init.go b/cli/commands/init.go index 6b6b9758..9a26362c 100644 --- a/cli/commands/init.go +++ b/cli/commands/init.go @@ -23,8 +23,9 @@ import ( var CLI struct { Debug bool `help:"Enable debug mode."` - Security SecurityCmd `cmd:"" help:"Security commands."` - Portfolio PortfolioCmd `cmd:"" help:"Portfolio commands."` + Security SecurityCmd `cmd:"" help:"Security commands."` + Portfolio PortfolioCmd `cmd:"" help:"Portfolio commands."` + BankAccount BankAccountCmd `cmd:"" help:"Bank account commands."` Completion kongcompletion.Completion `cmd:"" help:"Outputs shell code for initializing tab completions" hidden:"" completion-shell-default:"false"` } diff --git a/cli/commands/portfolio.go b/cli/commands/portfolio.go index 349e8e45..97076378 100644 --- a/cli/commands/portfolio.go +++ b/cli/commands/portfolio.go @@ -209,8 +209,6 @@ func eventTypeFrom(typ string) portfoliov1.PortfolioEventType { return portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DELIVERY_INBOUND } else if typ == "delivery-outbound" { return portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DELIVERY_OUTBOUND - } else if typ == "dividend" { - return portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DIVIDEND } return portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_UNSPECIFIED diff --git a/cmd/mgo/mgo.go b/cmd/mgo/mgo.go index e8ea23aa..0a570e40 100644 --- a/cmd/mgo/mgo.go +++ b/cmd/mgo/mgo.go @@ -42,6 +42,6 @@ func main() { ctx, err := parser.Parse(os.Args[1:]) parser.FatalIfErrorf(err) - err = ctx.Run(&cli.Session{}) + err = ctx.Run(cli.NewSession()) parser.FatalIfErrorf(err) } diff --git a/finance/calculation.go b/finance/calculation.go index e64effc0..4f342c7f 100644 --- a/finance/calculation.go +++ b/finance/calculation.go @@ -38,6 +38,8 @@ type calculation struct { Fees *portfoliov1.Currency Taxes *portfoliov1.Currency + Cash *portfoliov1.Currency + fifo []*fifoTx } @@ -45,6 +47,7 @@ func NewCalculation(txs []*portfoliov1.PortfolioEvent) *calculation { var c calculation c.Fees = portfoliov1.Zero() c.Taxes = portfoliov1.Zero() + c.Cash = portfoliov1.Zero() for _, tx := range txs { c.Apply(tx) @@ -58,11 +61,20 @@ func (c *calculation) Apply(tx *portfoliov1.PortfolioEvent) { case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DELIVERY_INBOUND: fallthrough case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY: + var ( + total *portfoliov1.Currency + ) + // Increase the amount of shares and the fees by the value stored in the // transaction c.Fees.PlusAssign(tx.Fees) c.Amount += tx.Amount + total = portfoliov1.Times(tx.Price, tx.Amount).Plus(tx.Fees).Plus(tx.Taxes) + + // Decrease our cash + c.Cash.MinusAssign(total) + // Add the transaction to the FIFO list. We need to have a list because // sold shares are sold according to the FIFO principle. We therefore // need to store this information to reduce the amount in the items @@ -77,7 +89,8 @@ func (c *calculation) Apply(tx *portfoliov1.PortfolioEvent) { fallthrough case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_SELL: var ( - sold float64 + sold float64 + total *portfoliov1.Currency ) // Increase the fees and taxes by the value stored in the @@ -85,6 +98,11 @@ func (c *calculation) Apply(tx *portfoliov1.PortfolioEvent) { c.Fees.PlusAssign(tx.Fees) c.Taxes.PlusAssign(tx.Taxes) + total = portfoliov1.Times(tx.Price, tx.Amount).Plus(tx.Fees).Plus(tx.Taxes) + + // Increase our cash + c.Cash.PlusAssign(total) + // Store the amount of shares sold in this variable, since we later need // to decrease it while looping through the FIFO list sold = tx.Amount @@ -128,6 +146,12 @@ func (c *calculation) Apply(tx *portfoliov1.PortfolioEvent) { sold -= n } + case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DEPOSIT_CASH: + // Add to the cash + c.Cash.PlusAssign(tx.Price) + case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_WITHDRAW_CASH: + // Remove from the cash + c.Cash.MinusAssign(tx.Price) } } diff --git a/finance/calculation_test.go b/finance/calculation_test.go index 88969ccc..d64e8455 100644 --- a/finance/calculation_test.go +++ b/finance/calculation_test.go @@ -37,6 +37,10 @@ func TestNewCalculation(t *testing.T) { name: "buy and sell", args: args{ txs: []*portfoliov1.PortfolioEvent{ + { + Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DEPOSIT_CASH, + Price: portfoliov1.Value(500000), + }, { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, Amount: 5, @@ -88,7 +92,8 @@ func TestNewCalculation(t *testing.T) { assert.Equals(t, 491425, int(c.NetValue().Value)) && assert.Equals(t, 494614, int(c.GrossValue().Value)) && assert.Equals(t, 19657, int(c.NetPrice().Value)) && - assert.Equals(t, 19785, int(c.GrossPrice().Value)) + assert.Equals(t, 19785, int(c.GrossPrice().Value)) && + assert.Equals(t, 44099, int(c.Cash.Value)) }, }, } diff --git a/gen/currency.go b/gen/currency.go new file mode 100644 index 00000000..3772e74f --- /dev/null +++ b/gen/currency.go @@ -0,0 +1,93 @@ +// Copyright 2023 Christian Banse +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is part of The Money Gopher. +package portfoliov1 + +import ( + "fmt" + "math" +) + +func Zero() *Currency { + // TODO(oxisto): Somehow make it possible to change default currency + return &Currency{Symbol: "EUR"} +} + +func Value(v int32) *Currency { + // TODO(oxisto): Somehow make it possible to change default currency + return &Currency{Symbol: "EUR", Value: v} +} + +func (c *Currency) PlusAssign(o *Currency) { + if o != nil { + c.Value += o.Value + } +} + +func (c *Currency) MinusAssign(o *Currency) { + if o != nil { + c.Value -= o.Value + } +} + +func Plus(a *Currency, b *Currency) *Currency { + return &Currency{ + Value: a.Value + b.Value, + Symbol: a.Symbol, + } +} + +func (a *Currency) Plus(b *Currency) *Currency { + if b == nil { + return &Currency{ + Value: a.Value, + Symbol: a.Symbol, + } + } + + return &Currency{ + Value: a.Value + b.Value, + Symbol: a.Symbol, + } +} + +func Minus(a *Currency, b *Currency) *Currency { + return &Currency{ + Value: a.Value - b.Value, + Symbol: a.Symbol, + } +} + +func Divide(a *Currency, b float64) *Currency { + return &Currency{ + Value: int32(math.Round((float64(a.Value) / b))), + Symbol: a.Symbol, + } +} + +func Times(a *Currency, b float64) *Currency { + return &Currency{ + Value: int32(math.Round((float64(a.Value) * b))), + Symbol: a.Symbol, + } +} + +func (c *Currency) Pretty() string { + return fmt.Sprintf("%.0f %s", float32(c.Value)/100, c.Symbol) +} + +func (c *Currency) IsZero() bool { + return c == nil || c.Value == 0 +} diff --git a/gen/mgo.pb.go b/gen/mgo.pb.go index c06871bb..eeb0c359 100644 --- a/gen/mgo.pb.go +++ b/gen/mgo.pb.go @@ -32,6 +32,11 @@ const ( PortfolioEventType_PORTFOLIO_EVENT_TYPE_DELIVERY_INBOUND PortfolioEventType = 3 PortfolioEventType_PORTFOLIO_EVENT_TYPE_DELIVERY_OUTBOUND PortfolioEventType = 4 PortfolioEventType_PORTFOLIO_EVENT_TYPE_DIVIDEND PortfolioEventType = 10 + PortfolioEventType_PORTFOLIO_EVENT_TYPE_INTEREST PortfolioEventType = 11 + PortfolioEventType_PORTFOLIO_EVENT_TYPE_DEPOSIT_CASH PortfolioEventType = 20 + PortfolioEventType_PORTFOLIO_EVENT_TYPE_WITHDRAW_CASH PortfolioEventType = 21 + PortfolioEventType_PORTFOLIO_EVENT_TYPE_ACCOUNT_FEES PortfolioEventType = 30 + PortfolioEventType_PORTFOLIO_EVENT_TYPE_TAX_REFUND PortfolioEventType = 31 ) // Enum value maps for PortfolioEventType. @@ -43,6 +48,11 @@ var ( 3: "PORTFOLIO_EVENT_TYPE_DELIVERY_INBOUND", 4: "PORTFOLIO_EVENT_TYPE_DELIVERY_OUTBOUND", 10: "PORTFOLIO_EVENT_TYPE_DIVIDEND", + 11: "PORTFOLIO_EVENT_TYPE_INTEREST", + 20: "PORTFOLIO_EVENT_TYPE_DEPOSIT_CASH", + 21: "PORTFOLIO_EVENT_TYPE_WITHDRAW_CASH", + 30: "PORTFOLIO_EVENT_TYPE_ACCOUNT_FEES", + 31: "PORTFOLIO_EVENT_TYPE_TAX_REFUND", } PortfolioEventType_value = map[string]int32{ "PORTFOLIO_EVENT_TYPE_UNSPECIFIED": 0, @@ -51,6 +61,11 @@ var ( "PORTFOLIO_EVENT_TYPE_DELIVERY_INBOUND": 3, "PORTFOLIO_EVENT_TYPE_DELIVERY_OUTBOUND": 4, "PORTFOLIO_EVENT_TYPE_DIVIDEND": 10, + "PORTFOLIO_EVENT_TYPE_INTEREST": 11, + "PORTFOLIO_EVENT_TYPE_DEPOSIT_CASH": 20, + "PORTFOLIO_EVENT_TYPE_WITHDRAW_CASH": 21, + "PORTFOLIO_EVENT_TYPE_ACCOUNT_FEES": 30, + "PORTFOLIO_EVENT_TYPE_TAX_REFUND": 31, } ) @@ -822,6 +837,53 @@ func (x *ImportTransactionsRequest) GetFromCsv() string { return "" } +type CreateBankAccountRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BankAccount *BankAccount `protobuf:"bytes,1,opt,name=bank_account,json=bankAccount,proto3" json:"bank_account,omitempty"` +} + +func (x *CreateBankAccountRequest) Reset() { + *x = CreateBankAccountRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_mgo_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateBankAccountRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateBankAccountRequest) ProtoMessage() {} + +func (x *CreateBankAccountRequest) ProtoReflect() protoreflect.Message { + mi := &file_mgo_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateBankAccountRequest.ProtoReflect.Descriptor instead. +func (*CreateBankAccountRequest) Descriptor() ([]byte, []int) { + return file_mgo_proto_rawDescGZIP(), []int{15} +} + +func (x *CreateBankAccountRequest) GetBankAccount() *BankAccount { + if x != nil { + return x.BankAccount + } + return nil +} + type Portfolio struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -829,6 +891,9 @@ type Portfolio struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + // BankAccountName contains the name/identifier of the underlying bank + // account. + BankAccountName string `protobuf:"bytes,3,opt,name=bank_account_name,json=bankAccountName,proto3" json:"bank_account_name,omitempty"` // Events contains all portfolio events, such as buy/sell transactions, // dividends or other. They need to be ordered by time (ascending). Events []*PortfolioEvent `protobuf:"bytes,5,rep,name=events,proto3" json:"events,omitempty"` @@ -837,7 +902,7 @@ type Portfolio struct { func (x *Portfolio) Reset() { *x = Portfolio{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[15] + mi := &file_mgo_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -850,7 +915,7 @@ func (x *Portfolio) String() string { func (*Portfolio) ProtoMessage() {} func (x *Portfolio) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[15] + mi := &file_mgo_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -863,7 +928,7 @@ func (x *Portfolio) ProtoReflect() protoreflect.Message { // Deprecated: Use Portfolio.ProtoReflect.Descriptor instead. func (*Portfolio) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{15} + return file_mgo_proto_rawDescGZIP(), []int{16} } func (x *Portfolio) GetName() string { @@ -880,6 +945,13 @@ func (x *Portfolio) GetDisplayName() string { return "" } +func (x *Portfolio) GetBankAccountName() string { + if x != nil { + return x.BankAccountName + } + return "" +} + func (x *Portfolio) GetEvents() []*PortfolioEvent { if x != nil { return x.Events @@ -887,6 +959,61 @@ func (x *Portfolio) GetEvents() []*PortfolioEvent { return nil } +type BankAccount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` +} + +func (x *BankAccount) Reset() { + *x = BankAccount{} + if protoimpl.UnsafeEnabled { + mi := &file_mgo_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BankAccount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BankAccount) ProtoMessage() {} + +func (x *BankAccount) ProtoReflect() protoreflect.Message { + mi := &file_mgo_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BankAccount.ProtoReflect.Descriptor instead. +func (*BankAccount) Descriptor() ([]byte, []int) { + return file_mgo_proto_rawDescGZIP(), []int{17} +} + +func (x *BankAccount) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *BankAccount) GetDisplayName() string { + if x != nil { + return x.DisplayName + } + return "" +} + // PortfolioSnapshot represents a snapshot in time of the portfolio. It can for // example be the current state of the portfolio but also represent the state of // the portfolio at a certain time in the past. @@ -902,22 +1029,28 @@ type PortfolioSnapshot struct { // FirstTransactionTime is the time of the first transaction with the // snapshot. FirstTransactionTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=first_transaction_time,json=firstTransactionTime,proto3,oneof" json:"first_transaction_time,omitempty"` - // TotalPurchaseValue contains the total purchase value of all positions + // TotalPurchaseValue contains the total purchase value of all asset positions TotalPurchaseValue *Currency `protobuf:"bytes,10,opt,name=total_purchase_value,json=totalPurchaseValue,proto3" json:"total_purchase_value,omitempty"` - // TotalMarketValue contains the total market value of all positions + // TotalMarketValue contains the total market value of all asset positions TotalMarketValue *Currency `protobuf:"bytes,11,opt,name=total_market_value,json=totalMarketValue,proto3" json:"total_market_value,omitempty"` // TotalProfitOrLoss contains the total absolute amount of profit or loss in - // this snapshot. + // this snapshot, based on asset value. TotalProfitOrLoss *Currency `protobuf:"bytes,20,opt,name=total_profit_or_loss,json=totalProfitOrLoss,proto3" json:"total_profit_or_loss,omitempty"` // TotalGains contains the total relative amount of profit or loss in this - // snapshot. + // snapshot, based on asset value. TotalGains float64 `protobuf:"fixed64,21,opt,name=total_gains,json=totalGains,proto3" json:"total_gains,omitempty"` + // Cash contains the current amount of cash in the portfolio's bank + // account(s). + Cash *Currency `protobuf:"bytes,22,opt,name=cash,proto3" json:"cash,omitempty"` + // TotalPortfolioValue contains the amount of cash plus the total market value + // of all assets. + TotalPortfolioValue *Currency `protobuf:"bytes,23,opt,name=total_portfolio_value,json=totalPortfolioValue,proto3" json:"total_portfolio_value,omitempty"` } func (x *PortfolioSnapshot) Reset() { *x = PortfolioSnapshot{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[16] + mi := &file_mgo_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -930,7 +1063,7 @@ func (x *PortfolioSnapshot) String() string { func (*PortfolioSnapshot) ProtoMessage() {} func (x *PortfolioSnapshot) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[16] + mi := &file_mgo_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -943,7 +1076,7 @@ func (x *PortfolioSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use PortfolioSnapshot.ProtoReflect.Descriptor instead. func (*PortfolioSnapshot) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{16} + return file_mgo_proto_rawDescGZIP(), []int{18} } func (x *PortfolioSnapshot) GetTime() *timestamppb.Timestamp { @@ -995,6 +1128,20 @@ func (x *PortfolioSnapshot) GetTotalGains() float64 { return 0 } +func (x *PortfolioSnapshot) GetCash() *Currency { + if x != nil { + return x.Cash + } + return nil +} + +func (x *PortfolioSnapshot) GetTotalPortfolioValue() *Currency { + if x != nil { + return x.TotalPortfolioValue + } + return nil +} + type PortfolioPosition struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1027,7 +1174,7 @@ type PortfolioPosition struct { func (x *PortfolioPosition) Reset() { *x = PortfolioPosition{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[17] + mi := &file_mgo_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1040,7 +1187,7 @@ func (x *PortfolioPosition) String() string { func (*PortfolioPosition) ProtoMessage() {} func (x *PortfolioPosition) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[17] + mi := &file_mgo_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1053,7 +1200,7 @@ func (x *PortfolioPosition) ProtoReflect() protoreflect.Message { // Deprecated: Use PortfolioPosition.ProtoReflect.Descriptor instead. func (*PortfolioPosition) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{17} + return file_mgo_proto_rawDescGZIP(), []int{19} } func (x *PortfolioPosition) GetSecurity() *Security { @@ -1138,7 +1285,7 @@ type PortfolioEvent struct { func (x *PortfolioEvent) Reset() { *x = PortfolioEvent{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[18] + mi := &file_mgo_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1151,7 +1298,7 @@ func (x *PortfolioEvent) String() string { func (*PortfolioEvent) ProtoMessage() {} func (x *PortfolioEvent) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[18] + mi := &file_mgo_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1164,7 +1311,7 @@ func (x *PortfolioEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use PortfolioEvent.ProtoReflect.Descriptor instead. func (*PortfolioEvent) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{18} + return file_mgo_proto_rawDescGZIP(), []int{20} } func (x *PortfolioEvent) GetName() string { @@ -1247,7 +1394,7 @@ type Security struct { func (x *Security) Reset() { *x = Security{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[19] + mi := &file_mgo_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1260,7 +1407,7 @@ func (x *Security) String() string { func (*Security) ProtoMessage() {} func (x *Security) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[19] + mi := &file_mgo_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1273,7 +1420,7 @@ func (x *Security) ProtoReflect() protoreflect.Message { // Deprecated: Use Security.ProtoReflect.Descriptor instead. func (*Security) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{19} + return file_mgo_proto_rawDescGZIP(), []int{21} } func (x *Security) GetName() string { @@ -1319,7 +1466,7 @@ type ListedSecurity struct { func (x *ListedSecurity) Reset() { *x = ListedSecurity{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[20] + mi := &file_mgo_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1332,7 +1479,7 @@ func (x *ListedSecurity) String() string { func (*ListedSecurity) ProtoMessage() {} func (x *ListedSecurity) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[20] + mi := &file_mgo_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1345,7 +1492,7 @@ func (x *ListedSecurity) ProtoReflect() protoreflect.Message { // Deprecated: Use ListedSecurity.ProtoReflect.Descriptor instead. func (*ListedSecurity) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{20} + return file_mgo_proto_rawDescGZIP(), []int{22} } func (x *ListedSecurity) GetSecurityName() string { @@ -1394,7 +1541,7 @@ type ListSecuritiesRequest struct { func (x *ListSecuritiesRequest) Reset() { *x = ListSecuritiesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[21] + mi := &file_mgo_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1407,7 +1554,7 @@ func (x *ListSecuritiesRequest) String() string { func (*ListSecuritiesRequest) ProtoMessage() {} func (x *ListSecuritiesRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[21] + mi := &file_mgo_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1420,7 +1567,7 @@ func (x *ListSecuritiesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSecuritiesRequest.ProtoReflect.Descriptor instead. func (*ListSecuritiesRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{21} + return file_mgo_proto_rawDescGZIP(), []int{23} } func (x *ListSecuritiesRequest) GetFilter() *ListSecuritiesRequest_Filter { @@ -1441,7 +1588,7 @@ type ListSecuritiesResponse struct { func (x *ListSecuritiesResponse) Reset() { *x = ListSecuritiesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[22] + mi := &file_mgo_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1454,7 +1601,7 @@ func (x *ListSecuritiesResponse) String() string { func (*ListSecuritiesResponse) ProtoMessage() {} func (x *ListSecuritiesResponse) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[22] + mi := &file_mgo_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1467,7 +1614,7 @@ func (x *ListSecuritiesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSecuritiesResponse.ProtoReflect.Descriptor instead. func (*ListSecuritiesResponse) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{22} + return file_mgo_proto_rawDescGZIP(), []int{24} } func (x *ListSecuritiesResponse) GetSecurities() []*Security { @@ -1488,7 +1635,7 @@ type GetSecurityRequest struct { func (x *GetSecurityRequest) Reset() { *x = GetSecurityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[23] + mi := &file_mgo_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1501,7 +1648,7 @@ func (x *GetSecurityRequest) String() string { func (*GetSecurityRequest) ProtoMessage() {} func (x *GetSecurityRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[23] + mi := &file_mgo_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1514,7 +1661,7 @@ func (x *GetSecurityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSecurityRequest.ProtoReflect.Descriptor instead. func (*GetSecurityRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{23} + return file_mgo_proto_rawDescGZIP(), []int{25} } func (x *GetSecurityRequest) GetName() string { @@ -1535,7 +1682,7 @@ type CreateSecurityRequest struct { func (x *CreateSecurityRequest) Reset() { *x = CreateSecurityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[24] + mi := &file_mgo_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1548,7 +1695,7 @@ func (x *CreateSecurityRequest) String() string { func (*CreateSecurityRequest) ProtoMessage() {} func (x *CreateSecurityRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[24] + mi := &file_mgo_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1561,7 +1708,7 @@ func (x *CreateSecurityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSecurityRequest.ProtoReflect.Descriptor instead. func (*CreateSecurityRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{24} + return file_mgo_proto_rawDescGZIP(), []int{26} } func (x *CreateSecurityRequest) GetSecurity() *Security { @@ -1583,7 +1730,7 @@ type UpdateSecurityRequest struct { func (x *UpdateSecurityRequest) Reset() { *x = UpdateSecurityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[25] + mi := &file_mgo_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1596,7 +1743,7 @@ func (x *UpdateSecurityRequest) String() string { func (*UpdateSecurityRequest) ProtoMessage() {} func (x *UpdateSecurityRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[25] + mi := &file_mgo_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1609,7 +1756,7 @@ func (x *UpdateSecurityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateSecurityRequest.ProtoReflect.Descriptor instead. func (*UpdateSecurityRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{25} + return file_mgo_proto_rawDescGZIP(), []int{27} } func (x *UpdateSecurityRequest) GetSecurity() *Security { @@ -1637,7 +1784,7 @@ type DeleteSecurityRequest struct { func (x *DeleteSecurityRequest) Reset() { *x = DeleteSecurityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[26] + mi := &file_mgo_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1650,7 +1797,7 @@ func (x *DeleteSecurityRequest) String() string { func (*DeleteSecurityRequest) ProtoMessage() {} func (x *DeleteSecurityRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[26] + mi := &file_mgo_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1663,7 +1810,7 @@ func (x *DeleteSecurityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSecurityRequest.ProtoReflect.Descriptor instead. func (*DeleteSecurityRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{26} + return file_mgo_proto_rawDescGZIP(), []int{28} } func (x *DeleteSecurityRequest) GetName() string { @@ -1684,7 +1831,7 @@ type TriggerQuoteUpdateRequest struct { func (x *TriggerQuoteUpdateRequest) Reset() { *x = TriggerQuoteUpdateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[27] + mi := &file_mgo_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1697,7 +1844,7 @@ func (x *TriggerQuoteUpdateRequest) String() string { func (*TriggerQuoteUpdateRequest) ProtoMessage() {} func (x *TriggerQuoteUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[27] + mi := &file_mgo_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1710,7 +1857,7 @@ func (x *TriggerQuoteUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TriggerQuoteUpdateRequest.ProtoReflect.Descriptor instead. func (*TriggerQuoteUpdateRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{27} + return file_mgo_proto_rawDescGZIP(), []int{29} } func (x *TriggerQuoteUpdateRequest) GetSecurityNames() []string { @@ -1729,7 +1876,7 @@ type TriggerQuoteUpdateResponse struct { func (x *TriggerQuoteUpdateResponse) Reset() { *x = TriggerQuoteUpdateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[28] + mi := &file_mgo_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1742,7 +1889,7 @@ func (x *TriggerQuoteUpdateResponse) String() string { func (*TriggerQuoteUpdateResponse) ProtoMessage() {} func (x *TriggerQuoteUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[28] + mi := &file_mgo_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1755,7 +1902,7 @@ func (x *TriggerQuoteUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TriggerQuoteUpdateResponse.ProtoReflect.Descriptor instead. func (*TriggerQuoteUpdateResponse) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{28} + return file_mgo_proto_rawDescGZIP(), []int{30} } type ListSecuritiesRequest_Filter struct { @@ -1769,7 +1916,7 @@ type ListSecuritiesRequest_Filter struct { func (x *ListSecuritiesRequest_Filter) Reset() { *x = ListSecuritiesRequest_Filter{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[30] + mi := &file_mgo_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1782,7 +1929,7 @@ func (x *ListSecuritiesRequest_Filter) String() string { func (*ListSecuritiesRequest_Filter) ProtoMessage() {} func (x *ListSecuritiesRequest_Filter) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[30] + mi := &file_mgo_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1795,7 +1942,7 @@ func (x *ListSecuritiesRequest_Filter) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSecuritiesRequest_Filter.ProtoReflect.Descriptor instead. func (*ListSecuritiesRequest_Filter) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{21, 0} + return file_mgo_proto_rawDescGZIP(), []int{23, 0} } func (x *ListSecuritiesRequest_Filter) GetSecurityNames() []string { @@ -1896,327 +2043,366 @@ var file_mgo_proto_rawDesc = []byte{ 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x63, 0x73, 0x76, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x66, 0x72, - 0x6f, 0x6d, 0x43, 0x73, 0x76, 0x22, 0x7c, 0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, - 0x69, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, - 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, - 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, - 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, - 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x22, 0xf0, 0x04, 0x0a, 0x11, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x09, 0x70, 0x6f, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6d, - 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, - 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x09, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x55, 0x0a, 0x16, 0x66, - 0x69, 0x72, 0x73, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x14, 0x66, 0x69, 0x72, 0x73, 0x74, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x88, - 0x01, 0x01, 0x12, 0x4c, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x72, 0x63, - 0x68, 0x61, 0x73, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x12, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x48, 0x0a, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, - 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, - 0x61, 0x72, 0x6b, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x14, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x74, 0x5f, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, - 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x63, 0x79, 0x52, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x74, 0x4f, 0x72, 0x4c, 0x6f, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x5f, 0x67, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x47, 0x61, 0x69, 0x6e, 0x73, 0x1a, 0x61, 0x0a, 0x0e, 0x50, 0x6f, 0x73, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, 0x67, - 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x19, 0x0a, 0x17, 0x5f, + 0x6f, 0x6d, 0x43, 0x73, 0x76, 0x22, 0x5c, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, + 0x61, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x40, 0x0a, 0x0c, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, + 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x6e, 0x6b, 0x41, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x0b, 0x62, 0x61, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x22, 0xa8, 0x01, 0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x6e, 0x6b, + 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x61, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, + 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x44, + 0x0a, 0x0b, 0x42, 0x61, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xf0, 0x05, 0x0a, 0x11, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, + 0x69, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x09, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, + 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x09, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x55, 0x0a, 0x16, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0xfa, 0x03, 0x0a, 0x11, 0x50, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x08, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x63, 0x75, - 0x72, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x41, 0x0a, 0x0e, - 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, - 0x52, 0x0d, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x41, 0x0a, 0x0e, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x63, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, + 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x14, 0x66, 0x69, 0x72, 0x73, + 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, + 0x88, 0x01, 0x01, 0x12, 0x4c, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x72, + 0x63, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x12, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x48, 0x0a, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x65, + 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4b, 0x0a, 0x14, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x74, 0x5f, 0x6f, 0x72, 0x5f, 0x6c, + 0x6f, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, + 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x74, 0x4f, 0x72, 0x4c, 0x6f, 0x73, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x5f, 0x67, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x47, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x63, 0x61, 0x73, + 0x68, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x63, 0x79, 0x52, 0x0d, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x50, 0x72, 0x69, - 0x63, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, + 0x6e, 0x63, 0x79, 0x52, 0x04, 0x63, 0x61, 0x73, 0x68, 0x12, 0x4e, 0x0a, 0x15, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x63, - 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x50, 0x72, 0x69, 0x63, 0x65, - 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x18, 0x0f, + 0x65, 0x6e, 0x63, 0x79, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74, 0x66, + 0x6f, 0x6c, 0x69, 0x6f, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x61, 0x0a, 0x0e, 0x50, 0x6f, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, + 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x19, 0x0a, 0x17, + 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0xfa, 0x03, 0x0a, 0x11, 0x50, 0x6f, 0x72, 0x74, + 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, + 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x41, 0x0a, + 0x0e, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, + 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, + 0x79, 0x52, 0x0d, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0d, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x50, 0x72, + 0x69, 0x63, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, + 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x50, 0x72, 0x69, 0x63, + 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, + 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, + 0x79, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x0e, + 0x70, 0x72, 0x6f, 0x66, 0x69, 0x74, 0x5f, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, - 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x0e, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x74, 0x5f, 0x6f, 0x72, 0x5f, 0x6c, 0x6f, 0x73, 0x73, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, - 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x74, 0x4f, 0x72, 0x4c, 0x6f, 0x73, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x67, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x67, 0x61, - 0x69, 0x6e, 0x73, 0x22, 0x86, 0x03, 0x0a, 0x0e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, - 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, - 0x74, 0x69, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x73, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x01, - 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, - 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x63, 0x79, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x66, 0x65, - 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, + 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x74, 0x4f, 0x72, 0x4c, 0x6f, 0x73, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x67, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x67, + 0x61, 0x69, 0x6e, 0x73, 0x22, 0x86, 0x03, 0x0a, 0x0e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, + 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, + 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, + 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, + 0x69, 0x6f, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x70, 0x72, 0x69, + 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x63, 0x79, 0x52, 0x04, 0x66, 0x65, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x05, 0x74, 0x61, - 0x78, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, + 0x65, 0x6e, 0x63, 0x79, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x66, + 0x65, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, - 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x05, 0x74, 0x61, 0x78, 0x65, 0x73, 0x22, 0xbf, 0x01, 0x0a, - 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, - 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x3d, 0x0a, 0x09, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, - 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x4f, 0x6e, 0x12, - 0x2a, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x74, 0x65, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x11, 0x0a, 0x0f, 0x5f, - 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22, 0xb0, - 0x02, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x1a, - 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x42, 0x0a, 0x0c, 0x6c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x04, 0x66, 0x65, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x05, 0x74, + 0x61, 0x78, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, + 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x05, 0x74, 0x61, 0x78, 0x65, 0x73, 0x22, 0xbf, 0x01, + 0x0a, 0x08, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x3d, 0x0a, 0x09, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x6e, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, + 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x4f, 0x6e, + 0x12, 0x2a, 0x0a, 0x0e, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0d, 0x71, 0x75, 0x6f, 0x74, + 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x11, 0x0a, 0x0f, + 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22, + 0xb0, 0x02, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x69, 0x63, 0x6b, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x69, 0x63, 0x6b, 0x65, 0x72, 0x12, + 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x42, 0x0a, 0x0c, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x00, 0x52, + 0x0b, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x88, 0x01, 0x01, 0x12, + 0x55, 0x0a, 0x16, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x01, 0x52, 0x14, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x73, + 0x74, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x6c, 0x61, 0x74, 0x65, + 0x73, 0x74, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x22, 0xa0, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x06, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, + 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x1a, 0x2f, 0x0a, 0x06, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x54, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3a, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, + 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, + 0x0a, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0x28, 0x0a, 0x12, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x4f, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, + 0x0a, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x00, 0x52, 0x0b, - 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x88, 0x01, 0x01, 0x12, 0x55, - 0x0a, 0x16, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x01, 0x52, 0x14, 0x6c, 0x61, - 0x74, 0x65, 0x73, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, - 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x73, - 0x74, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x22, 0xa0, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x06, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x67, - 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x66, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x1a, 0x2f, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x74, - 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x75, - 0x72, 0x69, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x66, 0x69, - 0x6c, 0x74, 0x65, 0x72, 0x22, 0x54, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, - 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, - 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x22, 0x8c, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x36, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, - 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x0a, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0x28, 0x0a, 0x12, 0x47, 0x65, - 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x4f, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, - 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x63, - 0x75, 0x72, 0x69, 0x74, 0x79, 0x22, 0x8c, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x36, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x2b, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x22, 0x42, 0x0a, 0x19, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x51, 0x75, 0x6f, 0x74, - 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, - 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x1c, 0x0a, 0x1a, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, - 0x51, 0x75, 0x6f, 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x2a, 0xf1, 0x01, 0x0a, 0x12, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x20, 0x50, 0x4f, - 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x1c, 0x0a, 0x18, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, - 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x55, 0x59, 0x10, 0x01, 0x12, 0x1d, - 0x0a, 0x19, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, - 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x29, 0x0a, - 0x25, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x49, - 0x4e, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x03, 0x12, 0x2a, 0x0a, 0x26, 0x50, 0x4f, 0x52, 0x54, + 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x2b, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x22, 0x42, 0x0a, 0x19, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x51, 0x75, 0x6f, + 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x1c, 0x0a, 0x1a, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, + 0x72, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0xaf, 0x03, 0x0a, 0x12, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, + 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x20, 0x50, + 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, + 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x55, 0x59, 0x10, 0x01, 0x12, + 0x1d, 0x0a, 0x19, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, + 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4c, 0x4c, 0x10, 0x02, 0x12, 0x29, + 0x0a, 0x25, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, + 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x59, 0x5f, + 0x49, 0x4e, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x03, 0x12, 0x2a, 0x0a, 0x26, 0x50, 0x4f, 0x52, + 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x4f, 0x55, 0x54, 0x42, 0x4f, + 0x55, 0x4e, 0x44, 0x10, 0x04, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, + 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, + 0x56, 0x49, 0x44, 0x45, 0x4e, 0x44, 0x10, 0x0a, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x4f, 0x55, 0x54, 0x42, 0x4f, 0x55, - 0x4e, 0x44, 0x10, 0x04, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, - 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x56, - 0x49, 0x44, 0x45, 0x4e, 0x44, 0x10, 0x0a, 0x32, 0xff, 0x09, 0x0a, 0x10, 0x50, 0x6f, 0x72, 0x74, - 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0f, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, - 0x28, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, - 0x69, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, - 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, - 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x68, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x28, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, - 0x69, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, - 0x12, 0x57, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x12, 0x25, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x58, 0x0a, 0x0f, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x28, 0x2e, 0x6d, - 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, + 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x45, 0x53, 0x54, 0x10, 0x0b, 0x12, 0x25, 0x0a, 0x21, 0x50, + 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x44, 0x45, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x5f, 0x43, 0x41, 0x53, 0x48, + 0x10, 0x14, 0x12, 0x26, 0x0a, 0x22, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, + 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x44, + 0x52, 0x41, 0x57, 0x5f, 0x43, 0x41, 0x53, 0x48, 0x10, 0x15, 0x12, 0x25, 0x0a, 0x21, 0x50, 0x4f, + 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x46, 0x45, 0x45, 0x53, 0x10, + 0x1e, 0x12, 0x23, 0x0a, 0x1f, 0x50, 0x4f, 0x52, 0x54, 0x46, 0x4f, 0x4c, 0x49, 0x4f, 0x5f, 0x45, + 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x41, 0x58, 0x5f, 0x52, 0x45, + 0x46, 0x55, 0x4e, 0x44, 0x10, 0x1f, 0x32, 0xdf, 0x0a, 0x0a, 0x10, 0x50, 0x6f, 0x72, 0x74, 0x66, + 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x28, + 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, + 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x68, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, + 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, + 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x28, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, + 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, + 0x57, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, + 0x25, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x6c, 0x69, 0x6f, 0x12, 0x53, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x72, - 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x28, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, - 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x6f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, - 0x12, 0x2d, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x23, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x6e, 0x61, 0x70, - 0x73, 0x68, 0x6f, 0x74, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x73, 0x0a, 0x1a, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6d, - 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, - 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x72, - 0x0a, 0x17, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, - 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, + 0x6c, 0x69, 0x6f, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x58, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x28, 0x2e, 0x6d, 0x67, + 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, + 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, + 0x69, 0x6f, 0x12, 0x53, 0x0a, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, + 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x12, 0x28, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, + 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x6f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x6f, + 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, + 0x2d, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, + 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x73, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, + 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x03, 0x90, - 0x02, 0x01, 0x12, 0x89, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x72, 0x0a, + 0x17, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6d, 0x67, 0x6f, + 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, + 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x03, 0x90, 0x02, + 0x01, 0x12, 0x89, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, + 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x32, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, + 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x32, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x73, 0x0a, + 0x1a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x6d, 0x67, + 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x20, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x69, 0x0a, 0x1a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x73, - 0x0a, 0x1a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x2e, 0x6d, - 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x20, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x69, 0x0a, 0x1a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x72, - 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x33, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x59, - 0x0a, 0x12, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0xcd, 0x04, 0x0a, 0x11, 0x53, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x68, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, - 0x73, 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6d, 0x67, 0x6f, - 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x54, 0x0a, 0x0b, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x24, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x12, 0x33, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, + 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x59, 0x0a, + 0x12, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, + 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x5e, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x42, 0x61, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x2e, + 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x6e, 0x6b, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, + 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x6e, + 0x6b, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0xcd, 0x04, 0x0a, 0x11, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x68, + 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, + 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x54, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x24, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, + 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, + 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x55, + 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, + 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, + 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x55, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, + 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x51, 0x0a, 0x0e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, - 0x55, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, - 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, - 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x55, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, - 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1a, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x51, 0x0a, - 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x12, - 0x27, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, - 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x12, 0x77, 0x0a, 0x1a, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x53, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x2b, + 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x77, 0x0a, 0x1a, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x2e, + 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6d, 0x67, 0x6f, + 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, + 0x69, 0x67, 0x67, 0x65, 0x72, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0xb2, 0x01, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, - 0x31, 0x2e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6d, 0x67, - 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x54, - 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0xb2, 0x01, 0x0a, 0x14, 0x63, 0x6f, - 0x6d, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x2e, - 0x76, 0x31, 0x42, 0x08, 0x4d, 0x67, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x78, 0x69, 0x73, 0x74, - 0x6f, 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2d, 0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x2f, 0x67, - 0x65, 0x6e, 0x3b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x76, 0x31, 0xa2, 0x02, - 0x03, 0x4d, 0x50, 0x58, 0xaa, 0x02, 0x10, 0x4d, 0x67, 0x6f, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x4d, 0x67, 0x6f, 0x5c, 0x50, 0x6f, - 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x4d, 0x67, 0x6f, - 0x5c, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x4d, 0x67, 0x6f, 0x3a, - 0x3a, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x31, 0x42, 0x08, 0x4d, 0x67, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x78, 0x69, 0x73, 0x74, 0x6f, + 0x2f, 0x6d, 0x6f, 0x6e, 0x65, 0x79, 0x2d, 0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x2f, 0x67, 0x65, + 0x6e, 0x3b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x76, 0x31, 0xa2, 0x02, 0x03, + 0x4d, 0x50, 0x58, 0xaa, 0x02, 0x10, 0x4d, 0x67, 0x6f, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, + 0x6c, 0x69, 0x6f, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x10, 0x4d, 0x67, 0x6f, 0x5c, 0x50, 0x6f, 0x72, + 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x4d, 0x67, 0x6f, 0x5c, + 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x4d, 0x67, 0x6f, 0x3a, 0x3a, + 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2232,7 +2418,7 @@ func file_mgo_proto_rawDescGZIP() []byte { } var file_mgo_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_mgo_proto_msgTypes = make([]protoimpl.MessageInfo, 31) +var file_mgo_proto_msgTypes = make([]protoimpl.MessageInfo, 33) var file_mgo_proto_goTypes = []interface{}{ (PortfolioEventType)(0), // 0: mgo.portfolio.v1.PortfolioEventType (*Currency)(nil), // 1: mgo.portfolio.v1.Currency @@ -2250,105 +2436,112 @@ var file_mgo_proto_goTypes = []interface{}{ (*UpdatePortfolioTransactionRequest)(nil), // 13: mgo.portfolio.v1.UpdatePortfolioTransactionRequest (*DeletePortfolioTransactionRequest)(nil), // 14: mgo.portfolio.v1.DeletePortfolioTransactionRequest (*ImportTransactionsRequest)(nil), // 15: mgo.portfolio.v1.ImportTransactionsRequest - (*Portfolio)(nil), // 16: mgo.portfolio.v1.Portfolio - (*PortfolioSnapshot)(nil), // 17: mgo.portfolio.v1.PortfolioSnapshot - (*PortfolioPosition)(nil), // 18: mgo.portfolio.v1.PortfolioPosition - (*PortfolioEvent)(nil), // 19: mgo.portfolio.v1.PortfolioEvent - (*Security)(nil), // 20: mgo.portfolio.v1.Security - (*ListedSecurity)(nil), // 21: mgo.portfolio.v1.ListedSecurity - (*ListSecuritiesRequest)(nil), // 22: mgo.portfolio.v1.ListSecuritiesRequest - (*ListSecuritiesResponse)(nil), // 23: mgo.portfolio.v1.ListSecuritiesResponse - (*GetSecurityRequest)(nil), // 24: mgo.portfolio.v1.GetSecurityRequest - (*CreateSecurityRequest)(nil), // 25: mgo.portfolio.v1.CreateSecurityRequest - (*UpdateSecurityRequest)(nil), // 26: mgo.portfolio.v1.UpdateSecurityRequest - (*DeleteSecurityRequest)(nil), // 27: mgo.portfolio.v1.DeleteSecurityRequest - (*TriggerQuoteUpdateRequest)(nil), // 28: mgo.portfolio.v1.TriggerQuoteUpdateRequest - (*TriggerQuoteUpdateResponse)(nil), // 29: mgo.portfolio.v1.TriggerQuoteUpdateResponse - nil, // 30: mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry - (*ListSecuritiesRequest_Filter)(nil), // 31: mgo.portfolio.v1.ListSecuritiesRequest.Filter - (*fieldmaskpb.FieldMask)(nil), // 32: google.protobuf.FieldMask - (*timestamppb.Timestamp)(nil), // 33: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 34: google.protobuf.Empty + (*CreateBankAccountRequest)(nil), // 16: mgo.portfolio.v1.CreateBankAccountRequest + (*Portfolio)(nil), // 17: mgo.portfolio.v1.Portfolio + (*BankAccount)(nil), // 18: mgo.portfolio.v1.BankAccount + (*PortfolioSnapshot)(nil), // 19: mgo.portfolio.v1.PortfolioSnapshot + (*PortfolioPosition)(nil), // 20: mgo.portfolio.v1.PortfolioPosition + (*PortfolioEvent)(nil), // 21: mgo.portfolio.v1.PortfolioEvent + (*Security)(nil), // 22: mgo.portfolio.v1.Security + (*ListedSecurity)(nil), // 23: mgo.portfolio.v1.ListedSecurity + (*ListSecuritiesRequest)(nil), // 24: mgo.portfolio.v1.ListSecuritiesRequest + (*ListSecuritiesResponse)(nil), // 25: mgo.portfolio.v1.ListSecuritiesResponse + (*GetSecurityRequest)(nil), // 26: mgo.portfolio.v1.GetSecurityRequest + (*CreateSecurityRequest)(nil), // 27: mgo.portfolio.v1.CreateSecurityRequest + (*UpdateSecurityRequest)(nil), // 28: mgo.portfolio.v1.UpdateSecurityRequest + (*DeleteSecurityRequest)(nil), // 29: mgo.portfolio.v1.DeleteSecurityRequest + (*TriggerQuoteUpdateRequest)(nil), // 30: mgo.portfolio.v1.TriggerQuoteUpdateRequest + (*TriggerQuoteUpdateResponse)(nil), // 31: mgo.portfolio.v1.TriggerQuoteUpdateResponse + nil, // 32: mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry + (*ListSecuritiesRequest_Filter)(nil), // 33: mgo.portfolio.v1.ListSecuritiesRequest.Filter + (*fieldmaskpb.FieldMask)(nil), // 34: google.protobuf.FieldMask + (*timestamppb.Timestamp)(nil), // 35: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 36: google.protobuf.Empty } var file_mgo_proto_depIdxs = []int32{ - 16, // 0: mgo.portfolio.v1.CreatePortfolioRequest.portfolio:type_name -> mgo.portfolio.v1.Portfolio - 16, // 1: mgo.portfolio.v1.ListPortfoliosResponse.portfolios:type_name -> mgo.portfolio.v1.Portfolio - 16, // 2: mgo.portfolio.v1.UpdatePortfolioRequest.portfolio:type_name -> mgo.portfolio.v1.Portfolio - 32, // 3: mgo.portfolio.v1.UpdatePortfolioRequest.update_mask:type_name -> google.protobuf.FieldMask - 33, // 4: mgo.portfolio.v1.GetPortfolioSnapshotRequest.time:type_name -> google.protobuf.Timestamp - 19, // 5: mgo.portfolio.v1.CreatePortfolioTransactionRequest.transaction:type_name -> mgo.portfolio.v1.PortfolioEvent - 19, // 6: mgo.portfolio.v1.ListPortfolioTransactionsResponse.transactions:type_name -> mgo.portfolio.v1.PortfolioEvent - 19, // 7: mgo.portfolio.v1.UpdatePortfolioTransactionRequest.transaction:type_name -> mgo.portfolio.v1.PortfolioEvent - 32, // 8: mgo.portfolio.v1.UpdatePortfolioTransactionRequest.update_mask:type_name -> google.protobuf.FieldMask - 19, // 9: mgo.portfolio.v1.Portfolio.events:type_name -> mgo.portfolio.v1.PortfolioEvent - 33, // 10: mgo.portfolio.v1.PortfolioSnapshot.time:type_name -> google.protobuf.Timestamp - 30, // 11: mgo.portfolio.v1.PortfolioSnapshot.positions:type_name -> mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry - 33, // 12: mgo.portfolio.v1.PortfolioSnapshot.first_transaction_time:type_name -> google.protobuf.Timestamp - 1, // 13: mgo.portfolio.v1.PortfolioSnapshot.total_purchase_value:type_name -> mgo.portfolio.v1.Currency - 1, // 14: mgo.portfolio.v1.PortfolioSnapshot.total_market_value:type_name -> mgo.portfolio.v1.Currency - 1, // 15: mgo.portfolio.v1.PortfolioSnapshot.total_profit_or_loss:type_name -> mgo.portfolio.v1.Currency - 20, // 16: mgo.portfolio.v1.PortfolioPosition.security:type_name -> mgo.portfolio.v1.Security - 1, // 17: mgo.portfolio.v1.PortfolioPosition.purchase_value:type_name -> mgo.portfolio.v1.Currency - 1, // 18: mgo.portfolio.v1.PortfolioPosition.purchase_price:type_name -> mgo.portfolio.v1.Currency - 1, // 19: mgo.portfolio.v1.PortfolioPosition.market_value:type_name -> mgo.portfolio.v1.Currency - 1, // 20: mgo.portfolio.v1.PortfolioPosition.market_price:type_name -> mgo.portfolio.v1.Currency - 1, // 21: mgo.portfolio.v1.PortfolioPosition.total_fees:type_name -> mgo.portfolio.v1.Currency - 1, // 22: mgo.portfolio.v1.PortfolioPosition.profit_or_loss:type_name -> mgo.portfolio.v1.Currency - 0, // 23: mgo.portfolio.v1.PortfolioEvent.type:type_name -> mgo.portfolio.v1.PortfolioEventType - 33, // 24: mgo.portfolio.v1.PortfolioEvent.time:type_name -> google.protobuf.Timestamp - 1, // 25: mgo.portfolio.v1.PortfolioEvent.price:type_name -> mgo.portfolio.v1.Currency - 1, // 26: mgo.portfolio.v1.PortfolioEvent.fees:type_name -> mgo.portfolio.v1.Currency - 1, // 27: mgo.portfolio.v1.PortfolioEvent.taxes:type_name -> mgo.portfolio.v1.Currency - 21, // 28: mgo.portfolio.v1.Security.listed_on:type_name -> mgo.portfolio.v1.ListedSecurity - 1, // 29: mgo.portfolio.v1.ListedSecurity.latest_quote:type_name -> mgo.portfolio.v1.Currency - 33, // 30: mgo.portfolio.v1.ListedSecurity.latest_quote_timestamp:type_name -> google.protobuf.Timestamp - 31, // 31: mgo.portfolio.v1.ListSecuritiesRequest.filter:type_name -> mgo.portfolio.v1.ListSecuritiesRequest.Filter - 20, // 32: mgo.portfolio.v1.ListSecuritiesResponse.securities:type_name -> mgo.portfolio.v1.Security - 20, // 33: mgo.portfolio.v1.CreateSecurityRequest.security:type_name -> mgo.portfolio.v1.Security - 20, // 34: mgo.portfolio.v1.UpdateSecurityRequest.security:type_name -> mgo.portfolio.v1.Security - 32, // 35: mgo.portfolio.v1.UpdateSecurityRequest.update_mask:type_name -> google.protobuf.FieldMask - 18, // 36: mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry.value:type_name -> mgo.portfolio.v1.PortfolioPosition - 2, // 37: mgo.portfolio.v1.PortfolioService.CreatePortfolio:input_type -> mgo.portfolio.v1.CreatePortfolioRequest - 3, // 38: mgo.portfolio.v1.PortfolioService.ListPortfolios:input_type -> mgo.portfolio.v1.ListPortfoliosRequest - 5, // 39: mgo.portfolio.v1.PortfolioService.GetPortfolio:input_type -> mgo.portfolio.v1.GetPortfolioRequest - 6, // 40: mgo.portfolio.v1.PortfolioService.UpdatePortfolio:input_type -> mgo.portfolio.v1.UpdatePortfolioRequest - 7, // 41: mgo.portfolio.v1.PortfolioService.DeletePortfolio:input_type -> mgo.portfolio.v1.DeletePortfolioRequest - 8, // 42: mgo.portfolio.v1.PortfolioService.GetPortfolioSnapshot:input_type -> mgo.portfolio.v1.GetPortfolioSnapshotRequest - 9, // 43: mgo.portfolio.v1.PortfolioService.CreatePortfolioTransaction:input_type -> mgo.portfolio.v1.CreatePortfolioTransactionRequest - 10, // 44: mgo.portfolio.v1.PortfolioService.GetPortfolioTransaction:input_type -> mgo.portfolio.v1.GetPortfolioTransactionRequest - 11, // 45: mgo.portfolio.v1.PortfolioService.ListPortfolioTransactions:input_type -> mgo.portfolio.v1.ListPortfolioTransactionsRequest - 13, // 46: mgo.portfolio.v1.PortfolioService.UpdatePortfolioTransaction:input_type -> mgo.portfolio.v1.UpdatePortfolioTransactionRequest - 14, // 47: mgo.portfolio.v1.PortfolioService.DeletePortfolioTransaction:input_type -> mgo.portfolio.v1.DeletePortfolioTransactionRequest - 15, // 48: mgo.portfolio.v1.PortfolioService.ImportTransactions:input_type -> mgo.portfolio.v1.ImportTransactionsRequest - 22, // 49: mgo.portfolio.v1.SecuritiesService.ListSecurities:input_type -> mgo.portfolio.v1.ListSecuritiesRequest - 24, // 50: mgo.portfolio.v1.SecuritiesService.GetSecurity:input_type -> mgo.portfolio.v1.GetSecurityRequest - 25, // 51: mgo.portfolio.v1.SecuritiesService.CreateSecurity:input_type -> mgo.portfolio.v1.CreateSecurityRequest - 26, // 52: mgo.portfolio.v1.SecuritiesService.UpdateSecurity:input_type -> mgo.portfolio.v1.UpdateSecurityRequest - 27, // 53: mgo.portfolio.v1.SecuritiesService.DeleteSecurity:input_type -> mgo.portfolio.v1.DeleteSecurityRequest - 28, // 54: mgo.portfolio.v1.SecuritiesService.TriggerSecurityQuoteUpdate:input_type -> mgo.portfolio.v1.TriggerQuoteUpdateRequest - 16, // 55: mgo.portfolio.v1.PortfolioService.CreatePortfolio:output_type -> mgo.portfolio.v1.Portfolio - 4, // 56: mgo.portfolio.v1.PortfolioService.ListPortfolios:output_type -> mgo.portfolio.v1.ListPortfoliosResponse - 16, // 57: mgo.portfolio.v1.PortfolioService.GetPortfolio:output_type -> mgo.portfolio.v1.Portfolio - 16, // 58: mgo.portfolio.v1.PortfolioService.UpdatePortfolio:output_type -> mgo.portfolio.v1.Portfolio - 34, // 59: mgo.portfolio.v1.PortfolioService.DeletePortfolio:output_type -> google.protobuf.Empty - 17, // 60: mgo.portfolio.v1.PortfolioService.GetPortfolioSnapshot:output_type -> mgo.portfolio.v1.PortfolioSnapshot - 19, // 61: mgo.portfolio.v1.PortfolioService.CreatePortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent - 19, // 62: mgo.portfolio.v1.PortfolioService.GetPortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent - 12, // 63: mgo.portfolio.v1.PortfolioService.ListPortfolioTransactions:output_type -> mgo.portfolio.v1.ListPortfolioTransactionsResponse - 19, // 64: mgo.portfolio.v1.PortfolioService.UpdatePortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent - 34, // 65: mgo.portfolio.v1.PortfolioService.DeletePortfolioTransaction:output_type -> google.protobuf.Empty - 34, // 66: mgo.portfolio.v1.PortfolioService.ImportTransactions:output_type -> google.protobuf.Empty - 23, // 67: mgo.portfolio.v1.SecuritiesService.ListSecurities:output_type -> mgo.portfolio.v1.ListSecuritiesResponse - 20, // 68: mgo.portfolio.v1.SecuritiesService.GetSecurity:output_type -> mgo.portfolio.v1.Security - 20, // 69: mgo.portfolio.v1.SecuritiesService.CreateSecurity:output_type -> mgo.portfolio.v1.Security - 20, // 70: mgo.portfolio.v1.SecuritiesService.UpdateSecurity:output_type -> mgo.portfolio.v1.Security - 34, // 71: mgo.portfolio.v1.SecuritiesService.DeleteSecurity:output_type -> google.protobuf.Empty - 29, // 72: mgo.portfolio.v1.SecuritiesService.TriggerSecurityQuoteUpdate:output_type -> mgo.portfolio.v1.TriggerQuoteUpdateResponse - 55, // [55:73] is the sub-list for method output_type - 37, // [37:55] is the sub-list for method input_type - 37, // [37:37] is the sub-list for extension type_name - 37, // [37:37] is the sub-list for extension extendee - 0, // [0:37] is the sub-list for field type_name + 17, // 0: mgo.portfolio.v1.CreatePortfolioRequest.portfolio:type_name -> mgo.portfolio.v1.Portfolio + 17, // 1: mgo.portfolio.v1.ListPortfoliosResponse.portfolios:type_name -> mgo.portfolio.v1.Portfolio + 17, // 2: mgo.portfolio.v1.UpdatePortfolioRequest.portfolio:type_name -> mgo.portfolio.v1.Portfolio + 34, // 3: mgo.portfolio.v1.UpdatePortfolioRequest.update_mask:type_name -> google.protobuf.FieldMask + 35, // 4: mgo.portfolio.v1.GetPortfolioSnapshotRequest.time:type_name -> google.protobuf.Timestamp + 21, // 5: mgo.portfolio.v1.CreatePortfolioTransactionRequest.transaction:type_name -> mgo.portfolio.v1.PortfolioEvent + 21, // 6: mgo.portfolio.v1.ListPortfolioTransactionsResponse.transactions:type_name -> mgo.portfolio.v1.PortfolioEvent + 21, // 7: mgo.portfolio.v1.UpdatePortfolioTransactionRequest.transaction:type_name -> mgo.portfolio.v1.PortfolioEvent + 34, // 8: mgo.portfolio.v1.UpdatePortfolioTransactionRequest.update_mask:type_name -> google.protobuf.FieldMask + 18, // 9: mgo.portfolio.v1.CreateBankAccountRequest.bank_account:type_name -> mgo.portfolio.v1.BankAccount + 21, // 10: mgo.portfolio.v1.Portfolio.events:type_name -> mgo.portfolio.v1.PortfolioEvent + 35, // 11: mgo.portfolio.v1.PortfolioSnapshot.time:type_name -> google.protobuf.Timestamp + 32, // 12: mgo.portfolio.v1.PortfolioSnapshot.positions:type_name -> mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry + 35, // 13: mgo.portfolio.v1.PortfolioSnapshot.first_transaction_time:type_name -> google.protobuf.Timestamp + 1, // 14: mgo.portfolio.v1.PortfolioSnapshot.total_purchase_value:type_name -> mgo.portfolio.v1.Currency + 1, // 15: mgo.portfolio.v1.PortfolioSnapshot.total_market_value:type_name -> mgo.portfolio.v1.Currency + 1, // 16: mgo.portfolio.v1.PortfolioSnapshot.total_profit_or_loss:type_name -> mgo.portfolio.v1.Currency + 1, // 17: mgo.portfolio.v1.PortfolioSnapshot.cash:type_name -> mgo.portfolio.v1.Currency + 1, // 18: mgo.portfolio.v1.PortfolioSnapshot.total_portfolio_value:type_name -> mgo.portfolio.v1.Currency + 22, // 19: mgo.portfolio.v1.PortfolioPosition.security:type_name -> mgo.portfolio.v1.Security + 1, // 20: mgo.portfolio.v1.PortfolioPosition.purchase_value:type_name -> mgo.portfolio.v1.Currency + 1, // 21: mgo.portfolio.v1.PortfolioPosition.purchase_price:type_name -> mgo.portfolio.v1.Currency + 1, // 22: mgo.portfolio.v1.PortfolioPosition.market_value:type_name -> mgo.portfolio.v1.Currency + 1, // 23: mgo.portfolio.v1.PortfolioPosition.market_price:type_name -> mgo.portfolio.v1.Currency + 1, // 24: mgo.portfolio.v1.PortfolioPosition.total_fees:type_name -> mgo.portfolio.v1.Currency + 1, // 25: mgo.portfolio.v1.PortfolioPosition.profit_or_loss:type_name -> mgo.portfolio.v1.Currency + 0, // 26: mgo.portfolio.v1.PortfolioEvent.type:type_name -> mgo.portfolio.v1.PortfolioEventType + 35, // 27: mgo.portfolio.v1.PortfolioEvent.time:type_name -> google.protobuf.Timestamp + 1, // 28: mgo.portfolio.v1.PortfolioEvent.price:type_name -> mgo.portfolio.v1.Currency + 1, // 29: mgo.portfolio.v1.PortfolioEvent.fees:type_name -> mgo.portfolio.v1.Currency + 1, // 30: mgo.portfolio.v1.PortfolioEvent.taxes:type_name -> mgo.portfolio.v1.Currency + 23, // 31: mgo.portfolio.v1.Security.listed_on:type_name -> mgo.portfolio.v1.ListedSecurity + 1, // 32: mgo.portfolio.v1.ListedSecurity.latest_quote:type_name -> mgo.portfolio.v1.Currency + 35, // 33: mgo.portfolio.v1.ListedSecurity.latest_quote_timestamp:type_name -> google.protobuf.Timestamp + 33, // 34: mgo.portfolio.v1.ListSecuritiesRequest.filter:type_name -> mgo.portfolio.v1.ListSecuritiesRequest.Filter + 22, // 35: mgo.portfolio.v1.ListSecuritiesResponse.securities:type_name -> mgo.portfolio.v1.Security + 22, // 36: mgo.portfolio.v1.CreateSecurityRequest.security:type_name -> mgo.portfolio.v1.Security + 22, // 37: mgo.portfolio.v1.UpdateSecurityRequest.security:type_name -> mgo.portfolio.v1.Security + 34, // 38: mgo.portfolio.v1.UpdateSecurityRequest.update_mask:type_name -> google.protobuf.FieldMask + 20, // 39: mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry.value:type_name -> mgo.portfolio.v1.PortfolioPosition + 2, // 40: mgo.portfolio.v1.PortfolioService.CreatePortfolio:input_type -> mgo.portfolio.v1.CreatePortfolioRequest + 3, // 41: mgo.portfolio.v1.PortfolioService.ListPortfolios:input_type -> mgo.portfolio.v1.ListPortfoliosRequest + 5, // 42: mgo.portfolio.v1.PortfolioService.GetPortfolio:input_type -> mgo.portfolio.v1.GetPortfolioRequest + 6, // 43: mgo.portfolio.v1.PortfolioService.UpdatePortfolio:input_type -> mgo.portfolio.v1.UpdatePortfolioRequest + 7, // 44: mgo.portfolio.v1.PortfolioService.DeletePortfolio:input_type -> mgo.portfolio.v1.DeletePortfolioRequest + 8, // 45: mgo.portfolio.v1.PortfolioService.GetPortfolioSnapshot:input_type -> mgo.portfolio.v1.GetPortfolioSnapshotRequest + 9, // 46: mgo.portfolio.v1.PortfolioService.CreatePortfolioTransaction:input_type -> mgo.portfolio.v1.CreatePortfolioTransactionRequest + 10, // 47: mgo.portfolio.v1.PortfolioService.GetPortfolioTransaction:input_type -> mgo.portfolio.v1.GetPortfolioTransactionRequest + 11, // 48: mgo.portfolio.v1.PortfolioService.ListPortfolioTransactions:input_type -> mgo.portfolio.v1.ListPortfolioTransactionsRequest + 13, // 49: mgo.portfolio.v1.PortfolioService.UpdatePortfolioTransaction:input_type -> mgo.portfolio.v1.UpdatePortfolioTransactionRequest + 14, // 50: mgo.portfolio.v1.PortfolioService.DeletePortfolioTransaction:input_type -> mgo.portfolio.v1.DeletePortfolioTransactionRequest + 15, // 51: mgo.portfolio.v1.PortfolioService.ImportTransactions:input_type -> mgo.portfolio.v1.ImportTransactionsRequest + 16, // 52: mgo.portfolio.v1.PortfolioService.CreateBankAccount:input_type -> mgo.portfolio.v1.CreateBankAccountRequest + 24, // 53: mgo.portfolio.v1.SecuritiesService.ListSecurities:input_type -> mgo.portfolio.v1.ListSecuritiesRequest + 26, // 54: mgo.portfolio.v1.SecuritiesService.GetSecurity:input_type -> mgo.portfolio.v1.GetSecurityRequest + 27, // 55: mgo.portfolio.v1.SecuritiesService.CreateSecurity:input_type -> mgo.portfolio.v1.CreateSecurityRequest + 28, // 56: mgo.portfolio.v1.SecuritiesService.UpdateSecurity:input_type -> mgo.portfolio.v1.UpdateSecurityRequest + 29, // 57: mgo.portfolio.v1.SecuritiesService.DeleteSecurity:input_type -> mgo.portfolio.v1.DeleteSecurityRequest + 30, // 58: mgo.portfolio.v1.SecuritiesService.TriggerSecurityQuoteUpdate:input_type -> mgo.portfolio.v1.TriggerQuoteUpdateRequest + 17, // 59: mgo.portfolio.v1.PortfolioService.CreatePortfolio:output_type -> mgo.portfolio.v1.Portfolio + 4, // 60: mgo.portfolio.v1.PortfolioService.ListPortfolios:output_type -> mgo.portfolio.v1.ListPortfoliosResponse + 17, // 61: mgo.portfolio.v1.PortfolioService.GetPortfolio:output_type -> mgo.portfolio.v1.Portfolio + 17, // 62: mgo.portfolio.v1.PortfolioService.UpdatePortfolio:output_type -> mgo.portfolio.v1.Portfolio + 36, // 63: mgo.portfolio.v1.PortfolioService.DeletePortfolio:output_type -> google.protobuf.Empty + 19, // 64: mgo.portfolio.v1.PortfolioService.GetPortfolioSnapshot:output_type -> mgo.portfolio.v1.PortfolioSnapshot + 21, // 65: mgo.portfolio.v1.PortfolioService.CreatePortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent + 21, // 66: mgo.portfolio.v1.PortfolioService.GetPortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent + 12, // 67: mgo.portfolio.v1.PortfolioService.ListPortfolioTransactions:output_type -> mgo.portfolio.v1.ListPortfolioTransactionsResponse + 21, // 68: mgo.portfolio.v1.PortfolioService.UpdatePortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent + 36, // 69: mgo.portfolio.v1.PortfolioService.DeletePortfolioTransaction:output_type -> google.protobuf.Empty + 36, // 70: mgo.portfolio.v1.PortfolioService.ImportTransactions:output_type -> google.protobuf.Empty + 18, // 71: mgo.portfolio.v1.PortfolioService.CreateBankAccount:output_type -> mgo.portfolio.v1.BankAccount + 25, // 72: mgo.portfolio.v1.SecuritiesService.ListSecurities:output_type -> mgo.portfolio.v1.ListSecuritiesResponse + 22, // 73: mgo.portfolio.v1.SecuritiesService.GetSecurity:output_type -> mgo.portfolio.v1.Security + 22, // 74: mgo.portfolio.v1.SecuritiesService.CreateSecurity:output_type -> mgo.portfolio.v1.Security + 22, // 75: mgo.portfolio.v1.SecuritiesService.UpdateSecurity:output_type -> mgo.portfolio.v1.Security + 36, // 76: mgo.portfolio.v1.SecuritiesService.DeleteSecurity:output_type -> google.protobuf.Empty + 31, // 77: mgo.portfolio.v1.SecuritiesService.TriggerSecurityQuoteUpdate:output_type -> mgo.portfolio.v1.TriggerQuoteUpdateResponse + 59, // [59:78] is the sub-list for method output_type + 40, // [40:59] is the sub-list for method input_type + 40, // [40:40] is the sub-list for extension type_name + 40, // [40:40] is the sub-list for extension extendee + 0, // [0:40] is the sub-list for field type_name } func init() { file_mgo_proto_init() } @@ -2538,7 +2731,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Portfolio); i { + switch v := v.(*CreateBankAccountRequest); i { case 0: return &v.state case 1: @@ -2550,7 +2743,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PortfolioSnapshot); i { + switch v := v.(*Portfolio); i { case 0: return &v.state case 1: @@ -2562,7 +2755,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PortfolioPosition); i { + switch v := v.(*BankAccount); i { case 0: return &v.state case 1: @@ -2574,7 +2767,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PortfolioEvent); i { + switch v := v.(*PortfolioSnapshot); i { case 0: return &v.state case 1: @@ -2586,7 +2779,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Security); i { + switch v := v.(*PortfolioPosition); i { case 0: return &v.state case 1: @@ -2598,7 +2791,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListedSecurity); i { + switch v := v.(*PortfolioEvent); i { case 0: return &v.state case 1: @@ -2610,7 +2803,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListSecuritiesRequest); i { + switch v := v.(*Security); i { case 0: return &v.state case 1: @@ -2622,7 +2815,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListSecuritiesResponse); i { + switch v := v.(*ListedSecurity); i { case 0: return &v.state case 1: @@ -2634,7 +2827,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSecurityRequest); i { + switch v := v.(*ListSecuritiesRequest); i { case 0: return &v.state case 1: @@ -2646,7 +2839,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateSecurityRequest); i { + switch v := v.(*ListSecuritiesResponse); i { case 0: return &v.state case 1: @@ -2658,7 +2851,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateSecurityRequest); i { + switch v := v.(*GetSecurityRequest); i { case 0: return &v.state case 1: @@ -2670,7 +2863,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteSecurityRequest); i { + switch v := v.(*CreateSecurityRequest); i { case 0: return &v.state case 1: @@ -2682,7 +2875,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TriggerQuoteUpdateRequest); i { + switch v := v.(*UpdateSecurityRequest); i { case 0: return &v.state case 1: @@ -2694,7 +2887,19 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TriggerQuoteUpdateResponse); i { + switch v := v.(*DeleteSecurityRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_mgo_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TriggerQuoteUpdateRequest); i { case 0: return &v.state case 1: @@ -2706,6 +2911,18 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TriggerQuoteUpdateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_mgo_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListSecuritiesRequest_Filter); i { case 0: return &v.state @@ -2718,17 +2935,17 @@ func file_mgo_proto_init() { } } } - file_mgo_proto_msgTypes[16].OneofWrappers = []interface{}{} - file_mgo_proto_msgTypes[19].OneofWrappers = []interface{}{} - file_mgo_proto_msgTypes[20].OneofWrappers = []interface{}{} + file_mgo_proto_msgTypes[18].OneofWrappers = []interface{}{} file_mgo_proto_msgTypes[21].OneofWrappers = []interface{}{} + file_mgo_proto_msgTypes[22].OneofWrappers = []interface{}{} + file_mgo_proto_msgTypes[23].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_mgo_proto_rawDesc, NumEnums: 1, - NumMessages: 31, + NumMessages: 33, NumExtensions: 0, NumServices: 2, }, diff --git a/gen/portfolio.go b/gen/portfolio.go index afcdbe2c..51da4595 100644 --- a/gen/portfolio.go +++ b/gen/portfolio.go @@ -1,10 +1,23 @@ +// Copyright 2023 Christian Banse +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is part of The Money Gopher. package portfoliov1 import ( - "fmt" "hash/fnv" "log/slog" - "math" "strconv" "time" ) @@ -16,6 +29,9 @@ func (p *Portfolio) EventMap() (m map[string][]*PortfolioEvent) { name := tx.GetSecurityName() if name != "" { m[name] = append(m[name], tx) + } else { + // a little bit of a hack + m["cash"] = append(m["cash"], tx) } } @@ -71,57 +87,3 @@ func (ls *ListedSecurity) LogValue() slog.Value { slog.String("ticker", ls.Ticker), ) } - -func Zero() *Currency { - // TODO(oxisto): Somehow make it possible to change default currency - return &Currency{Symbol: "EUR"} -} - -func Value(v int32) *Currency { - // TODO(oxisto): Somehow make it possible to change default currency - return &Currency{Symbol: "EUR", Value: v} -} - -func (c *Currency) PlusAssign(o *Currency) { - if o != nil { - c.Value += o.Value - } -} - -func (c *Currency) MinusAssign(o *Currency) { - if o != nil { - c.Value -= o.Value - } -} - -func Plus(a *Currency, b *Currency) *Currency { - return &Currency{ - Value: a.Value + b.Value, - Symbol: a.Symbol, - } -} - -func Minus(a *Currency, b *Currency) *Currency { - return &Currency{ - Value: a.Value - b.Value, - Symbol: a.Symbol, - } -} - -func Divide(a *Currency, b float64) *Currency { - return &Currency{ - Value: int32(math.Round((float64(a.Value) / b))), - Symbol: a.Symbol, - } -} - -func Times(a *Currency, b float64) *Currency { - return &Currency{ - Value: int32(math.Round((float64(a.Value) * b))), - Symbol: a.Symbol, - } -} - -func (c *Currency) Pretty() string { - return fmt.Sprintf("%.0f %s", float32(c.Value)/100, c.Symbol) -} diff --git a/gen/portfolio_sql.go b/gen/portfolio_sql.go index 9a9bd9a0..d24ee5f1 100644 --- a/gen/portfolio_sql.go +++ b/gen/portfolio_sql.go @@ -1,3 +1,18 @@ +// Copyright 2023 Christian Banse +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is part of The Money Gopher. package portfoliov1 import ( @@ -210,3 +225,76 @@ func (*PortfolioEvent) Scan(sc persistence.Scanner) (obj persistence.StorageObje return &e, nil } + +func (*BankAccount) InitTables(db *persistence.DB) (err error) { + _, err1 := db.Exec(`CREATE TABLE IF NOT EXISTS bank_accounts ( +name TEXT PRIMARY KEY, +display_name TEXT NOT NULL +);`) + err2 := (&PortfolioEvent{}).InitTables(db) + + return errors.Join(err1, err2) +} + +func (*BankAccount) PrepareReplace(db *persistence.DB) (stmt *sql.Stmt, err error) { + return db.Prepare(`REPLACE INTO bank_accounts (name, display_name) VALUES (?,?);`) +} + +func (*BankAccount) PrepareList(db *persistence.DB) (stmt *sql.Stmt, err error) { + return db.Prepare(`SELECT name, display_name FROM bank_accounts`) +} + +func (*BankAccount) PrepareGet(db *persistence.DB) (stmt *sql.Stmt, err error) { + return db.Prepare(`SELECT name, display_name FROM bank_accounts WHERE name = ?`) +} + +func (*BankAccount) PrepareUpdate(db *persistence.DB, columns []string) (stmt *sql.Stmt, err error) { + // We need to make sure to quote columns here because they are potentially evil user input + var ( + query string + set []string + ) + + set = make([]string, len(columns)) + for i, col := range columns { + set[i] = persistence.Quote(col) + " = ?" + } + + query += "UPDATE bank_accounts SET " + strings.Join(set, ", ") + " WHERE name = ?;" + + return db.Prepare(query) +} + +func (*BankAccount) PrepareDelete(db *persistence.DB) (stmt *sql.Stmt, err error) { + return db.Prepare(`DELETE FROM bank_accounts WHERE name = ?`) +} + +func (p *BankAccount) ReplaceIntoArgs() []any { + return []any{p.Name, p.DisplayName} +} + +func (p *BankAccount) UpdateArgs(columns []string) (args []any) { + for _, col := range columns { + switch col { + case "name": + args = append(args, p.Name) + case "display_name": + args = append(args, p.DisplayName) + } + } + + return args +} + +func (*BankAccount) Scan(sc persistence.Scanner) (obj persistence.StorageObject, err error) { + var ( + acc BankAccount + ) + + err = sc.Scan(&acc.Name, &acc.DisplayName) + if err != nil { + return nil, err + } + + return &acc, nil +} diff --git a/gen/portfoliov1connect/mgo.connect.go b/gen/portfoliov1connect/mgo.connect.go index 96b12a66..00d01ca9 100644 --- a/gen/portfoliov1connect/mgo.connect.go +++ b/gen/portfoliov1connect/mgo.connect.go @@ -72,6 +72,9 @@ const ( // PortfolioServiceImportTransactionsProcedure is the fully-qualified name of the PortfolioService's // ImportTransactions RPC. PortfolioServiceImportTransactionsProcedure = "/mgo.portfolio.v1.PortfolioService/ImportTransactions" + // PortfolioServiceCreateBankAccountProcedure is the fully-qualified name of the PortfolioService's + // CreateBankAccount RPC. + PortfolioServiceCreateBankAccountProcedure = "/mgo.portfolio.v1.PortfolioService/CreateBankAccount" // SecuritiesServiceListSecuritiesProcedure is the fully-qualified name of the SecuritiesService's // ListSecurities RPC. SecuritiesServiceListSecuritiesProcedure = "/mgo.portfolio.v1.SecuritiesService/ListSecurities" @@ -107,6 +110,7 @@ var ( portfolioServiceUpdatePortfolioTransactionMethodDescriptor = portfolioServiceServiceDescriptor.Methods().ByName("UpdatePortfolioTransaction") portfolioServiceDeletePortfolioTransactionMethodDescriptor = portfolioServiceServiceDescriptor.Methods().ByName("DeletePortfolioTransaction") portfolioServiceImportTransactionsMethodDescriptor = portfolioServiceServiceDescriptor.Methods().ByName("ImportTransactions") + portfolioServiceCreateBankAccountMethodDescriptor = portfolioServiceServiceDescriptor.Methods().ByName("CreateBankAccount") securitiesServiceServiceDescriptor = gen.File_mgo_proto.Services().ByName("SecuritiesService") securitiesServiceListSecuritiesMethodDescriptor = securitiesServiceServiceDescriptor.Methods().ByName("ListSecurities") securitiesServiceGetSecurityMethodDescriptor = securitiesServiceServiceDescriptor.Methods().ByName("GetSecurity") @@ -130,6 +134,7 @@ type PortfolioServiceClient interface { UpdatePortfolioTransaction(context.Context, *connect.Request[gen.UpdatePortfolioTransactionRequest]) (*connect.Response[gen.PortfolioEvent], error) DeletePortfolioTransaction(context.Context, *connect.Request[gen.DeletePortfolioTransactionRequest]) (*connect.Response[emptypb.Empty], error) ImportTransactions(context.Context, *connect.Request[gen.ImportTransactionsRequest]) (*connect.Response[emptypb.Empty], error) + CreateBankAccount(context.Context, *connect.Request[gen.CreateBankAccountRequest]) (*connect.Response[gen.BankAccount], error) } // NewPortfolioServiceClient constructs a client for the mgo.portfolio.v1.PortfolioService service. @@ -219,6 +224,12 @@ func NewPortfolioServiceClient(httpClient connect.HTTPClient, baseURL string, op connect.WithSchema(portfolioServiceImportTransactionsMethodDescriptor), connect.WithClientOptions(opts...), ), + createBankAccount: connect.NewClient[gen.CreateBankAccountRequest, gen.BankAccount]( + httpClient, + baseURL+PortfolioServiceCreateBankAccountProcedure, + connect.WithSchema(portfolioServiceCreateBankAccountMethodDescriptor), + connect.WithClientOptions(opts...), + ), } } @@ -236,6 +247,7 @@ type portfolioServiceClient struct { updatePortfolioTransaction *connect.Client[gen.UpdatePortfolioTransactionRequest, gen.PortfolioEvent] deletePortfolioTransaction *connect.Client[gen.DeletePortfolioTransactionRequest, emptypb.Empty] importTransactions *connect.Client[gen.ImportTransactionsRequest, emptypb.Empty] + createBankAccount *connect.Client[gen.CreateBankAccountRequest, gen.BankAccount] } // CreatePortfolio calls mgo.portfolio.v1.PortfolioService.CreatePortfolio. @@ -298,6 +310,11 @@ func (c *portfolioServiceClient) ImportTransactions(ctx context.Context, req *co return c.importTransactions.CallUnary(ctx, req) } +// CreateBankAccount calls mgo.portfolio.v1.PortfolioService.CreateBankAccount. +func (c *portfolioServiceClient) CreateBankAccount(ctx context.Context, req *connect.Request[gen.CreateBankAccountRequest]) (*connect.Response[gen.BankAccount], error) { + return c.createBankAccount.CallUnary(ctx, req) +} + // PortfolioServiceHandler is an implementation of the mgo.portfolio.v1.PortfolioService service. type PortfolioServiceHandler interface { CreatePortfolio(context.Context, *connect.Request[gen.CreatePortfolioRequest]) (*connect.Response[gen.Portfolio], error) @@ -312,6 +329,7 @@ type PortfolioServiceHandler interface { UpdatePortfolioTransaction(context.Context, *connect.Request[gen.UpdatePortfolioTransactionRequest]) (*connect.Response[gen.PortfolioEvent], error) DeletePortfolioTransaction(context.Context, *connect.Request[gen.DeletePortfolioTransactionRequest]) (*connect.Response[emptypb.Empty], error) ImportTransactions(context.Context, *connect.Request[gen.ImportTransactionsRequest]) (*connect.Response[emptypb.Empty], error) + CreateBankAccount(context.Context, *connect.Request[gen.CreateBankAccountRequest]) (*connect.Response[gen.BankAccount], error) } // NewPortfolioServiceHandler builds an HTTP handler from the service implementation. It returns the @@ -397,6 +415,12 @@ func NewPortfolioServiceHandler(svc PortfolioServiceHandler, opts ...connect.Han connect.WithSchema(portfolioServiceImportTransactionsMethodDescriptor), connect.WithHandlerOptions(opts...), ) + portfolioServiceCreateBankAccountHandler := connect.NewUnaryHandler( + PortfolioServiceCreateBankAccountProcedure, + svc.CreateBankAccount, + connect.WithSchema(portfolioServiceCreateBankAccountMethodDescriptor), + connect.WithHandlerOptions(opts...), + ) return "/mgo.portfolio.v1.PortfolioService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case PortfolioServiceCreatePortfolioProcedure: @@ -423,6 +447,8 @@ func NewPortfolioServiceHandler(svc PortfolioServiceHandler, opts ...connect.Han portfolioServiceDeletePortfolioTransactionHandler.ServeHTTP(w, r) case PortfolioServiceImportTransactionsProcedure: portfolioServiceImportTransactionsHandler.ServeHTTP(w, r) + case PortfolioServiceCreateBankAccountProcedure: + portfolioServiceCreateBankAccountHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -480,6 +506,10 @@ func (UnimplementedPortfolioServiceHandler) ImportTransactions(context.Context, return nil, connect.NewError(connect.CodeUnimplemented, errors.New("mgo.portfolio.v1.PortfolioService.ImportTransactions is not implemented")) } +func (UnimplementedPortfolioServiceHandler) CreateBankAccount(context.Context, *connect.Request[gen.CreateBankAccountRequest]) (*connect.Response[gen.BankAccount], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("mgo.portfolio.v1.PortfolioService.CreateBankAccount is not implemented")) +} + // SecuritiesServiceClient is a client for the mgo.portfolio.v1.SecuritiesService service. type SecuritiesServiceClient interface { ListSecurities(context.Context, *connect.Request[gen.ListSecuritiesRequest]) (*connect.Response[gen.ListSecuritiesResponse], error) diff --git a/gen/securities_sql.go b/gen/securities_sql.go index 39adbbe4..6a762c88 100644 --- a/gen/securities_sql.go +++ b/gen/securities_sql.go @@ -1,3 +1,18 @@ +// Copyright 2023 Christian Banse +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is part of The Money Gopher. package portfoliov1 import ( diff --git a/mgo.proto b/mgo.proto index 3adc2791..47cfd231 100644 --- a/mgo.proto +++ b/mgo.proto @@ -58,16 +58,28 @@ message ImportTransactionsRequest { string from_csv = 2; } +message CreateBankAccountRequest { BankAccount bank_account = 1; } + message Portfolio { string name = 1; string display_name = 2; + // BankAccountName contains the name/identifier of the underlying bank + // account. + string bank_account_name = 3; + // Events contains all portfolio events, such as buy/sell transactions, // dividends or other. They need to be ordered by time (ascending). repeated PortfolioEvent events = 5; } +message BankAccount { + string name = 1; + + string display_name = 2; +} + // PortfolioSnapshot represents a snapshot in time of the portfolio. It can for // example be the current state of the portfolio but also represent the state of // the portfolio at a certain time in the past. @@ -82,19 +94,27 @@ message PortfolioSnapshot { // snapshot. optional google.protobuf.Timestamp first_transaction_time = 3; - // TotalPurchaseValue contains the total purchase value of all positions + // TotalPurchaseValue contains the total purchase value of all asset positions Currency total_purchase_value = 10; - // TotalMarketValue contains the total market value of all positions + // TotalMarketValue contains the total market value of all asset positions Currency total_market_value = 11; // TotalProfitOrLoss contains the total absolute amount of profit or loss in - // this snapshot. + // this snapshot, based on asset value. Currency total_profit_or_loss = 20; // TotalGains contains the total relative amount of profit or loss in this - // snapshot. + // snapshot, based on asset value. double total_gains = 21; + + // Cash contains the current amount of cash in the portfolio's bank + // account(s). + Currency cash = 22; + + // TotalPortfolioValue contains the amount of cash plus the total market value + // of all assets. + Currency total_portfolio_value = 23; } message PortfolioPosition { @@ -132,11 +152,20 @@ message PortfolioPosition { enum PortfolioEventType { PORTFOLIO_EVENT_TYPE_UNSPECIFIED = 0; + PORTFOLIO_EVENT_TYPE_BUY = 1; PORTFOLIO_EVENT_TYPE_SELL = 2; PORTFOLIO_EVENT_TYPE_DELIVERY_INBOUND = 3; PORTFOLIO_EVENT_TYPE_DELIVERY_OUTBOUND = 4; + PORTFOLIO_EVENT_TYPE_DIVIDEND = 10; + PORTFOLIO_EVENT_TYPE_INTEREST = 11; + + PORTFOLIO_EVENT_TYPE_DEPOSIT_CASH = 20; + PORTFOLIO_EVENT_TYPE_WITHDRAW_CASH = 21; + + PORTFOLIO_EVENT_TYPE_ACCOUNT_FEES = 30; + PORTFOLIO_EVENT_TYPE_TAX_REFUND = 31; } message PortfolioEvent { @@ -185,6 +214,8 @@ service PortfolioService { rpc ImportTransactions(ImportTransactionsRequest) returns (google.protobuf.Empty); + + rpc CreateBankAccount(CreateBankAccountRequest) returns (BankAccount); } message Security { diff --git a/money-gopher.code-workspace b/money-gopher.code-workspace index fa883ead..04b51a42 100644 --- a/money-gopher.code-workspace +++ b/money-gopher.code-workspace @@ -28,6 +28,7 @@ "moneyd", "moneygopher", "mybank", + "mycash", "myportfolio", "oxisto", "portfoliov", diff --git a/service/internal/crud/crud_requests.go b/service/internal/crud/crud_requests.go index c1ca7bb0..8aa8357a 100644 --- a/service/internal/crud/crud_requests.go +++ b/service/internal/crud/crud_requests.go @@ -20,13 +20,27 @@ package crud import ( - "github.com/oxisto/money-gopher/persistence" + "fmt" + "log/slog" + "strings" "connectrpc.com/connect" "google.golang.org/protobuf/types/known/emptypb" + + "github.com/oxisto/money-gopher/persistence" ) func Create[T any, S persistence.StorageObject](obj S, op persistence.StorageOperations[S], convert func(obj S) *T) (res *connect.Response[T], err error) { + var typ = fmt.Sprintf("%T", obj) + + _, typ, _ = strings.Cut(typ, ".") + typ = strings.ToLower(typ) + + slog.Info( + fmt.Sprintf("Creating %s", typ), + typ, obj, + ) + // TODO(oxisto): We probably want to have a pure create instead of replace here err = op.Replace(obj) if err != nil { diff --git a/service/portfolio/account.go b/service/portfolio/account.go new file mode 100644 index 00000000..b9732abe --- /dev/null +++ b/service/portfolio/account.go @@ -0,0 +1,38 @@ +// Copyright 2023 Christian Banse +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is part of The Money Gopher. + +package portfolio + +import ( + "context" + + "connectrpc.com/connect" + + portfoliov1 "github.com/oxisto/money-gopher/gen" + "github.com/oxisto/money-gopher/service/internal/crud" +) + +var bankAccountSetter = func(obj *portfoliov1.BankAccount) *portfoliov1.BankAccount { + return obj +} + +func (svc *service) CreateBankAccount(ctx context.Context, req *connect.Request[portfoliov1.CreateBankAccountRequest]) (res *connect.Response[portfoliov1.BankAccount], err error) { + return crud.Create( + req.Msg.BankAccount, + svc.bankAccounts, + bankAccountSetter, + ) +} diff --git a/service/portfolio/account_test.go b/service/portfolio/account_test.go new file mode 100644 index 00000000..b4632fa4 --- /dev/null +++ b/service/portfolio/account_test.go @@ -0,0 +1,92 @@ +// Copyright 2023 Christian Banse +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file is part of The Money Gopher. + +package portfolio + +import ( + "context" + "testing" + + "connectrpc.com/connect" + "github.com/oxisto/assert" + portfoliov1 "github.com/oxisto/money-gopher/gen" + "github.com/oxisto/money-gopher/gen/portfoliov1connect" + "github.com/oxisto/money-gopher/internal" + "github.com/oxisto/money-gopher/persistence" +) + +func Test_service_CreateBankAccount(t *testing.T) { + type fields struct { + portfolios persistence.StorageOperations[*portfoliov1.Portfolio] + bankAccounts persistence.StorageOperations[*portfoliov1.BankAccount] + securities portfoliov1connect.SecuritiesServiceClient + } + type args struct { + ctx context.Context + req *connect.Request[portfoliov1.CreateBankAccountRequest] + } + tests := []struct { + name string + fields fields + args args + wantRes assert.Want[*connect.Response[portfoliov1.BankAccount]] + wantSvc assert.Want[*service] + wantErr bool + }{ + { + name: "happy path", + fields: fields{ + portfolios: internal.NewTestDBOps[*portfoliov1.Portfolio](t), + bankAccounts: internal.NewTestDBOps[*portfoliov1.BankAccount](t), + }, + args: args{ + req: connect.NewRequest(&portfoliov1.CreateBankAccountRequest{ + BankAccount: &portfoliov1.BankAccount{ + Name: "bank/mycash", + DisplayName: "My Cash Account", + }, + }), + }, + wantRes: func(t *testing.T, r *connect.Response[portfoliov1.BankAccount]) bool { + return true && + assert.Equals(t, "bank/mycash", r.Msg.Name) && + assert.Equals(t, "My Cash Account", r.Msg.DisplayName) + }, + wantSvc: func(t *testing.T, s *service) bool { + list, _ := s.bankAccounts.List() + return assert.Equals(t, 1, len(list)) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + svc := &service{ + portfolios: tt.fields.portfolios, + events: persistence.Relationship[*portfoliov1.PortfolioEvent](tt.fields.portfolios), + bankAccounts: tt.fields.bankAccounts, + securities: tt.fields.securities, + } + gotRes, err := svc.CreateBankAccount(tt.args.ctx, tt.args.req) + if (err != nil) != tt.wantErr { + t.Errorf("service.CreateBankAccount() error = %v, wantErr %v", err, tt.wantErr) + return + } + tt.wantRes(t, gotRes) + tt.wantSvc(t, svc) + }) + } +} diff --git a/service/portfolio/service.go b/service/portfolio/service.go index f294de25..ea8aaab6 100644 --- a/service/portfolio/service.go +++ b/service/portfolio/service.go @@ -29,9 +29,10 @@ const DefaultSecuritiesServiceURL = "http://localhost:8080" // service is the main struct fo the [PortfolioService] implementation. type service struct { - portfolios persistence.StorageOperations[*portfoliov1.Portfolio] - events persistence.StorageOperations[*portfoliov1.PortfolioEvent] - securities portfoliov1connect.SecuritiesServiceClient + portfolios persistence.StorageOperations[*portfoliov1.Portfolio] + events persistence.StorageOperations[*portfoliov1.PortfolioEvent] + bankAccounts persistence.StorageOperations[*portfoliov1.BankAccount] + securities portfoliov1connect.SecuritiesServiceClient portfoliov1connect.UnimplementedPortfolioServiceHandler } @@ -46,6 +47,7 @@ func NewService(opts Options) portfoliov1connect.PortfolioServiceHandler { s.portfolios = persistence.Ops[*portfoliov1.Portfolio](opts.DB) s.events = persistence.Relationship[*portfoliov1.PortfolioEvent](s.portfolios) + s.bankAccounts = persistence.Ops[*portfoliov1.BankAccount](opts.DB) s.securities = opts.SecuritiesClient if s.securities == nil { @@ -54,8 +56,15 @@ func NewService(opts Options) portfoliov1connect.PortfolioServiceHandler { // Add a simple starter portfolio s.portfolios.Replace(&portfoliov1.Portfolio{ - Name: "bank/myportfolio", - DisplayName: "My Portfolio", + Name: "bank/myportfolio", + DisplayName: "My Portfolio", + BankAccountName: "bank/mycash", + }) + + // Add its cash account + s.bankAccounts.Replace(&portfoliov1.BankAccount{ + Name: "bank/mycash", + DisplayName: "My Cash Account", }) return &s diff --git a/service/portfolio/snapshot.go b/service/portfolio/snapshot.go index c12cd0eb..a8a97ec7 100644 --- a/service/portfolio/snapshot.go +++ b/service/portfolio/snapshot.go @@ -56,6 +56,7 @@ func (svc *service) GetPortfolioSnapshot(ctx context.Context, req *connect.Reque TotalPurchaseValue: portfoliov1.Zero(), TotalMarketValue: portfoliov1.Zero(), TotalProfitOrLoss: portfoliov1.Zero(), + Cash: portfoliov1.Zero(), } // Record the first transaction time @@ -94,10 +95,19 @@ func (svc *service) GetPortfolioSnapshot(ctx context.Context, req *connect.Reque c := finance.NewCalculation(txs) + if name == "cash" { + // Add deposited/withdrawn cash directly + snap.Cash.PlusAssign(c.Cash) + continue + } + if c.Amount == 0 { continue } + // Also add cash that is part of a securities' transaction (e.g., sell/buy) + snap.Cash.PlusAssign(c.Cash) + pos := &portfoliov1.PortfolioPosition{ Security: secmap[name], Amount: c.Amount, @@ -123,6 +133,9 @@ func (svc *service) GetPortfolioSnapshot(ctx context.Context, req *connect.Reque // Calculate total gains snap.TotalGains = float64(portfoliov1.Minus(snap.TotalMarketValue, snap.TotalPurchaseValue).Value) / float64(snap.TotalPurchaseValue.Value) + // Calculate total portfolio value + snap.TotalPortfolioValue = snap.TotalMarketValue.Plus(snap.Cash) + return connect.NewResponse(snap), nil } diff --git a/service/portfolio/transactions.go b/service/portfolio/transactions.go index edd7710d..b3b77e41 100644 --- a/service/portfolio/transactions.go +++ b/service/portfolio/transactions.go @@ -19,6 +19,7 @@ package portfolio import ( "bytes" "context" + "errors" "log/slog" portfoliov1 "github.com/oxisto/money-gopher/gen" @@ -33,9 +34,36 @@ var portfolioEventSetter = func(obj *portfoliov1.PortfolioEvent) *portfoliov1.Po return obj } +var ( + ErrMissingSecurityName = errors.New("the specified transaction type requires a security name") + ErrMissingPrice = errors.New("a transaction requires a price") + ErrMissingAmount = errors.New("the specified transaction type requires an amount") +) + func (svc *service) CreatePortfolioTransaction(ctx context.Context, req *connect.Request[portfoliov1.CreatePortfolioTransactionRequest]) (res *connect.Response[portfoliov1.PortfolioEvent], err error) { + var ( + tx *portfoliov1.PortfolioEvent = req.Msg.Transaction + ) + + // Do some basic validation depending on the type + switch tx.Type { + case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_SELL: + fallthrough + case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY: + if tx.SecurityName == "" { + return nil, connect.NewError(connect.CodeInvalidArgument, ErrMissingSecurityName) + } else if tx.Amount == 0 { + return nil, connect.NewError(connect.CodeInvalidArgument, ErrMissingAmount) + } + } + + // We always need a price + if tx.Price.IsZero() { + return nil, connect.NewError(connect.CodeInvalidArgument, ErrMissingPrice) + } + // Create a unique name for the transaction - req.Msg.Transaction.MakeUniqueName() + tx.MakeUniqueName() slog.Info( "Creating transaction", diff --git a/service/portfolio/transactions_test.go b/service/portfolio/transactions_test.go index 1d3dc09e..20b6c8d5 100644 --- a/service/portfolio/transactions_test.go +++ b/service/portfolio/transactions_test.go @@ -56,6 +56,8 @@ func Test_service_CreatePortfolioTransaction(t *testing.T) { PortfolioName: "bank/myportfolio", Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, SecurityName: "My Security", + Amount: 1, + Price: portfoliov1.Value(2000), }, }), }, diff --git a/ui/.prettierrc b/ui/.prettierrc index c60a8c10..8bc6e864 100644 --- a/ui/.prettierrc +++ b/ui/.prettierrc @@ -4,6 +4,5 @@ "trailingComma": "none", "printWidth": 100, "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], - "pluginSearchDirs": ["."], "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] } diff --git a/ui/src/lib/components/PortfolioBreadcrumb.svelte b/ui/src/lib/components/PortfolioBreadcrumb.svelte index c49ee790..b01a6588 100644 --- a/ui/src/lib/components/PortfolioBreadcrumb.svelte +++ b/ui/src/lib/components/PortfolioBreadcrumb.svelte @@ -63,7 +63,7 @@ class="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400" aria-hidden="true" /> - {Object.values(snapshot.positions).length} Positions + {Object.values(snapshot.positions).length} Position(s)
-{{ asc }} -{{ sortBy }}
@@ -120,7 +118,8 @@ Total Assets + + + + + + + + + + + +
Total
+ Cash Value + + {currency(snapshot.cash)} +
+ Total Portfolio Value + + {currency(snapshot.totalPortfolioValue)} +
diff --git a/ui/src/lib/components/SecurityComboBox.svelte b/ui/src/lib/components/SecurityListBox.svelte similarity index 100% rename from ui/src/lib/components/SecurityComboBox.svelte rename to ui/src/lib/components/SecurityListBox.svelte diff --git a/ui/src/lib/components/TransactionTypeListBox.svelte b/ui/src/lib/components/TransactionTypeListBox.svelte new file mode 100644 index 00000000..b5afbbf0 --- /dev/null +++ b/ui/src/lib/components/TransactionTypeListBox.svelte @@ -0,0 +1,86 @@ + + +
+ + + +
    + {#each types as value (value)} + {@const active = $listbox.active === value} + {@const selected = $listbox.selected === value} +
  • +
    + + {value} + +
    + + {#if selected} + + + {/if} +
  • + {/each} +
+
+
diff --git a/ui/src/lib/gen/mgo_connect.ts b/ui/src/lib/gen/mgo_connect.ts index 32bf8140..03541a3e 100644 --- a/ui/src/lib/gen/mgo_connect.ts +++ b/ui/src/lib/gen/mgo_connect.ts @@ -3,7 +3,7 @@ /* eslint-disable */ // @ts-nocheck -import { CreatePortfolioRequest, CreatePortfolioTransactionRequest, CreateSecurityRequest, DeletePortfolioRequest, DeletePortfolioTransactionRequest, DeleteSecurityRequest, GetPortfolioRequest, GetPortfolioSnapshotRequest, GetPortfolioTransactionRequest, GetSecurityRequest, ImportTransactionsRequest, ListPortfoliosRequest, ListPortfoliosResponse, ListPortfolioTransactionsRequest, ListPortfolioTransactionsResponse, ListSecuritiesRequest, ListSecuritiesResponse, Portfolio, PortfolioEvent, PortfolioSnapshot, Security, TriggerQuoteUpdateRequest, TriggerQuoteUpdateResponse, UpdatePortfolioRequest, UpdatePortfolioTransactionRequest, UpdateSecurityRequest } from "./mgo_pb.js"; +import { BankAccount, CreateBankAccountRequest, CreatePortfolioRequest, CreatePortfolioTransactionRequest, CreateSecurityRequest, DeletePortfolioRequest, DeletePortfolioTransactionRequest, DeleteSecurityRequest, GetPortfolioRequest, GetPortfolioSnapshotRequest, GetPortfolioTransactionRequest, GetSecurityRequest, ImportTransactionsRequest, ListPortfoliosRequest, ListPortfoliosResponse, ListPortfolioTransactionsRequest, ListPortfolioTransactionsResponse, ListSecuritiesRequest, ListSecuritiesResponse, Portfolio, PortfolioEvent, PortfolioSnapshot, Security, TriggerQuoteUpdateRequest, TriggerQuoteUpdateResponse, UpdatePortfolioRequest, UpdatePortfolioTransactionRequest, UpdateSecurityRequest } from "./mgo_pb.js"; import { Empty, MethodIdempotency, MethodKind } from "@bufbuild/protobuf"; /** @@ -125,6 +125,15 @@ export const PortfolioService = { O: Empty, kind: MethodKind.Unary, }, + /** + * @generated from rpc mgo.portfolio.v1.PortfolioService.CreateBankAccount + */ + createBankAccount: { + name: "CreateBankAccount", + I: CreateBankAccountRequest, + O: BankAccount, + kind: MethodKind.Unary, + }, } } as const; diff --git a/ui/src/lib/gen/mgo_pb.ts b/ui/src/lib/gen/mgo_pb.ts index 6f4f5f67..12514fd7 100644 --- a/ui/src/lib/gen/mgo_pb.ts +++ b/ui/src/lib/gen/mgo_pb.ts @@ -39,6 +39,31 @@ export enum PortfolioEventType { * @generated from enum value: PORTFOLIO_EVENT_TYPE_DIVIDEND = 10; */ DIVIDEND = 10, + + /** + * @generated from enum value: PORTFOLIO_EVENT_TYPE_INTEREST = 11; + */ + INTEREST = 11, + + /** + * @generated from enum value: PORTFOLIO_EVENT_TYPE_DEPOSIT_CASH = 20; + */ + DEPOSIT_CASH = 20, + + /** + * @generated from enum value: PORTFOLIO_EVENT_TYPE_WITHDRAW_CASH = 21; + */ + WITHDRAW_CASH = 21, + + /** + * @generated from enum value: PORTFOLIO_EVENT_TYPE_ACCOUNT_FEES = 30; + */ + ACCOUNT_FEES = 30, + + /** + * @generated from enum value: PORTFOLIO_EVENT_TYPE_TAX_REFUND = 31; + */ + TAX_REFUND = 31, } // Retrieve enum metadata with: proto3.getEnumType(PortfolioEventType) proto3.util.setEnumType(PortfolioEventType, "mgo.portfolio.v1.PortfolioEventType", [ @@ -48,6 +73,11 @@ proto3.util.setEnumType(PortfolioEventType, "mgo.portfolio.v1.PortfolioEventType { no: 3, name: "PORTFOLIO_EVENT_TYPE_DELIVERY_INBOUND" }, { no: 4, name: "PORTFOLIO_EVENT_TYPE_DELIVERY_OUTBOUND" }, { no: 10, name: "PORTFOLIO_EVENT_TYPE_DIVIDEND" }, + { no: 11, name: "PORTFOLIO_EVENT_TYPE_INTEREST" }, + { no: 20, name: "PORTFOLIO_EVENT_TYPE_DEPOSIT_CASH" }, + { no: 21, name: "PORTFOLIO_EVENT_TYPE_WITHDRAW_CASH" }, + { no: 30, name: "PORTFOLIO_EVENT_TYPE_ACCOUNT_FEES" }, + { no: 31, name: "PORTFOLIO_EVENT_TYPE_TAX_REFUND" }, ]); /** @@ -637,6 +667,43 @@ export class ImportTransactionsRequest extends Message { + /** + * @generated from field: mgo.portfolio.v1.BankAccount bank_account = 1; + */ + bankAccount?: BankAccount; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "mgo.portfolio.v1.CreateBankAccountRequest"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "bank_account", kind: "message", T: BankAccount }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): CreateBankAccountRequest { + return new CreateBankAccountRequest().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): CreateBankAccountRequest { + return new CreateBankAccountRequest().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): CreateBankAccountRequest { + return new CreateBankAccountRequest().fromJsonString(jsonString, options); + } + + static equals(a: CreateBankAccountRequest | PlainMessage | undefined, b: CreateBankAccountRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(CreateBankAccountRequest, a, b); + } +} + /** * @generated from message mgo.portfolio.v1.Portfolio */ @@ -651,6 +718,14 @@ export class Portfolio extends Message { */ displayName = ""; + /** + * BankAccountName contains the name/identifier of the underlying bank + * account. + * + * @generated from field: string bank_account_name = 3; + */ + bankAccountName = ""; + /** * Events contains all portfolio events, such as buy/sell transactions, * dividends or other. They need to be ordered by time (ascending). @@ -669,6 +744,7 @@ export class Portfolio extends Message { static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "bank_account_name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 5, name: "events", kind: "message", T: PortfolioEvent, repeated: true }, ]); @@ -689,6 +765,49 @@ export class Portfolio extends Message { } } +/** + * @generated from message mgo.portfolio.v1.BankAccount + */ +export class BankAccount extends Message { + /** + * @generated from field: string name = 1; + */ + name = ""; + + /** + * @generated from field: string display_name = 2; + */ + displayName = ""; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "mgo.portfolio.v1.BankAccount"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "display_name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): BankAccount { + return new BankAccount().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): BankAccount { + return new BankAccount().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): BankAccount { + return new BankAccount().fromJsonString(jsonString, options); + } + + static equals(a: BankAccount | PlainMessage | undefined, b: BankAccount | PlainMessage | undefined): boolean { + return proto3.util.equals(BankAccount, a, b); + } +} + /** * PortfolioSnapshot represents a snapshot in time of the portfolio. It can for * example be the current state of the portfolio but also represent the state of @@ -720,14 +839,14 @@ export class PortfolioSnapshot extends Message { firstTransactionTime?: Timestamp; /** - * TotalPurchaseValue contains the total purchase value of all positions + * TotalPurchaseValue contains the total purchase value of all asset positions * * @generated from field: mgo.portfolio.v1.Currency total_purchase_value = 10; */ totalPurchaseValue?: Currency; /** - * TotalMarketValue contains the total market value of all positions + * TotalMarketValue contains the total market value of all asset positions * * @generated from field: mgo.portfolio.v1.Currency total_market_value = 11; */ @@ -735,7 +854,7 @@ export class PortfolioSnapshot extends Message { /** * TotalProfitOrLoss contains the total absolute amount of profit or loss in - * this snapshot. + * this snapshot, based on asset value. * * @generated from field: mgo.portfolio.v1.Currency total_profit_or_loss = 20; */ @@ -743,12 +862,28 @@ export class PortfolioSnapshot extends Message { /** * TotalGains contains the total relative amount of profit or loss in this - * snapshot. + * snapshot, based on asset value. * * @generated from field: double total_gains = 21; */ totalGains = 0; + /** + * Cash contains the current amount of cash in the portfolio's bank + * account(s). + * + * @generated from field: mgo.portfolio.v1.Currency cash = 22; + */ + cash?: Currency; + + /** + * TotalPortfolioValue contains the amount of cash plus the total market value + * of all assets. + * + * @generated from field: mgo.portfolio.v1.Currency total_portfolio_value = 23; + */ + totalPortfolioValue?: Currency; + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); @@ -764,6 +899,8 @@ export class PortfolioSnapshot extends Message { { no: 11, name: "total_market_value", kind: "message", T: Currency }, { no: 20, name: "total_profit_or_loss", kind: "message", T: Currency }, { no: 21, name: "total_gains", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ }, + { no: 22, name: "cash", kind: "message", T: Currency }, + { no: 23, name: "total_portfolio_value", kind: "message", T: Currency }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): PortfolioSnapshot { diff --git a/ui/src/routes/(app)/portfolios/[...portfolioName]/+layout.svelte b/ui/src/routes/(app)/portfolios/[...portfolioName]/+layout.svelte new file mode 100644 index 00000000..6f9ba6c6 --- /dev/null +++ b/ui/src/routes/(app)/portfolios/[...portfolioName]/+layout.svelte @@ -0,0 +1,9 @@ + + + + diff --git a/ui/src/routes/(app)/portfolios/[...portfolioName]/+page.svelte b/ui/src/routes/(app)/portfolios/[...portfolioName]/+page.svelte index a8d809cf..37901d46 100644 --- a/ui/src/routes/(app)/portfolios/[...portfolioName]/+page.svelte +++ b/ui/src/routes/(app)/portfolios/[...portfolioName]/+page.svelte @@ -1,12 +1,10 @@ - Show transactions list diff --git a/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/+page.svelte b/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/+page.svelte index d410da31..da178a52 100644 --- a/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/+page.svelte +++ b/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/+page.svelte @@ -5,4 +5,4 @@ export let data: PageData; - + diff --git a/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/[txName]/+page.svelte b/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/[txName]/+page.svelte index f8260bde..2ef3d533 100644 --- a/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/[txName]/+page.svelte +++ b/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/[txName]/+page.svelte @@ -3,13 +3,14 @@ import { portfolioClient } from '$lib/api/client'; import Button from '$lib/components/Button.svelte'; import CurrencyInput from '$lib/components/CurrencyInput.svelte'; - import SecurityComboBox from '$lib/components/SecurityComboBox.svelte'; + import DateInput from '$lib/components/DateTimeInput.svelte'; + import SecurityListBox from '$lib/components/SecurityListBox.svelte'; + import TransactionTypeListBox from '$lib/components/TransactionTypeListBox.svelte'; + import { Currency, PortfolioEventType } from '$lib/gen/mgo_pb'; import { currency } from '$lib/intl'; + import { FieldMask } from '@bufbuild/protobuf'; import { ConnectError } from '@connectrpc/connect'; import type { PageData } from './$types'; - import { FieldMask } from '@bufbuild/protobuf'; - import DateInput from '$lib/components/DateTimeInput.svelte'; - import { Currency } from '$lib/gen/mgo_pb'; export let data: PageData; @@ -22,6 +23,10 @@ (data.transaction.taxes?.value ?? 0)) }); + $: isSecurityTransaction = + data.transaction.type == PortfolioEventType.BUY || + data.transaction.type == PortfolioEventType.SELL; + async function save() { try { let client = portfolioClient(); @@ -56,9 +61,20 @@
-

Add Transaction

+

+ {#if data.add} + Add Transaction + {:else} + Edit Transaction + {/if} +

- This allows you to add a transaction to a portfolio. + {#if data.add} + This allows you to add a transaction to portfolio {data.transaction.portfolioName}. + {:else} + This allows you to edit the existing transaction {data.transaction.name} in + portfolio {data.transaction.portfolioName}. + {/if}

- +
- +
-
- -
- + +
+ +
+
+ +
+ +
+ + /> +
-
+ {/if} Price - Fees - Taxes + {#if isSecurityTransaction} + Fees + Taxes + {/if}
Total
@@ -128,4 +160,6 @@ -{error} +{#if error} + {error} +{/if} diff --git a/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/[txName]/+page.ts b/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/[txName]/+page.ts index 9d34b360..0459ad26 100644 --- a/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/[txName]/+page.ts +++ b/ui/src/routes/(app)/portfolios/[...portfolioName]/transactions/[txName]/+page.ts @@ -1,5 +1,5 @@ import { portfolioClient } from '$lib/api/client'; -import { PortfolioEvent, PortfolioEventType } from '$lib/gen/mgo_pb'; +import { Currency, PortfolioEvent, PortfolioEventType } from '$lib/gen/mgo_pb'; import type { PageLoad } from './$types'; import { Timestamp } from '@bufbuild/protobuf'; @@ -8,6 +8,8 @@ export const load = (async ({ params, parent }) => { const txName = params.txName; const add = txName == 'add'; + const symbol = 'EUR'; + let transaction: PortfolioEvent; if (add) { // Construct a new time, based on "now" but reset the minutes to 0 @@ -19,7 +21,10 @@ export const load = (async ({ params, parent }) => { amount: 1, type: PortfolioEventType.BUY, portfolioName: data.portfolio.name, - time: Timestamp.fromDate(time) + time: Timestamp.fromDate(time), + fees: new Currency({ symbol: symbol, value: 0 }), + taxes: new Currency({ symbol: symbol, value: 0 }), + price: new Currency({ symbol: symbol, value: 0 }) }); } else { const client = portfolioClient(fetch);