From 24829d5971fef665247bae4010278f5ea57a9243 Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Tue, 19 Dec 2023 20:51:55 +0100 Subject: [PATCH] Using a dedicated currency object instead of float (#255) --- cli/commands/portfolio.go | 14 +- finance/calculation.go | 56 +- finance/calculation_test.go | 38 +- gen/mgo.pb.go | 1352 +++++++++-------- gen/portfolio.go | 62 +- gen/portfolio_sql.go | 28 +- gen/portfolio_test.go | 8 +- gen/securities_sql.go | 30 +- import/csv/csv_importer.go | 33 +- import/csv/csv_importer_test.go | 15 +- mgo.proto | 41 +- service/internal/crud/crud_requests.go | 4 +- service/internal/crud/crud_requests_test.go | 5 +- service/portfolio/portfolio.go | 9 +- service/portfolio/portfolio_test.go | 16 +- service/portfolio/snapshot.go | 25 +- service/portfolio/snapshot_test.go | 17 +- service/portfolio/transactions.go | 3 +- service/securities/quote.go | 4 +- service/securities/quote_provider.go | 2 +- service/securities/quote_provider_ing.go | 10 +- service/securities/quote_provider_ing_test.go | 4 +- service/securities/quote_provider_yf.go | 10 +- service/securities/quote_provider_yf_test.go | 4 +- service/securities/quote_test.go | 10 +- service/securities/securities.go | 7 +- service/securities/service.go | 4 +- ui/src/lib/components/CurrencyInput.svelte | 63 +- ui/src/lib/components/PortfolioCard.svelte | 4 +- .../components/PortfolioPositionRow.svelte | 10 +- .../components/PortfolioPositionsTable.svelte | 25 +- .../components/PortfolioTransactionRow.svelte | 15 +- .../PortfolioTransactionsTable.svelte | 6 +- ui/src/lib/gen/mgo_pb.ts | 140 +- ui/src/lib/intl.ts | 12 +- .../transactions/[txName]/+page.svelte | 28 +- ui/src/routes/securities/+page.svelte | 7 +- 37 files changed, 1213 insertions(+), 908 deletions(-) diff --git a/cli/commands/portfolio.go b/cli/commands/portfolio.go index 5cf063a1..349e8e45 100644 --- a/cli/commands/portfolio.go +++ b/cli/commands/portfolio.go @@ -81,10 +81,10 @@ func (l *ListPortfolioCmd) Run(s *cli.Session) error { strings.Repeat("-", 15), strings.Repeat("-", 15), 15, "Market Value", - 15, fmt.Sprintf("%.02f €", snapshot.Msg.TotalMarketValue), + 15, snapshot.Msg.TotalMarketValue.Pretty(), 15, "Performance", 15, fmt.Sprintf("%s € (%s %%)", - greenOrRed(snapshot.Msg.TotalProfitOrLoss), + greenOrRed(float64(snapshot.Msg.TotalProfitOrLoss.Value)), greenOrRed(snapshot.Msg.TotalGains*100), ), ) @@ -148,7 +148,7 @@ func (cmd *ShowPortfolioCmd) Run(s *cli.Session) error { return nil } -func greenOrRed(f float32) string { +func greenOrRed(f float64) string { if f < 0 { return color.RedString("%.02f", f) } else { @@ -160,7 +160,7 @@ type CreateTransactionCmd struct { PortfolioName string `required:"" predictor:"portfolio" help:"The name of the portfolio where the transaction will be created in"` SecurityName string `arg:"" predictor:"security" help:"The name of the security this transaction belongs to (its ISIN)"` Type string `required:"" enum:"buy,sell,delivery-inbound,delivery-outbound,dividend" default:"buy"` - Amount float32 `required:"" help:"The amount of securities involved in the transaction"` + Amount float64 `required:"" help:"The amount of securities involved in the transaction"` Price float32 `required:"" help:"The price without fees or taxes"` Fees float32 `help:"Any fees that applied to the transaction"` Taxes float32 `help:"Any taxes that applied to the transaction"` @@ -175,9 +175,9 @@ func (cmd *CreateTransactionCmd) Run(s *cli.Session) error { Type: eventTypeFrom(cmd.Type), // eventTypeFrom(cmd.Type) Amount: cmd.Amount, Time: timeOrNow(cmd.Time), - Price: cmd.Price, - Fees: cmd.Fees, - Taxes: cmd.Taxes, + Price: portfoliov1.Value(int32(cmd.Price * 100)), + Fees: portfoliov1.Value(int32(cmd.Fees * 100)), + Taxes: portfoliov1.Value(int32(cmd.Taxes * 100)), }, }) diff --git a/finance/calculation.go b/finance/calculation.go index 473b42bf..e64effc0 100644 --- a/finance/calculation.go +++ b/finance/calculation.go @@ -27,26 +27,24 @@ import ( // list. We basically need to copy the values from the original transaction, // since we need to modify it. type fifoTx struct { - // amount of shares in this transaction - amount float32 - // value contains the net value of this transaction, i.e., without taxes and fees - value float32 - // fees contain any fees associated to this transaction - fees float32 - // ppu is the price per unit (amount) - ppu float32 + amount float64 // amount of shares in this transaction + value *portfoliov1.Currency // value contains the net value of this transaction, i.e., without taxes and fees + fees *portfoliov1.Currency // fees contain any fees associated to this transaction + ppu *portfoliov1.Currency // ppu is the price per unit (amount) } type calculation struct { - Amount float32 - Fees float32 - Taxes float32 + Amount float64 + Fees *portfoliov1.Currency + Taxes *portfoliov1.Currency fifo []*fifoTx } func NewCalculation(txs []*portfoliov1.PortfolioEvent) *calculation { var c calculation + c.Fees = portfoliov1.Zero() + c.Taxes = portfoliov1.Zero() for _, tx := range txs { c.Apply(tx) @@ -62,7 +60,7 @@ func (c *calculation) Apply(tx *portfoliov1.PortfolioEvent) { case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY: // Increase the amount of shares and the fees by the value stored in the // transaction - c.Fees += tx.Fees + c.Fees.PlusAssign(tx.Fees) c.Amount += tx.Amount // Add the transaction to the FIFO list. We need to have a list because @@ -72,20 +70,20 @@ func (c *calculation) Apply(tx *portfoliov1.PortfolioEvent) { c.fifo = append(c.fifo, &fifoTx{ amount: tx.Amount, ppu: tx.Price, - value: tx.Price * float32(tx.Amount), + value: portfoliov1.Times(tx.Price, tx.Amount), fees: tx.Fees, }) case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DELIVERY_OUTBOUND: fallthrough case portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_SELL: var ( - sold float32 + sold float64 ) // Increase the fees and taxes by the value stored in the // transaction - c.Fees += tx.Fees - c.Taxes += tx.Taxes + c.Fees.PlusAssign(tx.Fees) + c.Taxes.PlusAssign(tx.Taxes) // Store the amount of shares sold in this variable, since we later need // to decrease it while looping through the FIFO list @@ -115,17 +113,17 @@ func (c *calculation) Apply(tx *portfoliov1.PortfolioEvent) { // Reduce the number of shares in this entry by the sold amount (but // max it to the item's amount). - n := float32(math.Min(float64(sold), float64(item.amount))) + n := math.Min(float64(sold), float64(item.amount)) item.amount -= n // Adjust the value with the new amount - item.value = item.ppu * float32(item.amount) + item.value = portfoliov1.Times(item.ppu, item.amount) // If no shares are left in this FIFO transaction, also remove the // fees, because they are now associated to the sale and not part of // the price calculation anymore. if item.amount <= 0 { - item.fees = 0 + item.fees = portfoliov1.Zero() } sold -= n @@ -133,26 +131,30 @@ func (c *calculation) Apply(tx *portfoliov1.PortfolioEvent) { } } -func (c *calculation) NetValue() (f float32) { +func (c *calculation) NetValue() (f *portfoliov1.Currency) { + f = portfoliov1.Zero() + for _, item := range c.fifo { - f += item.value + f.PlusAssign(item.value) } return } -func (c *calculation) GrossValue() (f float32) { +func (c *calculation) GrossValue() (f *portfoliov1.Currency) { + f = portfoliov1.Zero() + for _, item := range c.fifo { - f += (item.value + item.fees) + f.PlusAssign(portfoliov1.Plus(item.value, item.fees)) } return } -func (c *calculation) NetPrice() (f float32) { - return c.NetValue() / float32(c.Amount) +func (c *calculation) NetPrice() (f *portfoliov1.Currency) { + return portfoliov1.Divide(c.NetValue(), c.Amount) } -func (c *calculation) GrossPrice() (f float32) { - return c.GrossValue() / float32(c.Amount) +func (c *calculation) GrossPrice() (f *portfoliov1.Currency) { + return portfoliov1.Divide(c.GrossValue(), c.Amount) } diff --git a/finance/calculation_test.go b/finance/calculation_test.go index bfca31bd..88969ccc 100644 --- a/finance/calculation_test.go +++ b/finance/calculation_test.go @@ -40,55 +40,55 @@ func TestNewCalculation(t *testing.T) { { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, Amount: 5, - Price: 181.10, - Fees: 7.16, + Price: portfoliov1.Value(18110), + Fees: portfoliov1.Value(716), }, { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_SELL, Amount: 2, - Price: 304.30, - Fees: 6.42, - Taxes: 16.32, + Price: portfoliov1.Value(30430), + Fees: portfoliov1.Value(642), + Taxes: portfoliov1.Value(1632), }, { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, Amount: 5, - Price: 290, - Fees: 8.53, + Price: portfoliov1.Value(29000), + Fees: portfoliov1.Value(853), }, { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_SELL, Amount: 3, - Price: 220, - Fees: 8.45, + Price: portfoliov1.Value(22000), + Fees: portfoliov1.Value(845), }, { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, Amount: 5, - Price: 203.30, - Fees: 7.44, + Price: portfoliov1.Value(20330), + Fees: portfoliov1.Value(744), }, { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, Amount: 5, - Price: 196.45, - Fees: 7.36, + Price: portfoliov1.Value(19645), + Fees: portfoliov1.Value(736), }, { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, Amount: 10, - Price: 146.55, - Fees: 8.56, + Price: portfoliov1.Value(14655), + Fees: portfoliov1.Value(856), }, }, }, want: func(t *testing.T, c *calculation) bool { return true && assert.Equals(t, 25, c.Amount) && - assert.Equals(t, 4914.25, c.NetValue()) && - assert.Equals(t, 4946.14, c.GrossValue()) && - assert.Equals(t, 196.57, c.NetPrice()) && - assert.Equals(t, 197.84561, c.GrossPrice()) + 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)) }, }, } diff --git a/gen/mgo.pb.go b/gen/mgo.pb.go index 9402bee8..c06871bb 100644 --- a/gen/mgo.pb.go +++ b/gen/mgo.pb.go @@ -81,6 +81,63 @@ func (PortfolioEventType) EnumDescriptor() ([]byte, []int) { return file_mgo_proto_rawDescGZIP(), []int{0} } +// Currency is a currency value in the lowest unit of the selected currency +// (e.g., cents for EUR/USD). +type Currency struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value int32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + Symbol string `protobuf:"bytes,2,opt,name=symbol,proto3" json:"symbol,omitempty"` +} + +func (x *Currency) Reset() { + *x = Currency{} + if protoimpl.UnsafeEnabled { + mi := &file_mgo_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Currency) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Currency) ProtoMessage() {} + +func (x *Currency) ProtoReflect() protoreflect.Message { + mi := &file_mgo_proto_msgTypes[0] + 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 Currency.ProtoReflect.Descriptor instead. +func (*Currency) Descriptor() ([]byte, []int) { + return file_mgo_proto_rawDescGZIP(), []int{0} +} + +func (x *Currency) GetValue() int32 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *Currency) GetSymbol() string { + if x != nil { + return x.Symbol + } + return "" +} + type CreatePortfolioRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -92,7 +149,7 @@ type CreatePortfolioRequest struct { func (x *CreatePortfolioRequest) Reset() { *x = CreatePortfolioRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[0] + mi := &file_mgo_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -105,7 +162,7 @@ func (x *CreatePortfolioRequest) String() string { func (*CreatePortfolioRequest) ProtoMessage() {} func (x *CreatePortfolioRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[0] + mi := &file_mgo_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -118,7 +175,7 @@ func (x *CreatePortfolioRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatePortfolioRequest.ProtoReflect.Descriptor instead. func (*CreatePortfolioRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{0} + return file_mgo_proto_rawDescGZIP(), []int{1} } func (x *CreatePortfolioRequest) GetPortfolio() *Portfolio { @@ -137,7 +194,7 @@ type ListPortfoliosRequest struct { func (x *ListPortfoliosRequest) Reset() { *x = ListPortfoliosRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[1] + mi := &file_mgo_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -150,7 +207,7 @@ func (x *ListPortfoliosRequest) String() string { func (*ListPortfoliosRequest) ProtoMessage() {} func (x *ListPortfoliosRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[1] + mi := &file_mgo_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -163,7 +220,7 @@ func (x *ListPortfoliosRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListPortfoliosRequest.ProtoReflect.Descriptor instead. func (*ListPortfoliosRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{1} + return file_mgo_proto_rawDescGZIP(), []int{2} } type ListPortfoliosResponse struct { @@ -177,7 +234,7 @@ type ListPortfoliosResponse struct { func (x *ListPortfoliosResponse) Reset() { *x = ListPortfoliosResponse{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[2] + mi := &file_mgo_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -190,7 +247,7 @@ func (x *ListPortfoliosResponse) String() string { func (*ListPortfoliosResponse) ProtoMessage() {} func (x *ListPortfoliosResponse) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[2] + mi := &file_mgo_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -203,7 +260,7 @@ func (x *ListPortfoliosResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListPortfoliosResponse.ProtoReflect.Descriptor instead. func (*ListPortfoliosResponse) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{2} + return file_mgo_proto_rawDescGZIP(), []int{3} } func (x *ListPortfoliosResponse) GetPortfolios() []*Portfolio { @@ -224,7 +281,7 @@ type GetPortfolioRequest struct { func (x *GetPortfolioRequest) Reset() { *x = GetPortfolioRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[3] + mi := &file_mgo_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -237,7 +294,7 @@ func (x *GetPortfolioRequest) String() string { func (*GetPortfolioRequest) ProtoMessage() {} func (x *GetPortfolioRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[3] + mi := &file_mgo_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -250,7 +307,7 @@ func (x *GetPortfolioRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPortfolioRequest.ProtoReflect.Descriptor instead. func (*GetPortfolioRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{3} + return file_mgo_proto_rawDescGZIP(), []int{4} } func (x *GetPortfolioRequest) GetName() string { @@ -272,7 +329,7 @@ type UpdatePortfolioRequest struct { func (x *UpdatePortfolioRequest) Reset() { *x = UpdatePortfolioRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[4] + mi := &file_mgo_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -285,7 +342,7 @@ func (x *UpdatePortfolioRequest) String() string { func (*UpdatePortfolioRequest) ProtoMessage() {} func (x *UpdatePortfolioRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[4] + mi := &file_mgo_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -298,7 +355,7 @@ func (x *UpdatePortfolioRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdatePortfolioRequest.ProtoReflect.Descriptor instead. func (*UpdatePortfolioRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{4} + return file_mgo_proto_rawDescGZIP(), []int{5} } func (x *UpdatePortfolioRequest) GetPortfolio() *Portfolio { @@ -326,7 +383,7 @@ type DeletePortfolioRequest struct { func (x *DeletePortfolioRequest) Reset() { *x = DeletePortfolioRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[5] + mi := &file_mgo_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -339,7 +396,7 @@ func (x *DeletePortfolioRequest) String() string { func (*DeletePortfolioRequest) ProtoMessage() {} func (x *DeletePortfolioRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[5] + mi := &file_mgo_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -352,7 +409,7 @@ func (x *DeletePortfolioRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeletePortfolioRequest.ProtoReflect.Descriptor instead. func (*DeletePortfolioRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{5} + return file_mgo_proto_rawDescGZIP(), []int{6} } func (x *DeletePortfolioRequest) GetName() string { @@ -377,7 +434,7 @@ type GetPortfolioSnapshotRequest struct { func (x *GetPortfolioSnapshotRequest) Reset() { *x = GetPortfolioSnapshotRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[6] + mi := &file_mgo_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -390,7 +447,7 @@ func (x *GetPortfolioSnapshotRequest) String() string { func (*GetPortfolioSnapshotRequest) ProtoMessage() {} func (x *GetPortfolioSnapshotRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[6] + mi := &file_mgo_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -403,7 +460,7 @@ func (x *GetPortfolioSnapshotRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPortfolioSnapshotRequest.ProtoReflect.Descriptor instead. func (*GetPortfolioSnapshotRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{6} + return file_mgo_proto_rawDescGZIP(), []int{7} } func (x *GetPortfolioSnapshotRequest) GetPortfolioName() string { @@ -431,7 +488,7 @@ type CreatePortfolioTransactionRequest struct { func (x *CreatePortfolioTransactionRequest) Reset() { *x = CreatePortfolioTransactionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[7] + mi := &file_mgo_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -444,7 +501,7 @@ func (x *CreatePortfolioTransactionRequest) String() string { func (*CreatePortfolioTransactionRequest) ProtoMessage() {} func (x *CreatePortfolioTransactionRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[7] + mi := &file_mgo_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -457,7 +514,7 @@ func (x *CreatePortfolioTransactionRequest) ProtoReflect() protoreflect.Message // Deprecated: Use CreatePortfolioTransactionRequest.ProtoReflect.Descriptor instead. func (*CreatePortfolioTransactionRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{7} + return file_mgo_proto_rawDescGZIP(), []int{8} } func (x *CreatePortfolioTransactionRequest) GetTransaction() *PortfolioEvent { @@ -478,7 +535,7 @@ type GetPortfolioTransactionRequest struct { func (x *GetPortfolioTransactionRequest) Reset() { *x = GetPortfolioTransactionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[8] + mi := &file_mgo_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -491,7 +548,7 @@ func (x *GetPortfolioTransactionRequest) String() string { func (*GetPortfolioTransactionRequest) ProtoMessage() {} func (x *GetPortfolioTransactionRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[8] + mi := &file_mgo_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -504,7 +561,7 @@ func (x *GetPortfolioTransactionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetPortfolioTransactionRequest.ProtoReflect.Descriptor instead. func (*GetPortfolioTransactionRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{8} + return file_mgo_proto_rawDescGZIP(), []int{9} } func (x *GetPortfolioTransactionRequest) GetName() string { @@ -525,7 +582,7 @@ type ListPortfolioTransactionsRequest struct { func (x *ListPortfolioTransactionsRequest) Reset() { *x = ListPortfolioTransactionsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[9] + mi := &file_mgo_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -538,7 +595,7 @@ func (x *ListPortfolioTransactionsRequest) String() string { func (*ListPortfolioTransactionsRequest) ProtoMessage() {} func (x *ListPortfolioTransactionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[9] + mi := &file_mgo_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -551,7 +608,7 @@ func (x *ListPortfolioTransactionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListPortfolioTransactionsRequest.ProtoReflect.Descriptor instead. func (*ListPortfolioTransactionsRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{9} + return file_mgo_proto_rawDescGZIP(), []int{10} } func (x *ListPortfolioTransactionsRequest) GetPortfolioName() string { @@ -572,7 +629,7 @@ type ListPortfolioTransactionsResponse struct { func (x *ListPortfolioTransactionsResponse) Reset() { *x = ListPortfolioTransactionsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[10] + mi := &file_mgo_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -585,7 +642,7 @@ func (x *ListPortfolioTransactionsResponse) String() string { func (*ListPortfolioTransactionsResponse) ProtoMessage() {} func (x *ListPortfolioTransactionsResponse) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[10] + mi := &file_mgo_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -598,7 +655,7 @@ func (x *ListPortfolioTransactionsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListPortfolioTransactionsResponse.ProtoReflect.Descriptor instead. func (*ListPortfolioTransactionsResponse) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{10} + return file_mgo_proto_rawDescGZIP(), []int{11} } func (x *ListPortfolioTransactionsResponse) GetTransactions() []*PortfolioEvent { @@ -620,7 +677,7 @@ type UpdatePortfolioTransactionRequest struct { func (x *UpdatePortfolioTransactionRequest) Reset() { *x = UpdatePortfolioTransactionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[11] + mi := &file_mgo_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -633,7 +690,7 @@ func (x *UpdatePortfolioTransactionRequest) String() string { func (*UpdatePortfolioTransactionRequest) ProtoMessage() {} func (x *UpdatePortfolioTransactionRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[11] + mi := &file_mgo_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -646,7 +703,7 @@ func (x *UpdatePortfolioTransactionRequest) ProtoReflect() protoreflect.Message // Deprecated: Use UpdatePortfolioTransactionRequest.ProtoReflect.Descriptor instead. func (*UpdatePortfolioTransactionRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{11} + return file_mgo_proto_rawDescGZIP(), []int{12} } func (x *UpdatePortfolioTransactionRequest) GetTransaction() *PortfolioEvent { @@ -674,7 +731,7 @@ type DeletePortfolioTransactionRequest struct { func (x *DeletePortfolioTransactionRequest) Reset() { *x = DeletePortfolioTransactionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[12] + mi := &file_mgo_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -687,7 +744,7 @@ func (x *DeletePortfolioTransactionRequest) String() string { func (*DeletePortfolioTransactionRequest) ProtoMessage() {} func (x *DeletePortfolioTransactionRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[12] + mi := &file_mgo_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -700,7 +757,7 @@ func (x *DeletePortfolioTransactionRequest) ProtoReflect() protoreflect.Message // Deprecated: Use DeletePortfolioTransactionRequest.ProtoReflect.Descriptor instead. func (*DeletePortfolioTransactionRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{12} + return file_mgo_proto_rawDescGZIP(), []int{13} } func (x *DeletePortfolioTransactionRequest) GetTransactionId() int32 { @@ -722,7 +779,7 @@ type ImportTransactionsRequest struct { func (x *ImportTransactionsRequest) Reset() { *x = ImportTransactionsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[13] + mi := &file_mgo_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -735,7 +792,7 @@ func (x *ImportTransactionsRequest) String() string { func (*ImportTransactionsRequest) ProtoMessage() {} func (x *ImportTransactionsRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[13] + mi := &file_mgo_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -748,7 +805,7 @@ func (x *ImportTransactionsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ImportTransactionsRequest.ProtoReflect.Descriptor instead. func (*ImportTransactionsRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{13} + return file_mgo_proto_rawDescGZIP(), []int{14} } func (x *ImportTransactionsRequest) GetPortfolioName() string { @@ -780,7 +837,7 @@ type Portfolio struct { func (x *Portfolio) Reset() { *x = Portfolio{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[14] + mi := &file_mgo_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -793,7 +850,7 @@ func (x *Portfolio) String() string { func (*Portfolio) ProtoMessage() {} func (x *Portfolio) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[14] + mi := &file_mgo_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -806,7 +863,7 @@ func (x *Portfolio) ProtoReflect() protoreflect.Message { // Deprecated: Use Portfolio.ProtoReflect.Descriptor instead. func (*Portfolio) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{14} + return file_mgo_proto_rawDescGZIP(), []int{15} } func (x *Portfolio) GetName() string { @@ -846,21 +903,21 @@ type PortfolioSnapshot struct { // 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 float32 `protobuf:"fixed32,10,opt,name=total_purchase_value,json=totalPurchaseValue,proto3" json:"total_purchase_value,omitempty"` + 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 float32 `protobuf:"fixed32,11,opt,name=total_market_value,json=totalMarketValue,proto3" json:"total_market_value,omitempty"` + 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. - TotalProfitOrLoss float32 `protobuf:"fixed32,20,opt,name=total_profit_or_loss,json=totalProfitOrLoss,proto3" json:"total_profit_or_loss,omitempty"` + 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. - TotalGains float32 `protobuf:"fixed32,21,opt,name=total_gains,json=totalGains,proto3" json:"total_gains,omitempty"` + TotalGains float64 `protobuf:"fixed64,21,opt,name=total_gains,json=totalGains,proto3" json:"total_gains,omitempty"` } func (x *PortfolioSnapshot) Reset() { *x = PortfolioSnapshot{} 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) } @@ -873,7 +930,7 @@ func (x *PortfolioSnapshot) String() string { func (*PortfolioSnapshot) ProtoMessage() {} func (x *PortfolioSnapshot) 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 { @@ -886,7 +943,7 @@ func (x *PortfolioSnapshot) ProtoReflect() protoreflect.Message { // Deprecated: Use PortfolioSnapshot.ProtoReflect.Descriptor instead. func (*PortfolioSnapshot) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{15} + return file_mgo_proto_rawDescGZIP(), []int{16} } func (x *PortfolioSnapshot) GetTime() *timestamppb.Timestamp { @@ -910,28 +967,28 @@ func (x *PortfolioSnapshot) GetFirstTransactionTime() *timestamppb.Timestamp { return nil } -func (x *PortfolioSnapshot) GetTotalPurchaseValue() float32 { +func (x *PortfolioSnapshot) GetTotalPurchaseValue() *Currency { if x != nil { return x.TotalPurchaseValue } - return 0 + return nil } -func (x *PortfolioSnapshot) GetTotalMarketValue() float32 { +func (x *PortfolioSnapshot) GetTotalMarketValue() *Currency { if x != nil { return x.TotalMarketValue } - return 0 + return nil } -func (x *PortfolioSnapshot) GetTotalProfitOrLoss() float32 { +func (x *PortfolioSnapshot) GetTotalProfitOrLoss() *Currency { if x != nil { return x.TotalProfitOrLoss } - return 0 + return nil } -func (x *PortfolioSnapshot) GetTotalGains() float32 { +func (x *PortfolioSnapshot) GetTotalGains() float64 { if x != nil { return x.TotalGains } @@ -944,33 +1001,33 @@ type PortfolioPosition struct { unknownFields protoimpl.UnknownFields Security *Security `protobuf:"bytes,1,opt,name=security,proto3" json:"security,omitempty"` - Amount float32 `protobuf:"fixed32,2,opt,name=amount,proto3" json:"amount,omitempty"` + Amount float64 `protobuf:"fixed64,2,opt,name=amount,proto3" json:"amount,omitempty"` // PurchaseValue was the market value of this position when it was bought // (net; exclusive of any fees). - PurchaseValue float32 `protobuf:"fixed32,5,opt,name=purchase_value,json=purchaseValue,proto3" json:"purchase_value,omitempty"` + PurchaseValue *Currency `protobuf:"bytes,5,opt,name=purchase_value,json=purchaseValue,proto3" json:"purchase_value,omitempty"` // PurchasePrice was the market price of this position when it was bought // (net; exclusive of any fees). - PurchasePrice float32 `protobuf:"fixed32,6,opt,name=purchase_price,json=purchasePrice,proto3" json:"purchase_price,omitempty"` + PurchasePrice *Currency `protobuf:"bytes,6,opt,name=purchase_price,json=purchasePrice,proto3" json:"purchase_price,omitempty"` // MarketValue is the current market value of this position, as retrieved from // the securities service. - MarketValue float32 `protobuf:"fixed32,10,opt,name=market_value,json=marketValue,proto3" json:"market_value,omitempty"` + MarketValue *Currency `protobuf:"bytes,10,opt,name=market_value,json=marketValue,proto3" json:"market_value,omitempty"` // MarketPrice is the current market price of this position, as retrieved from // the securities service. - MarketPrice float32 `protobuf:"fixed32,11,opt,name=market_price,json=marketPrice,proto3" json:"market_price,omitempty"` + MarketPrice *Currency `protobuf:"bytes,11,opt,name=market_price,json=marketPrice,proto3" json:"market_price,omitempty"` // TotalFees is the total amount of fees accumulating in this position through // various transactions. - TotalFees float32 `protobuf:"fixed32,15,opt,name=total_fees,json=totalFees,proto3" json:"total_fees,omitempty"` + TotalFees *Currency `protobuf:"bytes,15,opt,name=total_fees,json=totalFees,proto3" json:"total_fees,omitempty"` // ProfitOrLoss contains the absolute amount of profit or loss in this // position. - ProfitOrLoss float32 `protobuf:"fixed32,20,opt,name=profit_or_loss,json=profitOrLoss,proto3" json:"profit_or_loss,omitempty"` + ProfitOrLoss *Currency `protobuf:"bytes,20,opt,name=profit_or_loss,json=profitOrLoss,proto3" json:"profit_or_loss,omitempty"` // Gains contains the relative amount of profit or loss in this position. - Gains float32 `protobuf:"fixed32,21,opt,name=gains,proto3" json:"gains,omitempty"` + Gains float64 `protobuf:"fixed64,21,opt,name=gains,proto3" json:"gains,omitempty"` } func (x *PortfolioPosition) Reset() { *x = PortfolioPosition{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[16] + mi := &file_mgo_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -983,7 +1040,7 @@ func (x *PortfolioPosition) String() string { func (*PortfolioPosition) ProtoMessage() {} func (x *PortfolioPosition) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[16] + mi := &file_mgo_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -996,7 +1053,7 @@ func (x *PortfolioPosition) ProtoReflect() protoreflect.Message { // Deprecated: Use PortfolioPosition.ProtoReflect.Descriptor instead. func (*PortfolioPosition) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{16} + return file_mgo_proto_rawDescGZIP(), []int{17} } func (x *PortfolioPosition) GetSecurity() *Security { @@ -1006,56 +1063,56 @@ func (x *PortfolioPosition) GetSecurity() *Security { return nil } -func (x *PortfolioPosition) GetAmount() float32 { +func (x *PortfolioPosition) GetAmount() float64 { if x != nil { return x.Amount } return 0 } -func (x *PortfolioPosition) GetPurchaseValue() float32 { +func (x *PortfolioPosition) GetPurchaseValue() *Currency { if x != nil { return x.PurchaseValue } - return 0 + return nil } -func (x *PortfolioPosition) GetPurchasePrice() float32 { +func (x *PortfolioPosition) GetPurchasePrice() *Currency { if x != nil { return x.PurchasePrice } - return 0 + return nil } -func (x *PortfolioPosition) GetMarketValue() float32 { +func (x *PortfolioPosition) GetMarketValue() *Currency { if x != nil { return x.MarketValue } - return 0 + return nil } -func (x *PortfolioPosition) GetMarketPrice() float32 { +func (x *PortfolioPosition) GetMarketPrice() *Currency { if x != nil { return x.MarketPrice } - return 0 + return nil } -func (x *PortfolioPosition) GetTotalFees() float32 { +func (x *PortfolioPosition) GetTotalFees() *Currency { if x != nil { return x.TotalFees } - return 0 + return nil } -func (x *PortfolioPosition) GetProfitOrLoss() float32 { +func (x *PortfolioPosition) GetProfitOrLoss() *Currency { if x != nil { return x.ProfitOrLoss } - return 0 + return nil } -func (x *PortfolioPosition) GetGains() float32 { +func (x *PortfolioPosition) GetGains() float64 { if x != nil { return x.Gains } @@ -1072,16 +1129,16 @@ type PortfolioEvent struct { Time *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time,proto3" json:"time,omitempty"` PortfolioName string `protobuf:"bytes,4,opt,name=portfolio_name,json=portfolioName,proto3" json:"portfolio_name,omitempty"` SecurityName string `protobuf:"bytes,5,opt,name=security_name,json=securityName,proto3" json:"security_name,omitempty"` - Amount float32 `protobuf:"fixed32,10,opt,name=amount,proto3" json:"amount,omitempty"` - Price float32 `protobuf:"fixed32,11,opt,name=price,proto3" json:"price,omitempty"` - Fees float32 `protobuf:"fixed32,12,opt,name=fees,proto3" json:"fees,omitempty"` - Taxes float32 `protobuf:"fixed32,13,opt,name=taxes,proto3" json:"taxes,omitempty"` + Amount float64 `protobuf:"fixed64,10,opt,name=amount,proto3" json:"amount,omitempty"` + Price *Currency `protobuf:"bytes,11,opt,name=price,proto3" json:"price,omitempty"` + Fees *Currency `protobuf:"bytes,12,opt,name=fees,proto3" json:"fees,omitempty"` + Taxes *Currency `protobuf:"bytes,13,opt,name=taxes,proto3" json:"taxes,omitempty"` } func (x *PortfolioEvent) Reset() { *x = PortfolioEvent{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[17] + mi := &file_mgo_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1094,7 +1151,7 @@ func (x *PortfolioEvent) String() string { func (*PortfolioEvent) ProtoMessage() {} func (x *PortfolioEvent) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[17] + mi := &file_mgo_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1107,7 +1164,7 @@ func (x *PortfolioEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use PortfolioEvent.ProtoReflect.Descriptor instead. func (*PortfolioEvent) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{17} + return file_mgo_proto_rawDescGZIP(), []int{18} } func (x *PortfolioEvent) GetName() string { @@ -1145,32 +1202,32 @@ func (x *PortfolioEvent) GetSecurityName() string { return "" } -func (x *PortfolioEvent) GetAmount() float32 { +func (x *PortfolioEvent) GetAmount() float64 { if x != nil { return x.Amount } return 0 } -func (x *PortfolioEvent) GetPrice() float32 { +func (x *PortfolioEvent) GetPrice() *Currency { if x != nil { return x.Price } - return 0 + return nil } -func (x *PortfolioEvent) GetFees() float32 { +func (x *PortfolioEvent) GetFees() *Currency { if x != nil { return x.Fees } - return 0 + return nil } -func (x *PortfolioEvent) GetTaxes() float32 { +func (x *PortfolioEvent) GetTaxes() *Currency { if x != nil { return x.Taxes } - return 0 + return nil } type Security struct { @@ -1190,7 +1247,7 @@ type Security struct { func (x *Security) Reset() { *x = Security{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[18] + mi := &file_mgo_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1203,7 +1260,7 @@ func (x *Security) String() string { func (*Security) ProtoMessage() {} func (x *Security) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[18] + mi := &file_mgo_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1216,7 +1273,7 @@ func (x *Security) ProtoReflect() protoreflect.Message { // Deprecated: Use Security.ProtoReflect.Descriptor instead. func (*Security) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{18} + return file_mgo_proto_rawDescGZIP(), []int{19} } func (x *Security) GetName() string { @@ -1255,14 +1312,14 @@ type ListedSecurity struct { SecurityName string `protobuf:"bytes,1,opt,name=security_name,json=securityName,proto3" json:"security_name,omitempty"` Ticker string `protobuf:"bytes,3,opt,name=ticker,proto3" json:"ticker,omitempty"` Currency string `protobuf:"bytes,4,opt,name=currency,proto3" json:"currency,omitempty"` - LatestQuote *float32 `protobuf:"fixed32,5,opt,name=latest_quote,json=latestQuote,proto3,oneof" json:"latest_quote,omitempty"` + LatestQuote *Currency `protobuf:"bytes,5,opt,name=latest_quote,json=latestQuote,proto3,oneof" json:"latest_quote,omitempty"` LatestQuoteTimestamp *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=latest_quote_timestamp,json=latestQuoteTimestamp,proto3,oneof" json:"latest_quote_timestamp,omitempty"` } func (x *ListedSecurity) Reset() { *x = ListedSecurity{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[19] + mi := &file_mgo_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1275,7 +1332,7 @@ func (x *ListedSecurity) String() string { func (*ListedSecurity) ProtoMessage() {} func (x *ListedSecurity) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[19] + mi := &file_mgo_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1288,7 +1345,7 @@ func (x *ListedSecurity) ProtoReflect() protoreflect.Message { // Deprecated: Use ListedSecurity.ProtoReflect.Descriptor instead. func (*ListedSecurity) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{19} + return file_mgo_proto_rawDescGZIP(), []int{20} } func (x *ListedSecurity) GetSecurityName() string { @@ -1312,11 +1369,11 @@ func (x *ListedSecurity) GetCurrency() string { return "" } -func (x *ListedSecurity) GetLatestQuote() float32 { - if x != nil && x.LatestQuote != nil { - return *x.LatestQuote +func (x *ListedSecurity) GetLatestQuote() *Currency { + if x != nil { + return x.LatestQuote } - return 0 + return nil } func (x *ListedSecurity) GetLatestQuoteTimestamp() *timestamppb.Timestamp { @@ -1337,7 +1394,7 @@ type ListSecuritiesRequest struct { func (x *ListSecuritiesRequest) Reset() { *x = ListSecuritiesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[20] + mi := &file_mgo_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1350,7 +1407,7 @@ func (x *ListSecuritiesRequest) String() string { func (*ListSecuritiesRequest) ProtoMessage() {} func (x *ListSecuritiesRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[20] + mi := &file_mgo_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1363,7 +1420,7 @@ func (x *ListSecuritiesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSecuritiesRequest.ProtoReflect.Descriptor instead. func (*ListSecuritiesRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{20} + return file_mgo_proto_rawDescGZIP(), []int{21} } func (x *ListSecuritiesRequest) GetFilter() *ListSecuritiesRequest_Filter { @@ -1384,7 +1441,7 @@ type ListSecuritiesResponse struct { func (x *ListSecuritiesResponse) Reset() { *x = ListSecuritiesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[21] + mi := &file_mgo_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1397,7 +1454,7 @@ func (x *ListSecuritiesResponse) String() string { func (*ListSecuritiesResponse) ProtoMessage() {} func (x *ListSecuritiesResponse) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[21] + mi := &file_mgo_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1410,7 +1467,7 @@ func (x *ListSecuritiesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSecuritiesResponse.ProtoReflect.Descriptor instead. func (*ListSecuritiesResponse) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{21} + return file_mgo_proto_rawDescGZIP(), []int{22} } func (x *ListSecuritiesResponse) GetSecurities() []*Security { @@ -1431,7 +1488,7 @@ type GetSecurityRequest struct { func (x *GetSecurityRequest) Reset() { *x = GetSecurityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[22] + mi := &file_mgo_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1444,7 +1501,7 @@ func (x *GetSecurityRequest) String() string { func (*GetSecurityRequest) ProtoMessage() {} func (x *GetSecurityRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[22] + mi := &file_mgo_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1457,7 +1514,7 @@ func (x *GetSecurityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSecurityRequest.ProtoReflect.Descriptor instead. func (*GetSecurityRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{22} + return file_mgo_proto_rawDescGZIP(), []int{23} } func (x *GetSecurityRequest) GetName() string { @@ -1478,7 +1535,7 @@ type CreateSecurityRequest struct { func (x *CreateSecurityRequest) Reset() { *x = CreateSecurityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[23] + mi := &file_mgo_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1491,7 +1548,7 @@ func (x *CreateSecurityRequest) String() string { func (*CreateSecurityRequest) ProtoMessage() {} func (x *CreateSecurityRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[23] + mi := &file_mgo_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1504,7 +1561,7 @@ func (x *CreateSecurityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSecurityRequest.ProtoReflect.Descriptor instead. func (*CreateSecurityRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{23} + return file_mgo_proto_rawDescGZIP(), []int{24} } func (x *CreateSecurityRequest) GetSecurity() *Security { @@ -1526,7 +1583,7 @@ type UpdateSecurityRequest struct { func (x *UpdateSecurityRequest) Reset() { *x = UpdateSecurityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[24] + mi := &file_mgo_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1539,7 +1596,7 @@ func (x *UpdateSecurityRequest) String() string { func (*UpdateSecurityRequest) ProtoMessage() {} func (x *UpdateSecurityRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[24] + mi := &file_mgo_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1552,7 +1609,7 @@ func (x *UpdateSecurityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateSecurityRequest.ProtoReflect.Descriptor instead. func (*UpdateSecurityRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{24} + return file_mgo_proto_rawDescGZIP(), []int{25} } func (x *UpdateSecurityRequest) GetSecurity() *Security { @@ -1580,7 +1637,7 @@ type DeleteSecurityRequest struct { func (x *DeleteSecurityRequest) Reset() { *x = DeleteSecurityRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[25] + mi := &file_mgo_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1593,7 +1650,7 @@ func (x *DeleteSecurityRequest) String() string { func (*DeleteSecurityRequest) ProtoMessage() {} func (x *DeleteSecurityRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[25] + mi := &file_mgo_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1606,7 +1663,7 @@ func (x *DeleteSecurityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSecurityRequest.ProtoReflect.Descriptor instead. func (*DeleteSecurityRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{25} + return file_mgo_proto_rawDescGZIP(), []int{26} } func (x *DeleteSecurityRequest) GetName() string { @@ -1627,7 +1684,7 @@ type TriggerQuoteUpdateRequest struct { func (x *TriggerQuoteUpdateRequest) Reset() { *x = TriggerQuoteUpdateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[26] + mi := &file_mgo_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1640,7 +1697,7 @@ func (x *TriggerQuoteUpdateRequest) String() string { func (*TriggerQuoteUpdateRequest) ProtoMessage() {} func (x *TriggerQuoteUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[26] + mi := &file_mgo_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1653,7 +1710,7 @@ func (x *TriggerQuoteUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TriggerQuoteUpdateRequest.ProtoReflect.Descriptor instead. func (*TriggerQuoteUpdateRequest) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{26} + return file_mgo_proto_rawDescGZIP(), []int{27} } func (x *TriggerQuoteUpdateRequest) GetSecurityNames() []string { @@ -1672,7 +1729,7 @@ type TriggerQuoteUpdateResponse struct { func (x *TriggerQuoteUpdateResponse) Reset() { *x = TriggerQuoteUpdateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[27] + mi := &file_mgo_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1685,7 +1742,7 @@ func (x *TriggerQuoteUpdateResponse) String() string { func (*TriggerQuoteUpdateResponse) ProtoMessage() {} func (x *TriggerQuoteUpdateResponse) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[27] + mi := &file_mgo_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1698,7 +1755,7 @@ func (x *TriggerQuoteUpdateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use TriggerQuoteUpdateResponse.ProtoReflect.Descriptor instead. func (*TriggerQuoteUpdateResponse) Descriptor() ([]byte, []int) { - return file_mgo_proto_rawDescGZIP(), []int{27} + return file_mgo_proto_rawDescGZIP(), []int{28} } type ListSecuritiesRequest_Filter struct { @@ -1712,7 +1769,7 @@ type ListSecuritiesRequest_Filter struct { func (x *ListSecuritiesRequest_Filter) Reset() { *x = ListSecuritiesRequest_Filter{} if protoimpl.UnsafeEnabled { - mi := &file_mgo_proto_msgTypes[29] + mi := &file_mgo_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1725,7 +1782,7 @@ func (x *ListSecuritiesRequest_Filter) String() string { func (*ListSecuritiesRequest_Filter) ProtoMessage() {} func (x *ListSecuritiesRequest_Filter) ProtoReflect() protoreflect.Message { - mi := &file_mgo_proto_msgTypes[29] + mi := &file_mgo_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1738,7 +1795,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{20, 0} + return file_mgo_proto_rawDescGZIP(), []int{21, 0} } func (x *ListSecuritiesRequest_Filter) GetSecurityNames() []string { @@ -1758,381 +1815,408 @@ var file_mgo_proto_rawDesc = []byte{ 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, - 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 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, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, - 0x69, 0x6f, 0x22, 0x17, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x6c, 0x69, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x55, 0x0a, 0x16, 0x4c, - 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, - 0x69, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 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, 0x52, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x73, 0x22, 0x29, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, - 0x69, 0x6f, 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, 0x90, 0x01, - 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, - 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 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, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x6c, 0x69, 0x6f, 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, 0x2c, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x6c, 0x69, 0x6f, 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, 0x74, - 0x0a, 0x1b, 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, 0x12, 0x25, 0x0a, - 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 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, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x38, 0x0a, + 0x08, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x22, 0x53, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x39, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 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, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x22, 0x17, 0x0a, 0x15, + 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x55, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x72, + 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3b, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 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, + 0x52, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x73, 0x22, 0x29, 0x0a, 0x13, + 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 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, 0x90, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 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, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 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, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, - 0x74, 0x69, 0x6d, 0x65, 0x22, 0x67, 0x0a, 0x21, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, + 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, 0x2c, 0x0a, 0x16, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 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, 0x74, 0x0a, 0x1b, 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, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x66, + 0x6f, 0x6c, 0x69, 0x6f, 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, 0x2e, + 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 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, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x67, + 0x0a, 0x21, 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, 0x12, 0x42, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 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, 0x0b, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x34, 0x0a, 0x1e, 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, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x49, 0x0a, + 0x20, 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, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 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, 0x22, 0x69, 0x0a, 0x21, 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, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, + 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 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, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x21, 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, 0x12, 0x42, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 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, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x34, 0x0a, - 0x1e, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x54, 0x72, 0x61, + 0x52, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 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, 0x4a, 0x0a, 0x21, 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, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x22, 0x49, 0x0a, 0x20, 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, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x66, - 0x6f, 0x6c, 0x69, 0x6f, 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, 0x22, 0x69, - 0x0a, 0x21, 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, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x67, 0x6f, 0x2e, + 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x5d, 0x0a, 0x19, 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, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, + 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, 0x0c, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x21, 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, 0x12, - 0x42, 0x0a, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 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, 0x0b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 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, 0x4a, 0x0a, 0x21, 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, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x5d, 0x0a, 0x19, - 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, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x6f, 0x72, - 0x74, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 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, 0x9c, 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, 0x30, 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, 0x02, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x75, 0x72, - 0x63, 0x68, 0x61, 0x73, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 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, 0x02, 0x52, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x72, - 0x6b, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2f, 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, 0x02, 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, 0x02, 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, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0xd2, 0x02, 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, + 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, 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, 0x02, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x25, - 0x0a, 0x0e, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, - 0x65, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0d, 0x70, - 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x0c, - 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x02, 0x52, 0x0b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x50, 0x72, 0x69, - 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x65, 0x65, 0x73, - 0x18, 0x0f, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x65, 0x65, - 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x74, 0x5f, 0x6f, 0x72, 0x5f, 0x6c, - 0x6f, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x02, 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, 0x02, 0x52, 0x05, 0x67, 0x61, 0x69, 0x6e, 0x73, 0x22, 0xb2, 0x02, - 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, 0x02, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x02, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x65, 0x65, 0x73, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x02, 0x52, 0x04, 0x66, 0x65, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x61, 0x78, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x02, 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, 0x94, 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, 0x26, 0x0a, 0x0c, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x02, 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, + 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, - 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, + 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, + 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, + 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, + 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, + 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, 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, 0x42, 0x55, 0x59, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x50, 0x4f, 0x52, 0x54, + 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, 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, 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, + 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, + 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, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 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, 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, + 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, + 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, 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, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x66, + 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, 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, 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, + 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, 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, + 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, 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, 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, + 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, 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, 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, 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, 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, } var ( @@ -2148,109 +2232,123 @@ func file_mgo_proto_rawDescGZIP() []byte { } var file_mgo_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_mgo_proto_msgTypes = make([]protoimpl.MessageInfo, 30) +var file_mgo_proto_msgTypes = make([]protoimpl.MessageInfo, 31) var file_mgo_proto_goTypes = []interface{}{ (PortfolioEventType)(0), // 0: mgo.portfolio.v1.PortfolioEventType - (*CreatePortfolioRequest)(nil), // 1: mgo.portfolio.v1.CreatePortfolioRequest - (*ListPortfoliosRequest)(nil), // 2: mgo.portfolio.v1.ListPortfoliosRequest - (*ListPortfoliosResponse)(nil), // 3: mgo.portfolio.v1.ListPortfoliosResponse - (*GetPortfolioRequest)(nil), // 4: mgo.portfolio.v1.GetPortfolioRequest - (*UpdatePortfolioRequest)(nil), // 5: mgo.portfolio.v1.UpdatePortfolioRequest - (*DeletePortfolioRequest)(nil), // 6: mgo.portfolio.v1.DeletePortfolioRequest - (*GetPortfolioSnapshotRequest)(nil), // 7: mgo.portfolio.v1.GetPortfolioSnapshotRequest - (*CreatePortfolioTransactionRequest)(nil), // 8: mgo.portfolio.v1.CreatePortfolioTransactionRequest - (*GetPortfolioTransactionRequest)(nil), // 9: mgo.portfolio.v1.GetPortfolioTransactionRequest - (*ListPortfolioTransactionsRequest)(nil), // 10: mgo.portfolio.v1.ListPortfolioTransactionsRequest - (*ListPortfolioTransactionsResponse)(nil), // 11: mgo.portfolio.v1.ListPortfolioTransactionsResponse - (*UpdatePortfolioTransactionRequest)(nil), // 12: mgo.portfolio.v1.UpdatePortfolioTransactionRequest - (*DeletePortfolioTransactionRequest)(nil), // 13: mgo.portfolio.v1.DeletePortfolioTransactionRequest - (*ImportTransactionsRequest)(nil), // 14: mgo.portfolio.v1.ImportTransactionsRequest - (*Portfolio)(nil), // 15: mgo.portfolio.v1.Portfolio - (*PortfolioSnapshot)(nil), // 16: mgo.portfolio.v1.PortfolioSnapshot - (*PortfolioPosition)(nil), // 17: mgo.portfolio.v1.PortfolioPosition - (*PortfolioEvent)(nil), // 18: mgo.portfolio.v1.PortfolioEvent - (*Security)(nil), // 19: mgo.portfolio.v1.Security - (*ListedSecurity)(nil), // 20: mgo.portfolio.v1.ListedSecurity - (*ListSecuritiesRequest)(nil), // 21: mgo.portfolio.v1.ListSecuritiesRequest - (*ListSecuritiesResponse)(nil), // 22: mgo.portfolio.v1.ListSecuritiesResponse - (*GetSecurityRequest)(nil), // 23: mgo.portfolio.v1.GetSecurityRequest - (*CreateSecurityRequest)(nil), // 24: mgo.portfolio.v1.CreateSecurityRequest - (*UpdateSecurityRequest)(nil), // 25: mgo.portfolio.v1.UpdateSecurityRequest - (*DeleteSecurityRequest)(nil), // 26: mgo.portfolio.v1.DeleteSecurityRequest - (*TriggerQuoteUpdateRequest)(nil), // 27: mgo.portfolio.v1.TriggerQuoteUpdateRequest - (*TriggerQuoteUpdateResponse)(nil), // 28: mgo.portfolio.v1.TriggerQuoteUpdateResponse - nil, // 29: mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry - (*ListSecuritiesRequest_Filter)(nil), // 30: mgo.portfolio.v1.ListSecuritiesRequest.Filter - (*fieldmaskpb.FieldMask)(nil), // 31: google.protobuf.FieldMask - (*timestamppb.Timestamp)(nil), // 32: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 33: google.protobuf.Empty + (*Currency)(nil), // 1: mgo.portfolio.v1.Currency + (*CreatePortfolioRequest)(nil), // 2: mgo.portfolio.v1.CreatePortfolioRequest + (*ListPortfoliosRequest)(nil), // 3: mgo.portfolio.v1.ListPortfoliosRequest + (*ListPortfoliosResponse)(nil), // 4: mgo.portfolio.v1.ListPortfoliosResponse + (*GetPortfolioRequest)(nil), // 5: mgo.portfolio.v1.GetPortfolioRequest + (*UpdatePortfolioRequest)(nil), // 6: mgo.portfolio.v1.UpdatePortfolioRequest + (*DeletePortfolioRequest)(nil), // 7: mgo.portfolio.v1.DeletePortfolioRequest + (*GetPortfolioSnapshotRequest)(nil), // 8: mgo.portfolio.v1.GetPortfolioSnapshotRequest + (*CreatePortfolioTransactionRequest)(nil), // 9: mgo.portfolio.v1.CreatePortfolioTransactionRequest + (*GetPortfolioTransactionRequest)(nil), // 10: mgo.portfolio.v1.GetPortfolioTransactionRequest + (*ListPortfolioTransactionsRequest)(nil), // 11: mgo.portfolio.v1.ListPortfolioTransactionsRequest + (*ListPortfolioTransactionsResponse)(nil), // 12: mgo.portfolio.v1.ListPortfolioTransactionsResponse + (*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 } var file_mgo_proto_depIdxs = []int32{ - 15, // 0: mgo.portfolio.v1.CreatePortfolioRequest.portfolio:type_name -> mgo.portfolio.v1.Portfolio - 15, // 1: mgo.portfolio.v1.ListPortfoliosResponse.portfolios:type_name -> mgo.portfolio.v1.Portfolio - 15, // 2: mgo.portfolio.v1.UpdatePortfolioRequest.portfolio:type_name -> mgo.portfolio.v1.Portfolio - 31, // 3: mgo.portfolio.v1.UpdatePortfolioRequest.update_mask:type_name -> google.protobuf.FieldMask - 32, // 4: mgo.portfolio.v1.GetPortfolioSnapshotRequest.time:type_name -> google.protobuf.Timestamp - 18, // 5: mgo.portfolio.v1.CreatePortfolioTransactionRequest.transaction:type_name -> mgo.portfolio.v1.PortfolioEvent - 18, // 6: mgo.portfolio.v1.ListPortfolioTransactionsResponse.transactions:type_name -> mgo.portfolio.v1.PortfolioEvent - 18, // 7: mgo.portfolio.v1.UpdatePortfolioTransactionRequest.transaction:type_name -> mgo.portfolio.v1.PortfolioEvent - 31, // 8: mgo.portfolio.v1.UpdatePortfolioTransactionRequest.update_mask:type_name -> google.protobuf.FieldMask - 18, // 9: mgo.portfolio.v1.Portfolio.events:type_name -> mgo.portfolio.v1.PortfolioEvent - 32, // 10: mgo.portfolio.v1.PortfolioSnapshot.time:type_name -> google.protobuf.Timestamp - 29, // 11: mgo.portfolio.v1.PortfolioSnapshot.positions:type_name -> mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry - 32, // 12: mgo.portfolio.v1.PortfolioSnapshot.first_transaction_time:type_name -> google.protobuf.Timestamp - 19, // 13: mgo.portfolio.v1.PortfolioPosition.security:type_name -> mgo.portfolio.v1.Security - 0, // 14: mgo.portfolio.v1.PortfolioEvent.type:type_name -> mgo.portfolio.v1.PortfolioEventType - 32, // 15: mgo.portfolio.v1.PortfolioEvent.time:type_name -> google.protobuf.Timestamp - 20, // 16: mgo.portfolio.v1.Security.listed_on:type_name -> mgo.portfolio.v1.ListedSecurity - 32, // 17: mgo.portfolio.v1.ListedSecurity.latest_quote_timestamp:type_name -> google.protobuf.Timestamp - 30, // 18: mgo.portfolio.v1.ListSecuritiesRequest.filter:type_name -> mgo.portfolio.v1.ListSecuritiesRequest.Filter - 19, // 19: mgo.portfolio.v1.ListSecuritiesResponse.securities:type_name -> mgo.portfolio.v1.Security - 19, // 20: mgo.portfolio.v1.CreateSecurityRequest.security:type_name -> mgo.portfolio.v1.Security - 19, // 21: mgo.portfolio.v1.UpdateSecurityRequest.security:type_name -> mgo.portfolio.v1.Security - 31, // 22: mgo.portfolio.v1.UpdateSecurityRequest.update_mask:type_name -> google.protobuf.FieldMask - 17, // 23: mgo.portfolio.v1.PortfolioSnapshot.PositionsEntry.value:type_name -> mgo.portfolio.v1.PortfolioPosition - 1, // 24: mgo.portfolio.v1.PortfolioService.CreatePortfolio:input_type -> mgo.portfolio.v1.CreatePortfolioRequest - 2, // 25: mgo.portfolio.v1.PortfolioService.ListPortfolios:input_type -> mgo.portfolio.v1.ListPortfoliosRequest - 4, // 26: mgo.portfolio.v1.PortfolioService.GetPortfolio:input_type -> mgo.portfolio.v1.GetPortfolioRequest - 5, // 27: mgo.portfolio.v1.PortfolioService.UpdatePortfolio:input_type -> mgo.portfolio.v1.UpdatePortfolioRequest - 6, // 28: mgo.portfolio.v1.PortfolioService.DeletePortfolio:input_type -> mgo.portfolio.v1.DeletePortfolioRequest - 7, // 29: mgo.portfolio.v1.PortfolioService.GetPortfolioSnapshot:input_type -> mgo.portfolio.v1.GetPortfolioSnapshotRequest - 8, // 30: mgo.portfolio.v1.PortfolioService.CreatePortfolioTransaction:input_type -> mgo.portfolio.v1.CreatePortfolioTransactionRequest - 9, // 31: mgo.portfolio.v1.PortfolioService.GetPortfolioTransaction:input_type -> mgo.portfolio.v1.GetPortfolioTransactionRequest - 10, // 32: mgo.portfolio.v1.PortfolioService.ListPortfolioTransactions:input_type -> mgo.portfolio.v1.ListPortfolioTransactionsRequest - 12, // 33: mgo.portfolio.v1.PortfolioService.UpdatePortfolioTransaction:input_type -> mgo.portfolio.v1.UpdatePortfolioTransactionRequest - 13, // 34: mgo.portfolio.v1.PortfolioService.DeletePortfolioTransaction:input_type -> mgo.portfolio.v1.DeletePortfolioTransactionRequest - 14, // 35: mgo.portfolio.v1.PortfolioService.ImportTransactions:input_type -> mgo.portfolio.v1.ImportTransactionsRequest - 21, // 36: mgo.portfolio.v1.SecuritiesService.ListSecurities:input_type -> mgo.portfolio.v1.ListSecuritiesRequest - 23, // 37: mgo.portfolio.v1.SecuritiesService.GetSecurity:input_type -> mgo.portfolio.v1.GetSecurityRequest - 24, // 38: mgo.portfolio.v1.SecuritiesService.CreateSecurity:input_type -> mgo.portfolio.v1.CreateSecurityRequest - 25, // 39: mgo.portfolio.v1.SecuritiesService.UpdateSecurity:input_type -> mgo.portfolio.v1.UpdateSecurityRequest - 26, // 40: mgo.portfolio.v1.SecuritiesService.DeleteSecurity:input_type -> mgo.portfolio.v1.DeleteSecurityRequest - 27, // 41: mgo.portfolio.v1.SecuritiesService.TriggerSecurityQuoteUpdate:input_type -> mgo.portfolio.v1.TriggerQuoteUpdateRequest - 15, // 42: mgo.portfolio.v1.PortfolioService.CreatePortfolio:output_type -> mgo.portfolio.v1.Portfolio - 3, // 43: mgo.portfolio.v1.PortfolioService.ListPortfolios:output_type -> mgo.portfolio.v1.ListPortfoliosResponse - 15, // 44: mgo.portfolio.v1.PortfolioService.GetPortfolio:output_type -> mgo.portfolio.v1.Portfolio - 15, // 45: mgo.portfolio.v1.PortfolioService.UpdatePortfolio:output_type -> mgo.portfolio.v1.Portfolio - 33, // 46: mgo.portfolio.v1.PortfolioService.DeletePortfolio:output_type -> google.protobuf.Empty - 16, // 47: mgo.portfolio.v1.PortfolioService.GetPortfolioSnapshot:output_type -> mgo.portfolio.v1.PortfolioSnapshot - 18, // 48: mgo.portfolio.v1.PortfolioService.CreatePortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent - 18, // 49: mgo.portfolio.v1.PortfolioService.GetPortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent - 11, // 50: mgo.portfolio.v1.PortfolioService.ListPortfolioTransactions:output_type -> mgo.portfolio.v1.ListPortfolioTransactionsResponse - 18, // 51: mgo.portfolio.v1.PortfolioService.UpdatePortfolioTransaction:output_type -> mgo.portfolio.v1.PortfolioEvent - 33, // 52: mgo.portfolio.v1.PortfolioService.DeletePortfolioTransaction:output_type -> google.protobuf.Empty - 33, // 53: mgo.portfolio.v1.PortfolioService.ImportTransactions:output_type -> google.protobuf.Empty - 22, // 54: mgo.portfolio.v1.SecuritiesService.ListSecurities:output_type -> mgo.portfolio.v1.ListSecuritiesResponse - 19, // 55: mgo.portfolio.v1.SecuritiesService.GetSecurity:output_type -> mgo.portfolio.v1.Security - 19, // 56: mgo.portfolio.v1.SecuritiesService.CreateSecurity:output_type -> mgo.portfolio.v1.Security - 19, // 57: mgo.portfolio.v1.SecuritiesService.UpdateSecurity:output_type -> mgo.portfolio.v1.Security - 33, // 58: mgo.portfolio.v1.SecuritiesService.DeleteSecurity:output_type -> google.protobuf.Empty - 28, // 59: mgo.portfolio.v1.SecuritiesService.TriggerSecurityQuoteUpdate:output_type -> mgo.portfolio.v1.TriggerQuoteUpdateResponse - 42, // [42:60] is the sub-list for method output_type - 24, // [24:42] is the sub-list for method input_type - 24, // [24:24] is the sub-list for extension type_name - 24, // [24:24] is the sub-list for extension extendee - 0, // [0:24] is the sub-list for field type_name + 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 } func init() { file_mgo_proto_init() } @@ -2260,7 +2358,7 @@ func file_mgo_proto_init() { } if !protoimpl.UnsafeEnabled { file_mgo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreatePortfolioRequest); i { + switch v := v.(*Currency); i { case 0: return &v.state case 1: @@ -2272,7 +2370,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListPortfoliosRequest); i { + switch v := v.(*CreatePortfolioRequest); i { case 0: return &v.state case 1: @@ -2284,7 +2382,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListPortfoliosResponse); i { + switch v := v.(*ListPortfoliosRequest); i { case 0: return &v.state case 1: @@ -2296,7 +2394,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPortfolioRequest); i { + switch v := v.(*ListPortfoliosResponse); i { case 0: return &v.state case 1: @@ -2308,7 +2406,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdatePortfolioRequest); i { + switch v := v.(*GetPortfolioRequest); i { case 0: return &v.state case 1: @@ -2320,7 +2418,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeletePortfolioRequest); i { + switch v := v.(*UpdatePortfolioRequest); i { case 0: return &v.state case 1: @@ -2332,7 +2430,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPortfolioSnapshotRequest); i { + switch v := v.(*DeletePortfolioRequest); i { case 0: return &v.state case 1: @@ -2344,7 +2442,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreatePortfolioTransactionRequest); i { + switch v := v.(*GetPortfolioSnapshotRequest); i { case 0: return &v.state case 1: @@ -2356,7 +2454,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetPortfolioTransactionRequest); i { + switch v := v.(*CreatePortfolioTransactionRequest); i { case 0: return &v.state case 1: @@ -2368,7 +2466,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListPortfolioTransactionsRequest); i { + switch v := v.(*GetPortfolioTransactionRequest); i { case 0: return &v.state case 1: @@ -2380,7 +2478,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListPortfolioTransactionsResponse); i { + switch v := v.(*ListPortfolioTransactionsRequest); i { case 0: return &v.state case 1: @@ -2392,7 +2490,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdatePortfolioTransactionRequest); i { + switch v := v.(*ListPortfolioTransactionsResponse); i { case 0: return &v.state case 1: @@ -2404,7 +2502,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeletePortfolioTransactionRequest); i { + switch v := v.(*UpdatePortfolioTransactionRequest); i { case 0: return &v.state case 1: @@ -2416,7 +2514,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ImportTransactionsRequest); i { + switch v := v.(*DeletePortfolioTransactionRequest); i { case 0: return &v.state case 1: @@ -2428,7 +2526,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Portfolio); i { + switch v := v.(*ImportTransactionsRequest); i { case 0: return &v.state case 1: @@ -2440,7 +2538,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PortfolioSnapshot); i { + switch v := v.(*Portfolio); i { case 0: return &v.state case 1: @@ -2452,7 +2550,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PortfolioPosition); i { + switch v := v.(*PortfolioSnapshot); i { case 0: return &v.state case 1: @@ -2464,7 +2562,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PortfolioEvent); i { + switch v := v.(*PortfolioPosition); i { case 0: return &v.state case 1: @@ -2476,7 +2574,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Security); i { + switch v := v.(*PortfolioEvent); i { case 0: return &v.state case 1: @@ -2488,7 +2586,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListedSecurity); i { + switch v := v.(*Security); i { case 0: return &v.state case 1: @@ -2500,7 +2598,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListSecuritiesRequest); i { + switch v := v.(*ListedSecurity); i { case 0: return &v.state case 1: @@ -2512,7 +2610,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListSecuritiesResponse); i { + switch v := v.(*ListSecuritiesRequest); i { case 0: return &v.state case 1: @@ -2524,7 +2622,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetSecurityRequest); i { + switch v := v.(*ListSecuritiesResponse); i { case 0: return &v.state case 1: @@ -2536,7 +2634,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateSecurityRequest); i { + switch v := v.(*GetSecurityRequest); i { case 0: return &v.state case 1: @@ -2548,7 +2646,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateSecurityRequest); i { + switch v := v.(*CreateSecurityRequest); i { case 0: return &v.state case 1: @@ -2560,7 +2658,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteSecurityRequest); i { + switch v := v.(*UpdateSecurityRequest); i { case 0: return &v.state case 1: @@ -2572,7 +2670,7 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TriggerQuoteUpdateRequest); i { + switch v := v.(*DeleteSecurityRequest); i { case 0: return &v.state case 1: @@ -2584,6 +2682,18 @@ func file_mgo_proto_init() { } } file_mgo_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TriggerQuoteUpdateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_mgo_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TriggerQuoteUpdateResponse); i { case 0: return &v.state @@ -2595,7 +2705,7 @@ func file_mgo_proto_init() { return nil } } - file_mgo_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_mgo_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListSecuritiesRequest_Filter); i { case 0: return &v.state @@ -2608,17 +2718,17 @@ func file_mgo_proto_init() { } } } - file_mgo_proto_msgTypes[15].OneofWrappers = []interface{}{} - file_mgo_proto_msgTypes[18].OneofWrappers = []interface{}{} + 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[21].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_mgo_proto_rawDesc, NumEnums: 1, - NumMessages: 30, + NumMessages: 31, NumExtensions: 0, NumServices: 2, }, diff --git a/gen/portfolio.go b/gen/portfolio.go index 394f4606..afcdbe2c 100644 --- a/gen/portfolio.go +++ b/gen/portfolio.go @@ -1,8 +1,10 @@ package portfoliov1 import ( + "fmt" "hash/fnv" "log/slog" + "math" "strconv" "time" ) @@ -56,9 +58,9 @@ func (tx *PortfolioEvent) LogValue() slog.Value { slog.String("name", tx.Name), slog.String("security.name", tx.SecurityName), slog.Float64("amount", float64(tx.Amount)), - slog.Float64("price", float64(tx.Price)), - slog.Float64("fees", float64(tx.Fees)), - slog.Float64("taxes", float64(tx.Taxes)), + slog.String("price", tx.Price.Pretty()), + slog.String("fees", tx.Fees.Pretty()), + slog.String("taxes", tx.Taxes.Pretty()), ) } @@ -69,3 +71,57 @@ 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 4595667a..9a9bd9a0 100644 --- a/gen/portfolio_sql.go +++ b/gen/portfolio_sql.go @@ -93,9 +93,9 @@ time DATETIME NOT NULL, portfolio_name TEXT NOT NULL, security_name TEXT NOT NULL, amount REAL, -price REAL, -fees REAL, -taxes REAL +price INTEGER, +fees INTEGER, +taxes INTEGER );`) if err != nil { return err @@ -148,9 +148,9 @@ func (e *PortfolioEvent) ReplaceIntoArgs() []any { e.PortfolioName, e.SecurityName, e.Amount, - e.Price, - e.Fees, - e.Taxes, + e.Price.GetValue(), + e.Fees.GetValue(), + e.Taxes.GetValue(), } } @@ -170,11 +170,11 @@ func (e *PortfolioEvent) UpdateArgs(columns []string) (args []any) { case "amount": args = append(args, e.Amount) case "price": - args = append(args, e.Price) + args = append(args, e.Price.GetValue()) case "fees": - args = append(args, e.Fees) + args = append(args, e.Fees.GetValue()) case "taxes": - args = append(args, e.Taxes) + args = append(args, e.Taxes.GetValue()) } } @@ -187,6 +187,10 @@ func (*PortfolioEvent) Scan(sc persistence.Scanner) (obj persistence.StorageObje t time.Time ) + e.Price = Zero() + e.Fees = Zero() + e.Taxes = Zero() + err = sc.Scan( &e.Name, &e.Type, @@ -194,9 +198,9 @@ func (*PortfolioEvent) Scan(sc persistence.Scanner) (obj persistence.StorageObje &e.PortfolioName, &e.SecurityName, &e.Amount, - &e.Price, - &e.Fees, - &e.Taxes, + &e.Price.Value, + &e.Fees.Value, + &e.Taxes.Value, ) if err != nil { return nil, err diff --git a/gen/portfolio_test.go b/gen/portfolio_test.go index 7ddff766..a6bb1506 100644 --- a/gen/portfolio_test.go +++ b/gen/portfolio_test.go @@ -15,10 +15,10 @@ func TestPortfolioEvent_MakeUniqueName(t *testing.T) { Time *timestamppb.Timestamp PortfolioName string SecurityName string - Amount float32 - Price float32 - Fees float32 - Taxes float32 + Amount float64 + Price *Currency + Fees *Currency + Taxes *Currency } tests := []struct { name string diff --git a/gen/securities_sql.go b/gen/securities_sql.go index 62aa496f..39adbbe4 100644 --- a/gen/securities_sql.go +++ b/gen/securities_sql.go @@ -29,7 +29,7 @@ func (*ListedSecurity) InitTables(db *persistence.DB) (err error) { security_name TEXT, ticker TEXT NOT NULL, currency TEXT NOT NULL, -latest_quote REAL, +latest_quote INTEGER, latest_quote_timestamp DATETIME, PRIMARY KEY (security_name, ticker) );`) @@ -112,8 +112,9 @@ func (s *Security) ReplaceIntoArgs() []any { func (l *ListedSecurity) ReplaceIntoArgs() []any { var ( - pt *time.Time - t time.Time + pt *time.Time + t time.Time + value sql.NullInt32 ) if l.LatestQuoteTimestamp != nil { @@ -121,7 +122,12 @@ func (l *ListedSecurity) ReplaceIntoArgs() []any { pt = &t } - return []any{l.SecurityName, l.Ticker, l.Currency, l.LatestQuote, pt} + if l.LatestQuote != nil { + value.Int32 = l.LatestQuote.Value + value.Valid = true + } + + return []any{l.SecurityName, l.Ticker, l.Currency, value, pt} } func (s *Security) UpdateArgs(columns []string) (args []any) { @@ -147,9 +153,9 @@ func (l *ListedSecurity) UpdateArgs(columns []string) (args []any) { case "ticker": args = append(args, l.Ticker) case "currency": - args = append(args, l.Currency) + args = append(args, l.LatestQuote.GetSymbol()) case "latest_quote": - args = append(args, l.LatestQuote) + args = append(args, l.LatestQuote.GetValue()) case "latest_quote_timestamp": if l.LatestQuoteTimestamp != nil { args = append(args, l.LatestQuoteTimestamp.AsTime()) @@ -177,11 +183,12 @@ func (*Security) Scan(sc persistence.Scanner) (obj persistence.StorageObject, er func (*ListedSecurity) Scan(sc persistence.Scanner) (obj persistence.StorageObject, err error) { var ( - l ListedSecurity - t sql.NullTime + l ListedSecurity + t sql.NullTime + value sql.NullInt32 ) - err = sc.Scan(&l.SecurityName, &l.Ticker, &l.Currency, &l.LatestQuote, &t) + err = sc.Scan(&l.SecurityName, &l.Ticker, &l.Currency, &value, &t) if err != nil { return nil, err } @@ -190,5 +197,10 @@ func (*ListedSecurity) Scan(sc persistence.Scanner) (obj persistence.StorageObje l.LatestQuoteTimestamp = timestamppb.New(t.Time) } + if value.Valid { + l.LatestQuote = Value(value.Int32) + l.LatestQuote.Symbol = l.Currency + } + return &l, nil } diff --git a/import/csv/csv_importer.go b/import/csv/csv_importer.go index c8d55f92..e6d38374 100644 --- a/import/csv/csv_importer.go +++ b/import/csv/csv_importer.go @@ -92,7 +92,7 @@ func Import(r io.Reader, pname string) (txs []*portfoliov1.PortfolioEvent, secs func readLine(cr *csv.Reader, pname string) (tx *portfoliov1.PortfolioEvent, sec *portfoliov1.Security, err error) { var ( record []string - value float32 + value *portfoliov1.Currency ) record, err = cr.Read() @@ -111,22 +111,22 @@ func readLine(cr *csv.Reader, pname string) (tx *portfoliov1.PortfolioEvent, sec return nil, nil, ErrParsingType } - value, err = parseFloat32(record[2]) + value, err = parseFloatCurrency(record[2]) if err != nil { return nil, nil, fmt.Errorf("%w: %w", ErrParsingValue, err) } - tx.Fees, err = parseFloat32(record[7]) + tx.Fees, err = parseFloatCurrency(record[7]) if err != nil { return nil, nil, fmt.Errorf("%w: %w", ErrParsingFees, err) } - tx.Taxes, err = parseFloat32(record[8]) + tx.Taxes, err = parseFloatCurrency(record[8]) if err != nil { return nil, nil, fmt.Errorf("%w: %w", ErrParsingTaxes, err) } - tx.Amount, err = parseFloat32(record[9]) + tx.Amount, err = parseFloat64(record[9]) if err != nil { return nil, nil, fmt.Errorf("%w: %w", ErrParsingAmount, err) } @@ -134,10 +134,10 @@ func readLine(cr *csv.Reader, pname string) (tx *portfoliov1.PortfolioEvent, sec // Calculate the price if tx.Type == portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY || tx.Type == portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DELIVERY_INBOUND { - tx.Price = (value - tx.Fees) / float32(tx.Amount) + tx.Price = portfoliov1.Divide(portfoliov1.Minus(value, tx.Fees), tx.Amount) } else if tx.Type == portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_SELL || tx.Type == portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_DELIVERY_OUTBOUND { - tx.Price = -(value - tx.Fees - tx.Taxes) / float32(tx.Amount) + tx.Price = portfoliov1.Times(portfoliov1.Divide(portfoliov1.Minus(portfoliov1.Minus(value, tx.Fees), tx.Taxes), tx.Amount), -1) } sec = new(portfoliov1.Security) @@ -197,18 +197,31 @@ func txTime(s string) (ts *timestamppb.Timestamp, err error) { return timestamppb.New(t), nil } -func parseFloat32(s string) (f float32, err error) { +func parseFloat64(s string) (f float64, err error) { // We assume that the float is in German locale (this might not be true for // all users), so we need to convert it s = strings.ReplaceAll(s, ".", "") s = strings.ReplaceAll(s, ",", ".") - f64, err := strconv.ParseFloat(s, 32) + f, err = strconv.ParseFloat(s, 32) if err != nil { return 0, err } - return float32(f64), nil + return +} + +func parseFloatCurrency(s string) (c *portfoliov1.Currency, err error) { + // Get rid of all , and . + s = strings.ReplaceAll(s, ".", "") + s = strings.ReplaceAll(s, ",", "") + + i, err := strconv.ParseInt(s, 10, 32) + if err != nil { + return portfoliov1.Zero(), err + } + + return portfoliov1.Value(int32(i)), nil } func lsCurrency(txCurrency string, tickerCurrency string) string { diff --git a/import/csv/csv_importer_test.go b/import/csv/csv_importer_test.go index 9c312574..6dc984a0 100644 --- a/import/csv/csv_importer_test.go +++ b/import/csv/csv_importer_test.go @@ -106,8 +106,9 @@ func Test_readLine(t *testing.T) { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, Time: timestamppb.New(time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local)), Amount: 20, - Fees: 10.25, - Price: 107.08, + Fees: portfoliov1.Value(1025), + Taxes: portfoliov1.Zero(), + Price: portfoliov1.Value(10708), }, wantSec: &portfoliov1.Security{ Name: "US0378331005", @@ -137,7 +138,9 @@ func Test_readLine(t *testing.T) { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_BUY, Time: timestamppb.New(time.Date(2022, 1, 1, 9, 0, 0, 0, time.Local)), Amount: 20, - Price: 60.395, + Price: portfoliov1.Value(6040), + Fees: portfoliov1.Zero(), + Taxes: portfoliov1.Zero(), }, wantSec: &portfoliov1.Security{ Name: "US00827B1061", @@ -167,9 +170,9 @@ func Test_readLine(t *testing.T) { Type: portfoliov1.PortfolioEventType_PORTFOLIO_EVENT_TYPE_SELL, Time: timestamppb.New(time.Date(2022, 1, 1, 8, 0, 6, 0, time.Local)), Amount: 103, - Fees: 0, - Taxes: 18.30, - Price: 15.52, + Fees: portfoliov1.Zero(), + Taxes: portfoliov1.Value(1830), + Price: portfoliov1.Value(1552), }, wantSec: &portfoliov1.Security{ Name: "DE0005557508", diff --git a/mgo.proto b/mgo.proto index 2e7e97a8..3adc2791 100644 --- a/mgo.proto +++ b/mgo.proto @@ -6,6 +6,13 @@ import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/field_mask.proto"; +// Currency is a currency value in the lowest unit of the selected currency +// (e.g., cents for EUR/USD). +message Currency { + int32 value = 1; + string symbol = 2; +} + message CreatePortfolioRequest { Portfolio portfolio = 1; } message ListPortfoliosRequest {} @@ -76,51 +83,51 @@ message PortfolioSnapshot { optional google.protobuf.Timestamp first_transaction_time = 3; // TotalPurchaseValue contains the total purchase value of all positions - float total_purchase_value = 10; + Currency total_purchase_value = 10; // TotalMarketValue contains the total market value of all positions - float total_market_value = 11; + Currency total_market_value = 11; // TotalProfitOrLoss contains the total absolute amount of profit or loss in // this snapshot. - float total_profit_or_loss = 20; + Currency total_profit_or_loss = 20; // TotalGains contains the total relative amount of profit or loss in this // snapshot. - float total_gains = 21; + double total_gains = 21; } message PortfolioPosition { Security security = 1; - float amount = 2; + double amount = 2; // PurchaseValue was the market value of this position when it was bought // (net; exclusive of any fees). - float purchase_value = 5; + Currency purchase_value = 5; // PurchasePrice was the market price of this position when it was bought // (net; exclusive of any fees). - float purchase_price = 6; + Currency purchase_price = 6; // MarketValue is the current market value of this position, as retrieved from // the securities service. - float market_value = 10; + Currency market_value = 10; // MarketPrice is the current market price of this position, as retrieved from // the securities service. - float market_price = 11; + Currency market_price = 11; // TotalFees is the total amount of fees accumulating in this position through // various transactions. - float total_fees = 15; + Currency total_fees = 15; // ProfitOrLoss contains the absolute amount of profit or loss in this // position. - float profit_or_loss = 20; + Currency profit_or_loss = 20; // Gains contains the relative amount of profit or loss in this position. - float gains = 21; + double gains = 21; } enum PortfolioEventType { @@ -139,10 +146,10 @@ message PortfolioEvent { string portfolio_name = 4; string security_name = 5; - float amount = 10; - float price = 11; - float fees = 12; - float taxes = 13; + double amount = 10; + Currency price = 11; + Currency fees = 12; + Currency taxes = 13; } service PortfolioService { @@ -198,7 +205,7 @@ message ListedSecurity { string ticker = 3; string currency = 4; - optional float latest_quote = 5; + optional Currency latest_quote = 5; optional google.protobuf.Timestamp latest_quote_timestamp = 6; } diff --git a/service/internal/crud/crud_requests.go b/service/internal/crud/crud_requests.go index d02b22bc..c1ca7bb0 100644 --- a/service/internal/crud/crud_requests.go +++ b/service/internal/crud/crud_requests.go @@ -38,14 +38,14 @@ func Create[T any, S persistence.StorageObject](obj S, op persistence.StorageOpe return } -func List[T any, S persistence.StorageObject](op persistence.StorageOperations[S], setter func(res *connect.Response[T], list []S), args ...any) (res *connect.Response[T], err error) { +func List[T any, S persistence.StorageObject](op persistence.StorageOperations[S], setter func(res *connect.Response[T], list []S) error, args ...any) (res *connect.Response[T], err error) { obj, err := op.List(args...) if err != nil { return nil, connect.NewError(connect.CodeInternal, err) } res = connect.NewResponse(new(T)) - setter(res, obj) + err = setter(res, obj) return } diff --git a/service/internal/crud/crud_requests_test.go b/service/internal/crud/crud_requests_test.go index b09335a2..710665e7 100644 --- a/service/internal/crud/crud_requests_test.go +++ b/service/internal/crud/crud_requests_test.go @@ -53,7 +53,7 @@ func TestCreate(t *testing.T) { func TestList(t *testing.T) { type args struct { op persistence.StorageOperations[*portfoliov1.Portfolio] - setter func(res *connect.Response[portfoliov1.ListPortfoliosResponse], list []*portfoliov1.Portfolio) + setter func(res *connect.Response[portfoliov1.ListPortfoliosResponse], list []*portfoliov1.Portfolio) error args []any } tests := []struct { @@ -66,8 +66,9 @@ func TestList(t *testing.T) { name: "error", args: args{ op: internal.ErrOps[*portfoliov1.Portfolio](errors.New("some-error")), - setter: func(res *connect.Response[portfoliov1.ListPortfoliosResponse], list []*portfoliov1.Portfolio) { + setter: func(res *connect.Response[portfoliov1.ListPortfoliosResponse], list []*portfoliov1.Portfolio) error { res.Msg.Portfolios = list + return nil }, args: []any{"some-key"}, }, diff --git a/service/portfolio/portfolio.go b/service/portfolio/portfolio.go index 17a1557f..61096092 100644 --- a/service/portfolio/portfolio.go +++ b/service/portfolio/portfolio.go @@ -44,12 +44,17 @@ func (svc *service) ListPortfolios(ctx context.Context, req *connect.Request[por func( res *connect.Response[portfoliov1.ListPortfoliosResponse], list []*portfoliov1.Portfolio, - ) { + ) error { res.Msg.Portfolios = list for _, p := range res.Msg.Portfolios { - p.Events, _ = svc.events.List(p.Name) + p.Events, err = svc.events.List(p.Name) + if err != nil { + return err + } } + + return nil }, ) } diff --git a/service/portfolio/portfolio_test.go b/service/portfolio/portfolio_test.go index e6e40bfb..99666d0c 100644 --- a/service/portfolio/portfolio_test.go +++ b/service/portfolio/portfolio_test.go @@ -44,8 +44,8 @@ func myPortfolio(t *testing.T) persistence.StorageOperations[*portfoliov1.Portfo PortfolioName: "bank/myportfolio", SecurityName: "US0378331005", Amount: 20, - Price: 107.08, - Fees: 10.25, + Price: portfoliov1.Value(10708), + Fees: portfoliov1.Value(1025), Time: timestamppb.New(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)), })) assert.NoError(t, rel.Replace(&portfoliov1.PortfolioEvent{ @@ -54,8 +54,8 @@ func myPortfolio(t *testing.T) persistence.StorageOperations[*portfoliov1.Portfo PortfolioName: "bank/myportfolio", SecurityName: "US0378331005", Amount: 10, - Price: 145.88, - Fees: 8.55, + Price: portfoliov1.Value(14588), + Fees: portfoliov1.Value(855), Time: timestamppb.New(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)), })) }) @@ -74,8 +74,8 @@ func zeroPositions(t *testing.T) persistence.StorageOperations[*portfoliov1.Port PortfolioName: "bank/myportfolio", SecurityName: "sec123", Amount: 10, - Price: 100.0, - Fees: 0, + Price: portfoliov1.Value(10000), + Fees: portfoliov1.Zero(), Time: timestamppb.New(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)), })) assert.NoError(t, rel.Replace(&portfoliov1.PortfolioEvent{ @@ -84,8 +84,8 @@ func zeroPositions(t *testing.T) persistence.StorageOperations[*portfoliov1.Port PortfolioName: "bank/myportfolio", SecurityName: "sec123", Amount: 10, - Price: 100.0, - Fees: 0, + Price: portfoliov1.Value(10000), + Fees: portfoliov1.Zero(), Time: timestamppb.New(time.Date(2023, 1, 2, 0, 0, 0, 0, time.UTC)), })) }) diff --git a/service/portfolio/snapshot.go b/service/portfolio/snapshot.go index 0d9e0eb9..8614c8a8 100644 --- a/service/portfolio/snapshot.go +++ b/service/portfolio/snapshot.go @@ -50,8 +50,11 @@ func (svc *service) GetPortfolioSnapshot(ctx context.Context, req *connect.Reque // Set up the snapshot snap = &portfoliov1.PortfolioSnapshot{ - Time: req.Msg.Time, - Positions: make(map[string]*portfoliov1.PortfolioPosition), + Time: req.Msg.Time, + Positions: make(map[string]*portfoliov1.PortfolioPosition), + TotalPurchaseValue: portfoliov1.Zero(), + TotalMarketValue: portfoliov1.Zero(), + TotalProfitOrLoss: portfoliov1.Zero(), } // Record the first transaction time @@ -97,36 +100,36 @@ func (svc *service) GetPortfolioSnapshot(ctx context.Context, req *connect.Reque Amount: c.Amount, PurchaseValue: c.NetValue(), PurchasePrice: c.NetPrice(), - MarketValue: marketPrice(secmap, name, c.NetPrice()) * float32(c.Amount), + MarketValue: portfoliov1.Times(marketPrice(secmap, name, c.NetPrice()), c.Amount), MarketPrice: marketPrice(secmap, name, c.NetPrice()), } // Calculate loss and gains - pos.ProfitOrLoss = pos.MarketValue - pos.PurchaseValue - pos.Gains = (pos.MarketValue - pos.PurchaseValue) / pos.PurchaseValue + pos.ProfitOrLoss = portfoliov1.Minus(pos.MarketValue, pos.PurchaseValue) + pos.Gains = float64(portfoliov1.Minus(pos.MarketValue, pos.PurchaseValue).Value) / float64(pos.PurchaseValue.Value) // Add to total value(s) - snap.TotalPurchaseValue += pos.PurchaseValue - snap.TotalMarketValue += pos.MarketValue - snap.TotalProfitOrLoss += pos.ProfitOrLoss + snap.TotalPurchaseValue.PlusAssign(pos.PurchaseValue) + snap.TotalMarketValue.PlusAssign(pos.MarketValue) + snap.TotalProfitOrLoss.PlusAssign(pos.ProfitOrLoss) // Store position in map snap.Positions[name] = pos } // Calculate total gains - snap.TotalGains = (snap.TotalMarketValue - snap.TotalPurchaseValue) / snap.TotalPurchaseValue + snap.TotalGains = float64(portfoliov1.Minus(snap.TotalMarketValue, snap.TotalPurchaseValue).Value) / float64(snap.TotalPurchaseValue.Value) return connect.NewResponse(snap), nil } -func marketPrice(secmap map[string]*portfoliov1.Security, name string, netPrice float32) float32 { +func marketPrice(secmap map[string]*portfoliov1.Security, name string, netPrice *portfoliov1.Currency) *portfoliov1.Currency { ls := secmap[name].ListedOn if ls == nil || ls[0].LatestQuote == nil { return netPrice } else { - return *ls[0].LatestQuote + return ls[0].LatestQuote } } diff --git a/service/portfolio/snapshot_test.go b/service/portfolio/snapshot_test.go index 6260a0de..c72d2f98 100644 --- a/service/portfolio/snapshot_test.go +++ b/service/portfolio/snapshot_test.go @@ -23,7 +23,6 @@ import ( "time" "github.com/oxisto/assert" - moneygopher "github.com/oxisto/money-gopher" portfoliov1 "github.com/oxisto/money-gopher/gen" "github.com/oxisto/money-gopher/gen/portfoliov1connect" "github.com/oxisto/money-gopher/internal" @@ -45,7 +44,7 @@ var mockSecuritiesClientWithData = &mockSecuritiesClient{ SecurityName: "US0378331005", Ticker: "APC.F", Currency: currency.EUR.String(), - LatestQuote: moneygopher.Ref(float32(100.0)), + LatestQuote: portfoliov1.Value(10000), LatestQuoteTimestamp: timestamppb.Now(), }, }, @@ -83,9 +82,9 @@ func Test_service_GetPortfolioSnapshot(t *testing.T) { return true && assert.Equals(t, "US0378331005", r.Msg.Positions["US0378331005"].Security.Name) && assert.Equals(t, 10, r.Msg.Positions["US0378331005"].Amount) && - assert.Equals(t, 1070.8, r.Msg.Positions["US0378331005"].PurchaseValue) && - assert.Equals(t, 107.08, r.Msg.Positions["US0378331005"].PurchasePrice) && - assert.Equals(t, 1000.0, r.Msg.TotalMarketValue) + assert.Equals(t, portfoliov1.Value(107080), r.Msg.Positions["US0378331005"].PurchaseValue) && + assert.Equals(t, portfoliov1.Value(10708), r.Msg.Positions["US0378331005"].PurchasePrice) && + assert.Equals(t, portfoliov1.Value(100000), r.Msg.TotalMarketValue) }, }, { @@ -104,10 +103,10 @@ func Test_service_GetPortfolioSnapshot(t *testing.T) { return true && assert.Equals(t, "US0378331005", pos.Security.Name) && assert.Equals(t, 20, pos.Amount) && - assert.Equals(t, 2141.6, pos.PurchaseValue) && - assert.Equals(t, 107.08, pos.PurchasePrice) && - assert.Equals(t, 100.0, pos.MarketPrice) && - assert.Equals(t, 2000.0, pos.MarketValue) + assert.Equals(t, portfoliov1.Value(214160), pos.PurchaseValue) && + assert.Equals(t, portfoliov1.Value(10708), pos.PurchasePrice) && + assert.Equals(t, portfoliov1.Value(10000), pos.MarketPrice) && + assert.Equals(t, portfoliov1.Value(200000), pos.MarketValue) }, }, { diff --git a/service/portfolio/transactions.go b/service/portfolio/transactions.go index 4273e973..edd7710d 100644 --- a/service/portfolio/transactions.go +++ b/service/portfolio/transactions.go @@ -65,8 +65,9 @@ func (svc *service) ListPortfolioTransactions(ctx context.Context, req *connect. func( res *connect.Response[portfoliov1.ListPortfolioTransactionsResponse], list []*portfoliov1.PortfolioEvent, - ) { + ) error { res.Msg.Transactions = list + return nil }, req.Msg.PortfolioName, ) diff --git a/service/securities/quote.go b/service/securities/quote.go index 3bb8acec..7e1ddc39 100644 --- a/service/securities/quote.go +++ b/service/securities/quote.go @@ -77,7 +77,7 @@ func (svc *service) TriggerSecurityQuoteUpdate(ctx context.Context, req *connect func (svc *service) updateQuote(qp QuoteProvider, ls *portfoliov1.ListedSecurity) (err error) { var ( - quote float32 + quote *portfoliov1.Currency t time.Time ctx context.Context cancel context.CancelFunc @@ -91,7 +91,7 @@ func (svc *service) updateQuote(qp QuoteProvider, ls *portfoliov1.ListedSecurity return err } - ls.LatestQuote = "e + ls.LatestQuote = quote ls.LatestQuoteTimestamp = timestamppb.New(t) _, err = svc.listedSecurities.Update( diff --git a/service/securities/quote_provider.go b/service/securities/quote_provider.go index 13835bfc..0cc3d9a1 100644 --- a/service/securities/quote_provider.go +++ b/service/securities/quote_provider.go @@ -39,5 +39,5 @@ func RegisterQuoteProvider(name string, qp QuoteProvider) { // QuoteProvider is an interface that retrieves quotes for a [ListedSecurity]. They // can either be historical quotes or the latest quote. type QuoteProvider interface { - LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) (quote float32, t time.Time, err error) + LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) (quote *portfoliov1.Currency, t time.Time, err error) } diff --git a/service/securities/quote_provider_ing.go b/service/securities/quote_provider_ing.go index 0a8dcc65..2cfeaaa7 100644 --- a/service/securities/quote_provider_ing.go +++ b/service/securities/quote_provider_ing.go @@ -45,7 +45,7 @@ type header struct { WKN string `json:"wkn"` } -func (ing *ing) LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) (quote float32, t time.Time, err error) { +func (ing *ing) LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) (quote *portfoliov1.Currency, t time.Time, err error) { var ( res *http.Response h header @@ -53,17 +53,17 @@ func (ing *ing) LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) res, err = ing.Get(fmt.Sprintf("https://component-api.wertpapiere.ing.de/api/v1/components/instrumentheader/%s", ls.SecurityName)) if err != nil { - return 0, t, fmt.Errorf("could not fetch quote: %w", err) + return nil, t, fmt.Errorf("could not fetch quote: %w", err) } err = json.NewDecoder(res.Body).Decode(&h) if err != nil { - return 0, t, fmt.Errorf("could not decode JSON: %w", err) + return nil, t, fmt.Errorf("could not decode JSON: %w", err) } if h.HasBidAsk { - return h.Bid, h.BidDate, nil + return portfoliov1.Value(int32(h.Bid * 100)), h.BidDate, nil } else { - return h.Price, h.PriceChangedDate, nil + return portfoliov1.Value(int32(h.Price * 100)), h.PriceChangedDate, nil } } diff --git a/service/securities/quote_provider_ing_test.go b/service/securities/quote_provider_ing_test.go index f571598f..041feb89 100644 --- a/service/securities/quote_provider_ing_test.go +++ b/service/securities/quote_provider_ing_test.go @@ -41,7 +41,7 @@ func Test_ing_LatestQuote(t *testing.T) { name string fields fields args args - wantQuote float32 + wantQuote *portfoliov1.Currency wantTime time.Time wantErr assert.Want[error] }{ @@ -100,7 +100,7 @@ func Test_ing_LatestQuote(t *testing.T) { Currency: "EUR", }, }, - wantQuote: float32(100.0), + wantQuote: portfoliov1.Value(10000), wantTime: time.Date(2023, 05, 04, 20, 0, 0, 0, time.UTC), wantErr: func(t *testing.T, err error) bool { return true }, }, diff --git a/service/securities/quote_provider_yf.go b/service/securities/quote_provider_yf.go index af0f5a90..7f5f4dc1 100644 --- a/service/securities/quote_provider_yf.go +++ b/service/securities/quote_provider_yf.go @@ -46,7 +46,7 @@ type chart struct { } `json:"chart"` } -func (yf *yf) LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) (quote float32, t time.Time, err error) { +func (yf *yf) LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) (quote *portfoliov1.Currency, t time.Time, err error) { var ( res *http.Response ch chart @@ -54,18 +54,18 @@ func (yf *yf) LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) ( res, err = yf.Get(fmt.Sprintf("https://query1.finance.yahoo.com/v8/finance/chart/%s?interval=1d&range=1mo", ls.Ticker)) if err != nil { - return 0, t, fmt.Errorf("could not fetch quote: %w", err) + return nil, t, fmt.Errorf("could not fetch quote: %w", err) } err = json.NewDecoder(res.Body).Decode(&ch) if err != nil { - return 0, t, fmt.Errorf("could not decode JSON: %w", err) + return nil, t, fmt.Errorf("could not decode JSON: %w", err) } if len(ch.Chart.Results) == 0 { - return 0, t, ErrEmptyResult + return nil, t, ErrEmptyResult } - return ch.Chart.Results[0].Meta.RegularMarketPrice, + return portfoliov1.Value(int32(ch.Chart.Results[0].Meta.RegularMarketPrice * 100)), time.Unix(ch.Chart.Results[0].Meta.RegularMarketTime, 0), nil } diff --git a/service/securities/quote_provider_yf_test.go b/service/securities/quote_provider_yf_test.go index bfd68e0e..b9b8e5a4 100644 --- a/service/securities/quote_provider_yf_test.go +++ b/service/securities/quote_provider_yf_test.go @@ -55,7 +55,7 @@ func Test_yf_LatestQuote(t *testing.T) { name string fields fields args args - wantQuote float32 + wantQuote *portfoliov1.Currency wantTime time.Time wantErr assert.Want[error] }{ @@ -134,7 +134,7 @@ func Test_yf_LatestQuote(t *testing.T) { Currency: "USD", }, }, - wantQuote: float32(100.0), + wantQuote: portfoliov1.Value(10000), wantTime: time.Date(2023, 05, 04, 20, 0, 0, 0, time.UTC), wantErr: func(t *testing.T, err error) bool { return true }, }, diff --git a/service/securities/quote_test.go b/service/securities/quote_test.go index 03308513..415e5472 100644 --- a/service/securities/quote_test.go +++ b/service/securities/quote_test.go @@ -36,8 +36,8 @@ const QuoteProviderMock = "mock" type mockQP struct { } -func (m *mockQP) LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) (quote float32, t time.Time, err error) { - return 1, time.Now(), nil +func (m *mockQP) LatestQuote(ctx context.Context, ls *portfoliov1.ListedSecurity) (quote *portfoliov1.Currency, t time.Time, err error) { + return portfoliov1.Value(100), time.Now(), nil } func Test_service_TriggerSecurityQuoteUpdate(t *testing.T) { @@ -101,8 +101,8 @@ func Test_service_TriggerSecurityQuoteUpdate(t *testing.T) { type mockQuoteProvider struct{} -func (mockQuoteProvider) LatestQuote(_ context.Context, _ *portfoliov1.ListedSecurity) (quote float32, t time.Time, err error) { - return 100, time.Date(1, 0, 0, 0, 0, 0, 0, time.UTC), nil +func (mockQuoteProvider) LatestQuote(_ context.Context, _ *portfoliov1.ListedSecurity) (quote *portfoliov1.Currency, t time.Time, err error) { + return portfoliov1.Value(100), time.Date(1, 0, 0, 0, 0, 0, 0, time.UTC), nil } func Test_service_updateQuote(t *testing.T) { @@ -134,7 +134,7 @@ func Test_service_updateQuote(t *testing.T) { ls: &portfoliov1.ListedSecurity{SecurityName: "My Security", Ticker: "SEC", Currency: currency.EUR.String()}, }, want: func(t *testing.T, ls *portfoliov1.ListedSecurity) bool { - return assert.Equals(t, 100, *ls.LatestQuote) + return assert.Equals(t, 100, int(ls.LatestQuote.Value)) }, }, } diff --git a/service/securities/securities.go b/service/securities/securities.go index dc7299a5..5f2aba5c 100644 --- a/service/securities/securities.go +++ b/service/securities/securities.go @@ -56,12 +56,17 @@ func (svc *service) GetSecurity(ctx context.Context, req *connect.Request[portfo func (svc *service) ListSecurities(ctx context.Context, req *connect.Request[portfoliov1.ListSecuritiesRequest]) (res *connect.Response[portfoliov1.ListSecuritiesResponse], err error) { return crud.List( svc.securities, - func(res *connect.Response[portfoliov1.ListSecuritiesResponse], list []*portfoliov1.Security) { + func(res *connect.Response[portfoliov1.ListSecuritiesResponse], list []*portfoliov1.Security) error { res.Msg.Securities = list for _, sec := range res.Msg.Securities { sec.ListedOn, err = svc.listedSecurities.List(sec.Name) + if err != nil { + return err + } } + + return nil }, ) } diff --git a/service/securities/service.go b/service/securities/service.go index 6efae565..b9e2ab38 100644 --- a/service/securities/service.go +++ b/service/securities/service.go @@ -48,14 +48,14 @@ func NewService(db *persistence.DB) portfoliov1connect.SecuritiesServiceHandler SecurityName: "US0378331005", Ticker: "APC.F", Currency: currency.EUR.String(), - LatestQuote: moneygopher.Ref(float32(150.16)), + LatestQuote: portfoliov1.Value(15016), LatestQuoteTimestamp: timestamppb.New(time.Date(2023, 4, 21, 0, 0, 0, 0, time.Local)), }, { SecurityName: "US0378331005", Ticker: "AAPL", Currency: currency.USD.String(), - LatestQuote: moneygopher.Ref(float32(165.02)), + LatestQuote: portfoliov1.Value(16502), LatestQuoteTimestamp: timestamppb.New(time.Date(2023, 4, 21, 0, 0, 0, 0, time.Local)), }, }, diff --git a/ui/src/lib/components/CurrencyInput.svelte b/ui/src/lib/components/CurrencyInput.svelte index 21b41f13..40c6cce0 100644 --- a/ui/src/lib/components/CurrencyInput.svelte +++ b/ui/src/lib/components/CurrencyInput.svelte @@ -1,30 +1,47 @@ -
- -
-
- {symbol} -
- + +
+
+ +
+ -
- {currency} + placeholder="0.00" + aria-describedby="price-currency" + /> +
+ {value.symbol} +
-
+{/if} diff --git a/ui/src/lib/components/PortfolioCard.svelte b/ui/src/lib/components/PortfolioCard.svelte index 57f00f04..c6bc603f 100644 --- a/ui/src/lib/components/PortfolioCard.svelte +++ b/ui/src/lib/components/PortfolioCard.svelte @@ -19,7 +19,9 @@ {portfolio.displayName}
- {currency(snapshot?.totalMarketValue, 'EUR')} + {#if snapshot && snapshot.totalMarketValue} + {currency(snapshot.totalMarketValue)} + {/if}
diff --git a/ui/src/lib/components/PortfolioPositionRow.svelte b/ui/src/lib/components/PortfolioPositionRow.svelte index 8e6fba3f..e566825b 100644 --- a/ui/src/lib/components/PortfolioPositionRow.svelte +++ b/ui/src/lib/components/PortfolioPositionRow.svelte @@ -52,8 +52,8 @@ class="{Math.abs(position.gains) <= 0.01 ? 'text-gray-500' : position.gains < 0 - ? 'text-red-500' - : 'text-green-500'} whitespace-nowrap px-3 py-2 text-right text-sm" + ? 'text-red-500' + : 'text-green-500'} whitespace-nowrap px-3 py-2 text-right text-sm" >
{Intl.NumberFormat(navigator.language, { @@ -63,14 +63,14 @@ src={Math.abs(position.gains) < 0.01 ? ArrowRight : position.gains < 0 - ? ArrowDown - : ArrowUp} + ? ArrowDown + : ArrowUp} class="float-right mt-0.5 h-4 w-4" aria-hidden="true" />
- {currency(position.profitOrLoss, 'EUR')} + {currency(position.profitOrLoss)}
diff --git a/ui/src/lib/components/PortfolioPositionsTable.svelte b/ui/src/lib/components/PortfolioPositionsTable.svelte index 698726e9..be4ea84f 100644 --- a/ui/src/lib/components/PortfolioPositionsTable.svelte +++ b/ui/src/lib/components/PortfolioPositionsTable.svelte @@ -16,10 +16,10 @@ return a.amount - b.amount; }); sorters.set('purchaseValue', (a: PortfolioPosition, b: PortfolioPosition) => { - return a.purchaseValue - b.purchaseValue; + return (a.purchaseValue?.value ?? 0) - (b.purchaseValue?.value ?? 0); }); sorters.set('marketValue', (a: PortfolioPosition, b: PortfolioPosition) => { - return a.marketValue - b.marketValue; + return (a.marketValue?.value ?? 0) - (b.marketValue?.value ?? 0); }); let sortBy = 'displayName'; @@ -39,9 +39,6 @@ }); } - $: perf = - ((snapshot.totalMarketValue - snapshot.totalPurchaseValue) / snapshot.totalPurchaseValue) * 100; - function toggleSortDirection() { asc = !asc; } @@ -133,34 +130,38 @@ scope="col" class="hidden px-3 py-3.5 text-right text-sm font-semibold text-gray-900 lg:table-cell" > - {currency(snapshot.totalPurchaseValue, 'EUR')} + {currency(snapshot.totalPurchaseValue)} - {currency(snapshot.totalMarketValue, 'EUR')} + {currency(snapshot.totalMarketValue)}
{Intl.NumberFormat(navigator.language, { maximumFractionDigits: 2 - }).format(perf)} % + }).format(snapshot.totalGains * 100)} %
- {currency(snapshot.totalMarketValue - snapshot.totalPurchaseValue, 'EUR')} + {currency(snapshot.totalProfitOrLoss)}
diff --git a/ui/src/lib/components/PortfolioTransactionRow.svelte b/ui/src/lib/components/PortfolioTransactionRow.svelte index 59923715..885611a0 100644 --- a/ui/src/lib/components/PortfolioTransactionRow.svelte +++ b/ui/src/lib/components/PortfolioTransactionRow.svelte @@ -1,5 +1,5 @@ @@ -34,22 +37,22 @@
- {formatCurrency(tx.price, currency)} + {formatCurrency(tx.price)}
- {formatCurrency(tx.fees, currency)} + {formatCurrency(tx.fees)}
- {formatCurrency(tx.taxes, currency)} + {formatCurrency(tx.taxes)}
- {formatCurrency(total, currency)} + {formatCurrency(total)}
diff --git a/ui/src/lib/components/PortfolioTransactionsTable.svelte b/ui/src/lib/components/PortfolioTransactionsTable.svelte index 2416e329..c7ff2274 100644 --- a/ui/src/lib/components/PortfolioTransactionsTable.svelte +++ b/ui/src/lib/components/PortfolioTransactionsTable.svelte @@ -17,13 +17,13 @@ return a.amount - b.amount; }); sorters.set('price', (a: PortfolioEvent, b: PortfolioEvent) => { - return a.price - b.price; + return (a.price?.value ?? 0) - (b.price?.value ?? 0); }); sorters.set('fees', (a: PortfolioEvent, b: PortfolioEvent) => { - return a.fees - b.fees; + return (a.fees?.value ?? 0) - (b.fees?.value ?? 0); }); sorters.set('taxes', (a: PortfolioEvent, b: PortfolioEvent) => { - return a.taxes - b.taxes; + return (a.taxes?.value ?? 0) - (b.taxes?.value ?? 0); }); let sortBy = 'time'; diff --git a/ui/src/lib/gen/mgo_pb.ts b/ui/src/lib/gen/mgo_pb.ts index 2cc4f486..6f4f5f67 100644 --- a/ui/src/lib/gen/mgo_pb.ts +++ b/ui/src/lib/gen/mgo_pb.ts @@ -50,6 +50,52 @@ proto3.util.setEnumType(PortfolioEventType, "mgo.portfolio.v1.PortfolioEventType { no: 10, name: "PORTFOLIO_EVENT_TYPE_DIVIDEND" }, ]); +/** + * Currency is a currency value in the lowest unit of the selected currency + * (e.g., cents for EUR/USD). + * + * @generated from message mgo.portfolio.v1.Currency + */ +export class Currency extends Message { + /** + * @generated from field: int32 value = 1; + */ + value = 0; + + /** + * @generated from field: string symbol = 2; + */ + symbol = ""; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "mgo.portfolio.v1.Currency"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "value", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 2, name: "symbol", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Currency { + return new Currency().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Currency { + return new Currency().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Currency { + return new Currency().fromJsonString(jsonString, options); + } + + static equals(a: Currency | PlainMessage | undefined, b: Currency | PlainMessage | undefined): boolean { + return proto3.util.equals(Currency, a, b); + } +} + /** * @generated from message mgo.portfolio.v1.CreatePortfolioRequest */ @@ -676,30 +722,30 @@ export class PortfolioSnapshot extends Message { /** * TotalPurchaseValue contains the total purchase value of all positions * - * @generated from field: float total_purchase_value = 10; + * @generated from field: mgo.portfolio.v1.Currency total_purchase_value = 10; */ - totalPurchaseValue = 0; + totalPurchaseValue?: Currency; /** * TotalMarketValue contains the total market value of all positions * - * @generated from field: float total_market_value = 11; + * @generated from field: mgo.portfolio.v1.Currency total_market_value = 11; */ - totalMarketValue = 0; + totalMarketValue?: Currency; /** * TotalProfitOrLoss contains the total absolute amount of profit or loss in * this snapshot. * - * @generated from field: float total_profit_or_loss = 20; + * @generated from field: mgo.portfolio.v1.Currency total_profit_or_loss = 20; */ - totalProfitOrLoss = 0; + totalProfitOrLoss?: Currency; /** * TotalGains contains the total relative amount of profit or loss in this * snapshot. * - * @generated from field: float total_gains = 21; + * @generated from field: double total_gains = 21; */ totalGains = 0; @@ -714,10 +760,10 @@ export class PortfolioSnapshot extends Message { { no: 1, name: "time", kind: "message", T: Timestamp }, { no: 2, name: "positions", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "message", T: PortfolioPosition} }, { no: 3, name: "first_transaction_time", kind: "message", T: Timestamp, opt: true }, - { no: 10, name: "total_purchase_value", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 11, name: "total_market_value", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 20, name: "total_profit_or_loss", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 21, name: "total_gains", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + { no: 10, name: "total_purchase_value", kind: "message", T: Currency }, + { 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 */ }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): PortfolioSnapshot { @@ -747,7 +793,7 @@ export class PortfolioPosition extends Message { security?: Security; /** - * @generated from field: float amount = 2; + * @generated from field: double amount = 2; */ amount = 0; @@ -755,54 +801,54 @@ export class PortfolioPosition extends Message { * PurchaseValue was the market value of this position when it was bought * (net; exclusive of any fees). * - * @generated from field: float purchase_value = 5; + * @generated from field: mgo.portfolio.v1.Currency purchase_value = 5; */ - purchaseValue = 0; + purchaseValue?: Currency; /** * PurchasePrice was the market price of this position when it was bought * (net; exclusive of any fees). * - * @generated from field: float purchase_price = 6; + * @generated from field: mgo.portfolio.v1.Currency purchase_price = 6; */ - purchasePrice = 0; + purchasePrice?: Currency; /** * MarketValue is the current market value of this position, as retrieved from * the securities service. * - * @generated from field: float market_value = 10; + * @generated from field: mgo.portfolio.v1.Currency market_value = 10; */ - marketValue = 0; + marketValue?: Currency; /** * MarketPrice is the current market price of this position, as retrieved from * the securities service. * - * @generated from field: float market_price = 11; + * @generated from field: mgo.portfolio.v1.Currency market_price = 11; */ - marketPrice = 0; + marketPrice?: Currency; /** * TotalFees is the total amount of fees accumulating in this position through * various transactions. * - * @generated from field: float total_fees = 15; + * @generated from field: mgo.portfolio.v1.Currency total_fees = 15; */ - totalFees = 0; + totalFees?: Currency; /** * ProfitOrLoss contains the absolute amount of profit or loss in this * position. * - * @generated from field: float profit_or_loss = 20; + * @generated from field: mgo.portfolio.v1.Currency profit_or_loss = 20; */ - profitOrLoss = 0; + profitOrLoss?: Currency; /** * Gains contains the relative amount of profit or loss in this position. * - * @generated from field: float gains = 21; + * @generated from field: double gains = 21; */ gains = 0; @@ -815,14 +861,14 @@ export class PortfolioPosition extends Message { static readonly typeName = "mgo.portfolio.v1.PortfolioPosition"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "security", kind: "message", T: Security }, - { no: 2, name: "amount", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 5, name: "purchase_value", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 6, name: "purchase_price", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 10, name: "market_value", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 11, name: "market_price", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 15, name: "total_fees", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 20, name: "profit_or_loss", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 21, name: "gains", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + { no: 2, name: "amount", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ }, + { no: 5, name: "purchase_value", kind: "message", T: Currency }, + { no: 6, name: "purchase_price", kind: "message", T: Currency }, + { no: 10, name: "market_value", kind: "message", T: Currency }, + { no: 11, name: "market_price", kind: "message", T: Currency }, + { no: 15, name: "total_fees", kind: "message", T: Currency }, + { no: 20, name: "profit_or_loss", kind: "message", T: Currency }, + { no: 21, name: "gains", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): PortfolioPosition { @@ -872,24 +918,24 @@ export class PortfolioEvent extends Message { securityName = ""; /** - * @generated from field: float amount = 10; + * @generated from field: double amount = 10; */ amount = 0; /** - * @generated from field: float price = 11; + * @generated from field: mgo.portfolio.v1.Currency price = 11; */ - price = 0; + price?: Currency; /** - * @generated from field: float fees = 12; + * @generated from field: mgo.portfolio.v1.Currency fees = 12; */ - fees = 0; + fees?: Currency; /** - * @generated from field: float taxes = 13; + * @generated from field: mgo.portfolio.v1.Currency taxes = 13; */ - taxes = 0; + taxes?: Currency; constructor(data?: PartialMessage) { super(); @@ -904,10 +950,10 @@ export class PortfolioEvent extends Message { { no: 3, name: "time", kind: "message", T: Timestamp }, { no: 4, name: "portfolio_name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 5, name: "security_name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 10, name: "amount", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 11, name: "price", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 12, name: "fees", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, - { no: 13, name: "taxes", kind: "scalar", T: 2 /* ScalarType.FLOAT */ }, + { no: 10, name: "amount", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ }, + { no: 11, name: "price", kind: "message", T: Currency }, + { no: 12, name: "fees", kind: "message", T: Currency }, + { no: 13, name: "taxes", kind: "message", T: Currency }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): PortfolioEvent { @@ -1007,9 +1053,9 @@ export class ListedSecurity extends Message { currency = ""; /** - * @generated from field: optional float latest_quote = 5; + * @generated from field: optional mgo.portfolio.v1.Currency latest_quote = 5; */ - latestQuote?: number; + latestQuote?: Currency; /** * @generated from field: optional google.protobuf.Timestamp latest_quote_timestamp = 6; @@ -1027,7 +1073,7 @@ export class ListedSecurity extends Message { { no: 1, name: "security_name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "ticker", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 4, name: "currency", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 5, name: "latest_quote", kind: "scalar", T: 2 /* ScalarType.FLOAT */, opt: true }, + { no: 5, name: "latest_quote", kind: "message", T: Currency, opt: true }, { no: 6, name: "latest_quote_timestamp", kind: "message", T: Timestamp, opt: true }, ]); diff --git a/ui/src/lib/intl.ts b/ui/src/lib/intl.ts index 5bb81140..ce1cd6af 100644 --- a/ui/src/lib/intl.ts +++ b/ui/src/lib/intl.ts @@ -1,8 +1,14 @@ -export function currency(value: number, currency: string): string { +import type { Currency } from './gen/mgo_pb'; + +export function currency(c: Currency | undefined): string { + if (c === undefined) { + return ''; + } + const formatter = Intl.NumberFormat(navigator.language, { style: 'currency', - currency: currency + currency: c.symbol }); - return formatter.format(value); + return formatter.format(c.value / 100); } diff --git a/ui/src/routes/portfolios/[...portfolioName]/transactions/[txName]/+page.svelte b/ui/src/routes/portfolios/[...portfolioName]/transactions/[txName]/+page.svelte index 868b6c33..f8260bde 100644 --- a/ui/src/routes/portfolios/[...portfolioName]/transactions/[txName]/+page.svelte +++ b/ui/src/routes/portfolios/[...portfolioName]/transactions/[txName]/+page.svelte @@ -9,12 +9,18 @@ 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; - $: total = - data.transaction.amount * - (data.transaction.price + data.transaction.fees + data.transaction.taxes); + $: total = new Currency({ + symbol: 'EUR', + value: + data.transaction.amount * + ((data.transaction.price?.value ?? 0) + + (data.transaction.fees?.value ?? 0) + + (data.transaction.taxes?.value ?? 0)) + }); async function save() { try { @@ -58,14 +64,14 @@
-
- -
- +
+ +
+ +
-
diff --git a/ui/src/routes/securities/+page.svelte b/ui/src/routes/securities/+page.svelte index 99f900c2..a9ecce7a 100644 --- a/ui/src/routes/securities/+page.svelte +++ b/ui/src/routes/securities/+page.svelte @@ -1,4 +1,5 @@