diff --git a/Makefile b/Makefile index 6e13fe0c24..83dc2eb74b 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ pack-files: generate-proto: ## regenerate protos @echo " > cloning protobuf from odpf/proton" @rm -rf proton/ - @git -c advice.detachedHead=false clone https://github.com/odpf/proton --depth 1 --quiet --branch main + @git -c advice.detachedHead=false clone https://github.com/odpf/proton --depth 1 --quiet --branch DBTCH-1024 @echo " > generating protobuf" @echo " > info: make sure correct version of dependencies are installed using 'install'" @buf generate diff --git a/api/handler/v1/runtime.go b/api/handler/v1/runtime.go index 4a0b0e53ab..8b768841ea 100644 --- a/api/handler/v1/runtime.go +++ b/api/handler/v1/runtime.go @@ -731,7 +731,44 @@ func (sv *RuntimeServiceServer) ListResourceSpecification(ctx context.Context, r }, nil } -func (sv *RuntimeServiceServer) ReplayDryRun(ctx context.Context, req *pb.ReplayDryRunRequest) (*pb.ReplayDryRunResponse, error) { +func (sv *RuntimeServiceServer) ReplayDryRun(ctx context.Context, req *pb.ReplayRequest) (*pb.ReplayDryRunResponse, error) { + replayRequestInput, err := sv.parseReplayRequest(req) + if err != nil { + return nil, err + } + + rootNode, err := sv.jobSvc.ReplayDryRun(replayRequestInput) + if err != nil { + return nil, status.Error(codes.Internal, fmt.Sprintf("error while processing replay: %v", err)) + } + + node, err := sv.adapter.ToReplayExecutionTreeNode(rootNode) + if err != nil { + return nil, status.Error(codes.Internal, fmt.Sprintf("error while processing replay: %v", err)) + } + return &pb.ReplayDryRunResponse{ + Success: true, + Response: node, + }, nil +} + +func (sv *RuntimeServiceServer) Replay(ctx context.Context, req *pb.ReplayRequest) (*pb.ReplayResponse, error) { + replayRequestInput, err := sv.parseReplayRequest(req) + if err != nil { + return nil, err + } + + replayUUID, err := sv.jobSvc.Replay(replayRequestInput) + if err != nil { + return nil, status.Error(codes.Internal, fmt.Sprintf("error while processing replay: %v", err)) + } + + return &pb.ReplayResponse{ + Id: replayUUID, + }, nil +} + +func (sv *RuntimeServiceServer) parseReplayRequest(req *pb.ReplayRequest) (*models.ReplayRequestInput, error) { projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { @@ -764,20 +801,13 @@ func (sv *RuntimeServiceServer) ReplayDryRun(ctx context.Context, req *pb.Replay if endDate.Before(startDate) { return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("replay end date cannot be before start date")) } - - rootNode, err := sv.jobSvc.ReplayDryRun(namespaceSpec, jobSpec, startDate, endDate) - if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("error while processing replay: %v", err)) + replayRequest := models.ReplayRequestInput{ + Job: jobSpec, + Start: startDate, + End: endDate, + Project: projSpec, } - - node, err := sv.adapter.ToReplayExecutionTreeNode(rootNode) - if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("error while processing replay: %v", err)) - } - return &pb.ReplayDryRunResponse{ - Success: true, - Response: node, - }, nil + return &replayRequest, nil } func NewRuntimeServiceServer( diff --git a/api/handler/v1/runtime_test.go b/api/handler/v1/runtime_test.go index 5e20259192..cf7fd7ec98 100644 --- a/api/handler/v1/runtime_test.go +++ b/api/handler/v1/runtime_test.go @@ -1479,11 +1479,17 @@ func TestRuntimeServiceServer(t *testing.T) { }, }), } + replayRequestInput := &models.ReplayRequestInput{ + Job: jobSpec, + Start: startDate, + End: endDate, + Project: projectSpec, + } dagNode := tree.NewTreeNode(jobSpec) jobService := new(mock.JobService) jobService.On("GetByName", jobName, namespaceSpec).Return(jobSpec, nil) - jobService.On("ReplayDryRun", namespaceSpec, jobSpec, startDate, endDate).Return(dagNode, nil) + jobService.On("ReplayDryRun", replayRequestInput).Return(dagNode, nil) defer jobService.AssertExpectations(t) projectRepository := new(mock.ProjectRepository) @@ -1514,7 +1520,7 @@ func TestRuntimeServiceServer(t *testing.T) { nil, nil, ) - replayRequest := pb.ReplayDryRunRequest{ + replayRequest := pb.ReplayRequest{ ProjectName: projectName, Namespace: namespaceSpec.Name, JobName: jobName, diff --git a/api/proto/odpf/optimus/runtime_service.pb.go b/api/proto/odpf/optimus/runtime_service.pb.go index 4c7ff7d5d1..041376a69c 100644 --- a/api/proto/odpf/optimus/runtime_service.pb.go +++ b/api/proto/odpf/optimus/runtime_service.pb.go @@ -3529,7 +3529,7 @@ func (x *UpdateResourceResponse) GetMessage() string { return "" } -type ReplayDryRunRequest struct { +type ReplayRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -3541,8 +3541,8 @@ type ReplayDryRunRequest struct { EndDate string `protobuf:"bytes,5,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` } -func (x *ReplayDryRunRequest) Reset() { - *x = ReplayDryRunRequest{} +func (x *ReplayRequest) Reset() { + *x = ReplayRequest{} if protoimpl.UnsafeEnabled { mi := &file_odpf_optimus_runtime_service_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -3550,13 +3550,13 @@ func (x *ReplayDryRunRequest) Reset() { } } -func (x *ReplayDryRunRequest) String() string { +func (x *ReplayRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ReplayDryRunRequest) ProtoMessage() {} +func (*ReplayRequest) ProtoMessage() {} -func (x *ReplayDryRunRequest) ProtoReflect() protoreflect.Message { +func (x *ReplayRequest) ProtoReflect() protoreflect.Message { mi := &file_odpf_optimus_runtime_service_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -3568,40 +3568,40 @@ func (x *ReplayDryRunRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ReplayDryRunRequest.ProtoReflect.Descriptor instead. -func (*ReplayDryRunRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use ReplayRequest.ProtoReflect.Descriptor instead. +func (*ReplayRequest) Descriptor() ([]byte, []int) { return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{55} } -func (x *ReplayDryRunRequest) GetProjectName() string { +func (x *ReplayRequest) GetProjectName() string { if x != nil { return x.ProjectName } return "" } -func (x *ReplayDryRunRequest) GetJobName() string { +func (x *ReplayRequest) GetJobName() string { if x != nil { return x.JobName } return "" } -func (x *ReplayDryRunRequest) GetNamespace() string { +func (x *ReplayRequest) GetNamespace() string { if x != nil { return x.Namespace } return "" } -func (x *ReplayDryRunRequest) GetStartDate() string { +func (x *ReplayRequest) GetStartDate() string { if x != nil { return x.StartDate } return "" } -func (x *ReplayDryRunRequest) GetEndDate() string { +func (x *ReplayRequest) GetEndDate() string { if x != nil { return x.EndDate } @@ -3726,6 +3726,53 @@ func (x *ReplayExecutionTreeNode) GetRuns() []*timestamp.Timestamp { return nil } +type ReplayResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ReplayResponse) Reset() { + *x = ReplayResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReplayResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReplayResponse) ProtoMessage() {} + +func (x *ReplayResponse) ProtoReflect() protoreflect.Message { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[58] + 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 ReplayResponse.ProtoReflect.Descriptor instead. +func (*ReplayResponse) Descriptor() ([]byte, []int) { + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{58} +} + +func (x *ReplayResponse) GetId() string { + if x != nil { + return x.Id + } + return "" +} + type ProjectSpecification_ProjectSecret struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3738,7 +3785,7 @@ type ProjectSpecification_ProjectSecret struct { func (x *ProjectSpecification_ProjectSecret) Reset() { *x = ProjectSpecification_ProjectSecret{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[59] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3751,7 +3798,7 @@ func (x *ProjectSpecification_ProjectSecret) String() string { func (*ProjectSpecification_ProjectSecret) ProtoMessage() {} func (x *ProjectSpecification_ProjectSecret) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[59] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3792,7 +3839,7 @@ type JobSpecification_Behavior struct { func (x *JobSpecification_Behavior) Reset() { *x = JobSpecification_Behavior{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[63] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3805,7 +3852,7 @@ func (x *JobSpecification_Behavior) String() string { func (*JobSpecification_Behavior) ProtoMessage() {} func (x *JobSpecification_Behavior) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[63] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3842,7 +3889,7 @@ type JobSpecification_Behavior_Retry struct { func (x *JobSpecification_Behavior_Retry) Reset() { *x = JobSpecification_Behavior_Retry{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[64] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3855,7 +3902,7 @@ func (x *JobSpecification_Behavior_Retry) String() string { func (*JobSpecification_Behavior_Retry) ProtoMessage() {} func (x *JobSpecification_Behavior_Retry) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[64] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4432,274 +4479,284 @@ var file_odpf_optimus_runtime_service_proto_rawDesc = []byte{ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x13, 0x52, 0x65, - 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, - 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x65, 0x6e, 0x64, 0x44, 0x61, 0x74, 0x65, 0x22, 0x73, 0x0a, 0x14, 0x52, 0x65, 0x70, 0x6c, 0x61, - 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x72, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x64, - 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x0d, 0x52, 0x65, + 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, + 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x61, + 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x44, 0x61, 0x74, + 0x65, 0x22, 0x73, 0x0a, 0x14, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, - 0x64, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xab, 0x01, 0x0a, - 0x17, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x45, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x0a, - 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x75, - 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 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, 0x72, 0x75, 0x6e, 0x73, 0x32, 0xe0, 0x1c, 0x0a, 0x0e, 0x52, - 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, - 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x01, - 0x2a, 0x12, 0x77, 0x0a, 0x16, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, - 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, + 0x64, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x45, 0x0a, + 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, + 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, + 0x72, 0x75, 0x6e, 0x73, 0x22, 0x20, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0xde, 0x1d, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x07, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, + 0x16, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, + 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0xb8, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, + 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x3d, 0x22, 0x38, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x3a, 0x01, + 0x2a, 0x12, 0xba, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0xb8, 0x01, 0x0a, 0x16, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3d, 0x22, 0x38, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x6a, - 0x6f, 0x62, 0x3a, 0x01, 0x2a, 0x12, 0xba, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, - 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, - 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x12, 0x43, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x12, 0xc0, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, - 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, - 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, - 0x2a, 0x43, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x99, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, - 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x12, 0x22, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, - 0x62, 0x12, 0xa9, 0x01, 0x0a, 0x14, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x12, 0x43, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, + 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xc0, + 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, + 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x2a, 0x43, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x12, 0x99, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, - 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x3a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, - 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x75, 0x6d, 0x70, 0x12, 0xa2, 0x01, - 0x0a, 0x15, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x12, 0xa9, 0x01, + 0x0a, 0x14, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x75, 0x6d, 0x70, 0x12, 0xa2, 0x01, 0x0a, 0x15, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x63, 0x68, 0x65, - 0x63, 0x6b, 0x12, 0x77, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, - 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x7a, 0x0a, 0x0f, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x24, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0xae, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x12, 0x2d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x28, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x9b, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x64, - 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x22, 0x33, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, - 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x2f, 0x7b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x3a, 0x01, 0x2a, 0x12, 0x6e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0xa2, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x12, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x2a, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x77, + 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, + 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x7a, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x24, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, + 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x3a, 0x01, 0x2a, 0x12, 0xae, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x2a, 0x12, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0xa4, 0x01, 0x0a, 0x10, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x12, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3b, 0x22, 0x36, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x12, 0x2d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x3a, - 0x01, 0x2a, 0x12, 0x8a, 0x01, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x3c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x12, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, - 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x64, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x1e, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x57, - 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x57, - 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x77, - 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x86, 0x01, 0x0a, 0x1b, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0xde, - 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6f, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x9b, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, + 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x22, 0x33, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x2f, 0x7b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x3a, + 0x01, 0x2a, 0x12, 0x6e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x12, 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x12, 0xa2, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x60, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x5a, 0x12, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0xa4, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x2e, 0x6f, + 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x3b, 0x22, 0x36, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x8a, + 0x01, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x6f, + 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6f, + 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x12, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, - 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0xc0, 0x01, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x22, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x64, 0x0a, 0x09, 0x47, + 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x12, 0x86, 0x01, 0x0a, 0x1b, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x30, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0xde, 0x01, 0x0a, 0x19, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x60, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x5a, 0x12, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0xc0, 0x01, 0x0a, 0x0e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, + 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x5d, 0x22, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xc7, + 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, + 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x70, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6a, 0x12, 0x68, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, + 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xc0, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x64, + 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x1a, 0x58, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, + 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x95, 0x01, 0x0a, 0x0c, + 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x1b, 0x2e, 0x6f, + 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, + 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, + 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x3e, 0x12, 0x3c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, - 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, - 0x01, 0x2a, 0x12, 0xc7, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x70, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x6a, 0x12, 0x68, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x7b, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xc0, 0x01, 0x0a, - 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x5d, 0x1a, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, - 0x9b, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, - 0x12, 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3e, 0x12, - 0x3c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, - 0x65, 0x70, 0x6c, 0x61, 0x79, 0x2d, 0x64, 0x72, 0x79, 0x2d, 0x72, 0x75, 0x6e, 0x42, 0x70, 0x0a, - 0x16, 0x69, 0x6f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x42, 0x15, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x01, - 0x5a, 0x1e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x64, 0x70, - 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, - 0x92, 0x41, 0x1c, 0x12, 0x05, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x2a, 0x01, 0x01, 0x72, 0x10, 0x0a, - 0x0e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x2d, 0x64, 0x72, 0x79, 0x2d, + 0x72, 0x75, 0x6e, 0x12, 0x81, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x12, 0x1b, + 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, + 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6f, 0x64, + 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x36, 0x12, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, + 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x70, 0x0a, 0x16, 0x69, 0x6f, 0x2e, 0x6f, 0x64, + 0x70, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x42, 0x15, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x1e, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x64, 0x70, 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x92, 0x41, 0x1c, 0x12, 0x05, 0x32, + 0x03, 0x30, 0x2e, 0x31, 0x2a, 0x01, 0x01, 0x72, 0x10, 0x0a, 0x0e, 0x4f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -4715,7 +4772,7 @@ func file_odpf_optimus_runtime_service_proto_rawDescGZIP() []byte { } var file_odpf_optimus_runtime_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_odpf_optimus_runtime_service_proto_msgTypes = make([]protoimpl.MessageInfo, 69) +var file_odpf_optimus_runtime_service_proto_msgTypes = make([]protoimpl.MessageInfo, 70) var file_odpf_optimus_runtime_service_proto_goTypes = []interface{}{ (InstanceSpec_Type)(0), // 0: odpf.optimus.InstanceSpec.Type (InstanceSpecData_Type)(0), // 1: odpf.optimus.InstanceSpecData.Type @@ -4774,44 +4831,45 @@ var file_odpf_optimus_runtime_service_proto_goTypes = []interface{}{ (*ReadResourceResponse)(nil), // 54: odpf.optimus.ReadResourceResponse (*UpdateResourceRequest)(nil), // 55: odpf.optimus.UpdateResourceRequest (*UpdateResourceResponse)(nil), // 56: odpf.optimus.UpdateResourceResponse - (*ReplayDryRunRequest)(nil), // 57: odpf.optimus.ReplayDryRunRequest + (*ReplayRequest)(nil), // 57: odpf.optimus.ReplayRequest (*ReplayDryRunResponse)(nil), // 58: odpf.optimus.ReplayDryRunResponse (*ReplayExecutionTreeNode)(nil), // 59: odpf.optimus.ReplayExecutionTreeNode - nil, // 60: odpf.optimus.ProjectSpecification.ConfigEntry - (*ProjectSpecification_ProjectSecret)(nil), // 61: odpf.optimus.ProjectSpecification.ProjectSecret - nil, // 62: odpf.optimus.NamespaceSpecification.ConfigEntry - nil, // 63: odpf.optimus.JobSpecification.AssetsEntry - nil, // 64: odpf.optimus.JobSpecification.LabelsEntry - (*JobSpecification_Behavior)(nil), // 65: odpf.optimus.JobSpecification.Behavior - (*JobSpecification_Behavior_Retry)(nil), // 66: odpf.optimus.JobSpecification.Behavior.Retry - nil, // 67: odpf.optimus.InstanceContext.EnvsEntry - nil, // 68: odpf.optimus.InstanceContext.FilesEntry - nil, // 69: odpf.optimus.ResourceSpecification.AssetsEntry - nil, // 70: odpf.optimus.ResourceSpecification.LabelsEntry - (*timestamp.Timestamp)(nil), // 71: google.protobuf.Timestamp - (*_struct.Struct)(nil), // 72: google.protobuf.Struct - (*duration.Duration)(nil), // 73: google.protobuf.Duration + (*ReplayResponse)(nil), // 60: odpf.optimus.ReplayResponse + nil, // 61: odpf.optimus.ProjectSpecification.ConfigEntry + (*ProjectSpecification_ProjectSecret)(nil), // 62: odpf.optimus.ProjectSpecification.ProjectSecret + nil, // 63: odpf.optimus.NamespaceSpecification.ConfigEntry + nil, // 64: odpf.optimus.JobSpecification.AssetsEntry + nil, // 65: odpf.optimus.JobSpecification.LabelsEntry + (*JobSpecification_Behavior)(nil), // 66: odpf.optimus.JobSpecification.Behavior + (*JobSpecification_Behavior_Retry)(nil), // 67: odpf.optimus.JobSpecification.Behavior.Retry + nil, // 68: odpf.optimus.InstanceContext.EnvsEntry + nil, // 69: odpf.optimus.InstanceContext.FilesEntry + nil, // 70: odpf.optimus.ResourceSpecification.AssetsEntry + nil, // 71: odpf.optimus.ResourceSpecification.LabelsEntry + (*timestamp.Timestamp)(nil), // 72: google.protobuf.Timestamp + (*_struct.Struct)(nil), // 73: google.protobuf.Struct + (*duration.Duration)(nil), // 74: google.protobuf.Duration } var file_odpf_optimus_runtime_service_proto_depIdxs = []int32{ - 60, // 0: odpf.optimus.ProjectSpecification.config:type_name -> odpf.optimus.ProjectSpecification.ConfigEntry - 61, // 1: odpf.optimus.ProjectSpecification.secrets:type_name -> odpf.optimus.ProjectSpecification.ProjectSecret - 62, // 2: odpf.optimus.NamespaceSpecification.config:type_name -> odpf.optimus.NamespaceSpecification.ConfigEntry + 61, // 0: odpf.optimus.ProjectSpecification.config:type_name -> odpf.optimus.ProjectSpecification.ConfigEntry + 62, // 1: odpf.optimus.ProjectSpecification.secrets:type_name -> odpf.optimus.ProjectSpecification.ProjectSecret + 63, // 2: odpf.optimus.NamespaceSpecification.config:type_name -> odpf.optimus.NamespaceSpecification.ConfigEntry 6, // 3: odpf.optimus.JobSpecHook.config:type_name -> odpf.optimus.JobConfigItem 6, // 4: odpf.optimus.JobSpecification.config:type_name -> odpf.optimus.JobConfigItem 7, // 5: odpf.optimus.JobSpecification.dependencies:type_name -> odpf.optimus.JobDependency - 63, // 6: odpf.optimus.JobSpecification.assets:type_name -> odpf.optimus.JobSpecification.AssetsEntry + 64, // 6: odpf.optimus.JobSpecification.assets:type_name -> odpf.optimus.JobSpecification.AssetsEntry 4, // 7: odpf.optimus.JobSpecification.hooks:type_name -> odpf.optimus.JobSpecHook - 64, // 8: odpf.optimus.JobSpecification.labels:type_name -> odpf.optimus.JobSpecification.LabelsEntry - 65, // 9: odpf.optimus.JobSpecification.behavior:type_name -> odpf.optimus.JobSpecification.Behavior - 71, // 10: odpf.optimus.InstanceSpec.scheduled_at:type_name -> google.protobuf.Timestamp + 65, // 8: odpf.optimus.JobSpecification.labels:type_name -> odpf.optimus.JobSpecification.LabelsEntry + 66, // 9: odpf.optimus.JobSpecification.behavior:type_name -> odpf.optimus.JobSpecification.Behavior + 72, // 10: odpf.optimus.InstanceSpec.scheduled_at:type_name -> google.protobuf.Timestamp 9, // 11: odpf.optimus.InstanceSpec.data:type_name -> odpf.optimus.InstanceSpecData 1, // 12: odpf.optimus.InstanceSpecData.type:type_name -> odpf.optimus.InstanceSpecData.Type - 67, // 13: odpf.optimus.InstanceContext.envs:type_name -> odpf.optimus.InstanceContext.EnvsEntry - 68, // 14: odpf.optimus.InstanceContext.files:type_name -> odpf.optimus.InstanceContext.FilesEntry - 71, // 15: odpf.optimus.JobStatus.scheduled_at:type_name -> google.protobuf.Timestamp - 72, // 16: odpf.optimus.ResourceSpecification.spec:type_name -> google.protobuf.Struct - 69, // 17: odpf.optimus.ResourceSpecification.assets:type_name -> odpf.optimus.ResourceSpecification.AssetsEntry - 70, // 18: odpf.optimus.ResourceSpecification.labels:type_name -> odpf.optimus.ResourceSpecification.LabelsEntry + 68, // 13: odpf.optimus.InstanceContext.envs:type_name -> odpf.optimus.InstanceContext.EnvsEntry + 69, // 14: odpf.optimus.InstanceContext.files:type_name -> odpf.optimus.InstanceContext.FilesEntry + 72, // 15: odpf.optimus.JobStatus.scheduled_at:type_name -> google.protobuf.Timestamp + 73, // 16: odpf.optimus.ResourceSpecification.spec:type_name -> google.protobuf.Struct + 70, // 17: odpf.optimus.ResourceSpecification.assets:type_name -> odpf.optimus.ResourceSpecification.AssetsEntry + 71, // 18: odpf.optimus.ResourceSpecification.labels:type_name -> odpf.optimus.ResourceSpecification.LabelsEntry 5, // 19: odpf.optimus.DeployJobSpecificationRequest.jobs:type_name -> odpf.optimus.JobSpecification 5, // 20: odpf.optimus.ListJobSpecificationResponse.jobs:type_name -> odpf.optimus.JobSpecification 5, // 21: odpf.optimus.CheckJobSpecificationRequest.job:type_name -> odpf.optimus.JobSpecification @@ -4823,7 +4881,7 @@ var file_odpf_optimus_runtime_service_proto_depIdxs = []int32{ 5, // 27: odpf.optimus.ReadJobSpecificationResponse.spec:type_name -> odpf.optimus.JobSpecification 2, // 28: odpf.optimus.ListProjectsResponse.projects:type_name -> odpf.optimus.ProjectSpecification 3, // 29: odpf.optimus.ListProjectNamespacesResponse.namespaces:type_name -> odpf.optimus.NamespaceSpecification - 71, // 30: odpf.optimus.RegisterInstanceRequest.scheduled_at:type_name -> google.protobuf.Timestamp + 72, // 30: odpf.optimus.RegisterInstanceRequest.scheduled_at:type_name -> google.protobuf.Timestamp 0, // 31: odpf.optimus.RegisterInstanceRequest.instance_type:type_name -> odpf.optimus.InstanceSpec.Type 2, // 32: odpf.optimus.RegisterInstanceResponse.project:type_name -> odpf.optimus.ProjectSpecification 5, // 33: odpf.optimus.RegisterInstanceResponse.job:type_name -> odpf.optimus.JobSpecification @@ -4831,9 +4889,9 @@ var file_odpf_optimus_runtime_service_proto_depIdxs = []int32{ 3, // 35: odpf.optimus.RegisterInstanceResponse.namespace:type_name -> odpf.optimus.NamespaceSpecification 10, // 36: odpf.optimus.RegisterInstanceResponse.context:type_name -> odpf.optimus.InstanceContext 11, // 37: odpf.optimus.JobStatusResponse.statuses:type_name -> odpf.optimus.JobStatus - 71, // 38: odpf.optimus.GetWindowRequest.scheduled_at:type_name -> google.protobuf.Timestamp - 71, // 39: odpf.optimus.GetWindowResponse.start:type_name -> google.protobuf.Timestamp - 71, // 40: odpf.optimus.GetWindowResponse.end:type_name -> google.protobuf.Timestamp + 72, // 38: odpf.optimus.GetWindowRequest.scheduled_at:type_name -> google.protobuf.Timestamp + 72, // 39: odpf.optimus.GetWindowResponse.start:type_name -> google.protobuf.Timestamp + 72, // 40: odpf.optimus.GetWindowResponse.end:type_name -> google.protobuf.Timestamp 12, // 41: odpf.optimus.DeployResourceSpecificationRequest.resources:type_name -> odpf.optimus.ResourceSpecification 12, // 42: odpf.optimus.ListResourceSpecificationResponse.resources:type_name -> odpf.optimus.ResourceSpecification 12, // 43: odpf.optimus.CreateResourceRequest.resource:type_name -> odpf.optimus.ResourceSpecification @@ -4841,9 +4899,9 @@ var file_odpf_optimus_runtime_service_proto_depIdxs = []int32{ 12, // 45: odpf.optimus.UpdateResourceRequest.resource:type_name -> odpf.optimus.ResourceSpecification 59, // 46: odpf.optimus.ReplayDryRunResponse.response:type_name -> odpf.optimus.ReplayExecutionTreeNode 59, // 47: odpf.optimus.ReplayExecutionTreeNode.dependents:type_name -> odpf.optimus.ReplayExecutionTreeNode - 71, // 48: odpf.optimus.ReplayExecutionTreeNode.runs:type_name -> google.protobuf.Timestamp - 66, // 49: odpf.optimus.JobSpecification.Behavior.retry:type_name -> odpf.optimus.JobSpecification.Behavior.Retry - 73, // 50: odpf.optimus.JobSpecification.Behavior.Retry.delay:type_name -> google.protobuf.Duration + 72, // 48: odpf.optimus.ReplayExecutionTreeNode.runs:type_name -> google.protobuf.Timestamp + 67, // 49: odpf.optimus.JobSpecification.Behavior.retry:type_name -> odpf.optimus.JobSpecification.Behavior.Retry + 74, // 50: odpf.optimus.JobSpecification.Behavior.Retry.delay:type_name -> google.protobuf.Duration 13, // 51: odpf.optimus.RuntimeService.Version:input_type -> odpf.optimus.VersionRequest 15, // 52: odpf.optimus.RuntimeService.DeployJobSpecification:input_type -> odpf.optimus.DeployJobSpecificationRequest 29, // 53: odpf.optimus.RuntimeService.CreateJobSpecification:input_type -> odpf.optimus.CreateJobSpecificationRequest @@ -4866,32 +4924,34 @@ var file_odpf_optimus_runtime_service_proto_depIdxs = []int32{ 51, // 70: odpf.optimus.RuntimeService.CreateResource:input_type -> odpf.optimus.CreateResourceRequest 53, // 71: odpf.optimus.RuntimeService.ReadResource:input_type -> odpf.optimus.ReadResourceRequest 55, // 72: odpf.optimus.RuntimeService.UpdateResource:input_type -> odpf.optimus.UpdateResourceRequest - 57, // 73: odpf.optimus.RuntimeService.ReplayDryRun:input_type -> odpf.optimus.ReplayDryRunRequest - 14, // 74: odpf.optimus.RuntimeService.Version:output_type -> odpf.optimus.VersionResponse - 16, // 75: odpf.optimus.RuntimeService.DeployJobSpecification:output_type -> odpf.optimus.DeployJobSpecificationResponse - 30, // 76: odpf.optimus.RuntimeService.CreateJobSpecification:output_type -> odpf.optimus.CreateJobSpecificationResponse - 32, // 77: odpf.optimus.RuntimeService.ReadJobSpecification:output_type -> odpf.optimus.ReadJobSpecificationResponse - 34, // 78: odpf.optimus.RuntimeService.DeleteJobSpecification:output_type -> odpf.optimus.DeleteJobSpecificationResponse - 18, // 79: odpf.optimus.RuntimeService.ListJobSpecification:output_type -> odpf.optimus.ListJobSpecificationResponse - 20, // 80: odpf.optimus.RuntimeService.DumpJobSpecification:output_type -> odpf.optimus.DumpJobSpecificationResponse - 22, // 81: odpf.optimus.RuntimeService.CheckJobSpecification:output_type -> odpf.optimus.CheckJobSpecificationResponse - 24, // 82: odpf.optimus.RuntimeService.CheckJobSpecifications:output_type -> odpf.optimus.CheckJobSpecificationsResponse - 26, // 83: odpf.optimus.RuntimeService.RegisterProject:output_type -> odpf.optimus.RegisterProjectResponse - 28, // 84: odpf.optimus.RuntimeService.RegisterProjectNamespace:output_type -> odpf.optimus.RegisterProjectNamespaceResponse - 36, // 85: odpf.optimus.RuntimeService.RegisterSecret:output_type -> odpf.optimus.RegisterSecretResponse - 38, // 86: odpf.optimus.RuntimeService.ListProjects:output_type -> odpf.optimus.ListProjectsResponse - 40, // 87: odpf.optimus.RuntimeService.ListProjectNamespaces:output_type -> odpf.optimus.ListProjectNamespacesResponse - 42, // 88: odpf.optimus.RuntimeService.RegisterInstance:output_type -> odpf.optimus.RegisterInstanceResponse - 44, // 89: odpf.optimus.RuntimeService.JobStatus:output_type -> odpf.optimus.JobStatusResponse - 46, // 90: odpf.optimus.RuntimeService.GetWindow:output_type -> odpf.optimus.GetWindowResponse - 48, // 91: odpf.optimus.RuntimeService.DeployResourceSpecification:output_type -> odpf.optimus.DeployResourceSpecificationResponse - 50, // 92: odpf.optimus.RuntimeService.ListResourceSpecification:output_type -> odpf.optimus.ListResourceSpecificationResponse - 52, // 93: odpf.optimus.RuntimeService.CreateResource:output_type -> odpf.optimus.CreateResourceResponse - 54, // 94: odpf.optimus.RuntimeService.ReadResource:output_type -> odpf.optimus.ReadResourceResponse - 56, // 95: odpf.optimus.RuntimeService.UpdateResource:output_type -> odpf.optimus.UpdateResourceResponse - 58, // 96: odpf.optimus.RuntimeService.ReplayDryRun:output_type -> odpf.optimus.ReplayDryRunResponse - 74, // [74:97] is the sub-list for method output_type - 51, // [51:74] is the sub-list for method input_type + 57, // 73: odpf.optimus.RuntimeService.ReplayDryRun:input_type -> odpf.optimus.ReplayRequest + 57, // 74: odpf.optimus.RuntimeService.Replay:input_type -> odpf.optimus.ReplayRequest + 14, // 75: odpf.optimus.RuntimeService.Version:output_type -> odpf.optimus.VersionResponse + 16, // 76: odpf.optimus.RuntimeService.DeployJobSpecification:output_type -> odpf.optimus.DeployJobSpecificationResponse + 30, // 77: odpf.optimus.RuntimeService.CreateJobSpecification:output_type -> odpf.optimus.CreateJobSpecificationResponse + 32, // 78: odpf.optimus.RuntimeService.ReadJobSpecification:output_type -> odpf.optimus.ReadJobSpecificationResponse + 34, // 79: odpf.optimus.RuntimeService.DeleteJobSpecification:output_type -> odpf.optimus.DeleteJobSpecificationResponse + 18, // 80: odpf.optimus.RuntimeService.ListJobSpecification:output_type -> odpf.optimus.ListJobSpecificationResponse + 20, // 81: odpf.optimus.RuntimeService.DumpJobSpecification:output_type -> odpf.optimus.DumpJobSpecificationResponse + 22, // 82: odpf.optimus.RuntimeService.CheckJobSpecification:output_type -> odpf.optimus.CheckJobSpecificationResponse + 24, // 83: odpf.optimus.RuntimeService.CheckJobSpecifications:output_type -> odpf.optimus.CheckJobSpecificationsResponse + 26, // 84: odpf.optimus.RuntimeService.RegisterProject:output_type -> odpf.optimus.RegisterProjectResponse + 28, // 85: odpf.optimus.RuntimeService.RegisterProjectNamespace:output_type -> odpf.optimus.RegisterProjectNamespaceResponse + 36, // 86: odpf.optimus.RuntimeService.RegisterSecret:output_type -> odpf.optimus.RegisterSecretResponse + 38, // 87: odpf.optimus.RuntimeService.ListProjects:output_type -> odpf.optimus.ListProjectsResponse + 40, // 88: odpf.optimus.RuntimeService.ListProjectNamespaces:output_type -> odpf.optimus.ListProjectNamespacesResponse + 42, // 89: odpf.optimus.RuntimeService.RegisterInstance:output_type -> odpf.optimus.RegisterInstanceResponse + 44, // 90: odpf.optimus.RuntimeService.JobStatus:output_type -> odpf.optimus.JobStatusResponse + 46, // 91: odpf.optimus.RuntimeService.GetWindow:output_type -> odpf.optimus.GetWindowResponse + 48, // 92: odpf.optimus.RuntimeService.DeployResourceSpecification:output_type -> odpf.optimus.DeployResourceSpecificationResponse + 50, // 93: odpf.optimus.RuntimeService.ListResourceSpecification:output_type -> odpf.optimus.ListResourceSpecificationResponse + 52, // 94: odpf.optimus.RuntimeService.CreateResource:output_type -> odpf.optimus.CreateResourceResponse + 54, // 95: odpf.optimus.RuntimeService.ReadResource:output_type -> odpf.optimus.ReadResourceResponse + 56, // 96: odpf.optimus.RuntimeService.UpdateResource:output_type -> odpf.optimus.UpdateResourceResponse + 58, // 97: odpf.optimus.RuntimeService.ReplayDryRun:output_type -> odpf.optimus.ReplayDryRunResponse + 60, // 98: odpf.optimus.RuntimeService.Replay:output_type -> odpf.optimus.ReplayResponse + 75, // [75:99] is the sub-list for method output_type + 51, // [51:75] is the sub-list for method input_type 51, // [51:51] is the sub-list for extension type_name 51, // [51:51] is the sub-list for extension extendee 0, // [0:51] is the sub-list for field type_name @@ -5564,7 +5624,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReplayDryRunRequest); i { + switch v := v.(*ReplayRequest); i { case 0: return &v.state case 1: @@ -5599,7 +5659,19 @@ func file_odpf_optimus_runtime_service_proto_init() { return nil } } - file_odpf_optimus_runtime_service_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + file_odpf_optimus_runtime_service_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReplayResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_odpf_optimus_runtime_service_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ProjectSpecification_ProjectSecret); i { case 0: return &v.state @@ -5611,7 +5683,7 @@ func file_odpf_optimus_runtime_service_proto_init() { return nil } } - file_odpf_optimus_runtime_service_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + file_odpf_optimus_runtime_service_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*JobSpecification_Behavior); i { case 0: return &v.state @@ -5623,7 +5695,7 @@ func file_odpf_optimus_runtime_service_proto_init() { return nil } } - file_odpf_optimus_runtime_service_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + file_odpf_optimus_runtime_service_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*JobSpecification_Behavior_Retry); i { case 0: return &v.state @@ -5642,7 +5714,7 @@ func file_odpf_optimus_runtime_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_odpf_optimus_runtime_service_proto_rawDesc, NumEnums: 2, - NumMessages: 69, + NumMessages: 70, NumExtensions: 0, NumServices: 1, }, diff --git a/api/proto/odpf/optimus/runtime_service.pb.gw.go b/api/proto/odpf/optimus/runtime_service.pb.gw.go index cdd10c8cc7..43391d7374 100644 --- a/api/proto/odpf/optimus/runtime_service.pb.gw.go +++ b/api/proto/odpf/optimus/runtime_service.pb.gw.go @@ -1466,7 +1466,7 @@ var ( ) func request_RuntimeService_ReplayDryRun_0(ctx context.Context, marshaler runtime.Marshaler, client RuntimeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ReplayDryRunRequest + var protoReq ReplayRequest var metadata runtime.ServerMetadata var ( @@ -1509,7 +1509,7 @@ func request_RuntimeService_ReplayDryRun_0(ctx context.Context, marshaler runtim } func local_request_RuntimeService_ReplayDryRun_0(ctx context.Context, marshaler runtime.Marshaler, server RuntimeServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq ReplayDryRunRequest + var protoReq ReplayRequest var metadata runtime.ServerMetadata var ( @@ -1551,6 +1551,96 @@ func local_request_RuntimeService_ReplayDryRun_0(ctx context.Context, marshaler } +var ( + filter_RuntimeService_Replay_0 = &utilities.DoubleArray{Encoding: map[string]int{"project_name": 0, "job_name": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} +) + +func request_RuntimeService_Replay_0(ctx context.Context, marshaler runtime.Marshaler, client RuntimeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ReplayRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["project_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project_name") + } + + protoReq.ProjectName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_name", err) + } + + val, ok = pathParams["job_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "job_name") + } + + protoReq.JobName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "job_name", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RuntimeService_Replay_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Replay(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_RuntimeService_Replay_0(ctx context.Context, marshaler runtime.Marshaler, server RuntimeServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ReplayRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["project_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project_name") + } + + protoReq.ProjectName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_name", err) + } + + val, ok = pathParams["job_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "job_name") + } + + protoReq.JobName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "job_name", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RuntimeService_Replay_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Replay(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterRuntimeServiceHandlerServer registers the http handlers for service RuntimeService to "mux". // UnaryRPC :call RuntimeServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -2017,6 +2107,29 @@ func RegisterRuntimeServiceHandlerServer(ctx context.Context, mux *runtime.Serve }) + mux.Handle("GET", pattern_RuntimeService_Replay_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/odpf.optimus.RuntimeService/Replay") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_RuntimeService_Replay_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_RuntimeService_Replay_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -2458,6 +2571,26 @@ func RegisterRuntimeServiceHandlerClient(ctx context.Context, mux *runtime.Serve }) + mux.Handle("GET", pattern_RuntimeService_Replay_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/odpf.optimus.RuntimeService/Replay") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_RuntimeService_Replay_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_RuntimeService_Replay_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -2501,6 +2634,8 @@ var ( pattern_RuntimeService_UpdateResource_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7}, []string{"api", "v1", "project", "project_name", "namespace", "datastore", "datastore_name", "resource"}, "")) pattern_RuntimeService_ReplayDryRun_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "project", "project_name", "job", "job_name", "replay-dry-run"}, "")) + + pattern_RuntimeService_Replay_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "project", "project_name", "job", "job_name", "replay"}, "")) ) var ( @@ -2543,4 +2678,6 @@ var ( forward_RuntimeService_UpdateResource_0 = runtime.ForwardResponseMessage forward_RuntimeService_ReplayDryRun_0 = runtime.ForwardResponseMessage + + forward_RuntimeService_Replay_0 = runtime.ForwardResponseMessage ) diff --git a/api/proto/odpf/optimus/runtime_service_grpc.pb.go b/api/proto/odpf/optimus/runtime_service_grpc.pb.go index 2ec07ef735..e317129df4 100644 --- a/api/proto/odpf/optimus/runtime_service_grpc.pb.go +++ b/api/proto/odpf/optimus/runtime_service_grpc.pb.go @@ -67,7 +67,8 @@ type RuntimeServiceClient interface { CreateResource(ctx context.Context, in *CreateResourceRequest, opts ...grpc.CallOption) (*CreateResourceResponse, error) ReadResource(ctx context.Context, in *ReadResourceRequest, opts ...grpc.CallOption) (*ReadResourceResponse, error) UpdateResource(ctx context.Context, in *UpdateResourceRequest, opts ...grpc.CallOption) (*UpdateResourceResponse, error) - ReplayDryRun(ctx context.Context, in *ReplayDryRunRequest, opts ...grpc.CallOption) (*ReplayDryRunResponse, error) + ReplayDryRun(ctx context.Context, in *ReplayRequest, opts ...grpc.CallOption) (*ReplayDryRunResponse, error) + Replay(ctx context.Context, in *ReplayRequest, opts ...grpc.CallOption) (*ReplayResponse, error) } type runtimeServiceClient struct { @@ -345,7 +346,7 @@ func (c *runtimeServiceClient) UpdateResource(ctx context.Context, in *UpdateRes return out, nil } -func (c *runtimeServiceClient) ReplayDryRun(ctx context.Context, in *ReplayDryRunRequest, opts ...grpc.CallOption) (*ReplayDryRunResponse, error) { +func (c *runtimeServiceClient) ReplayDryRun(ctx context.Context, in *ReplayRequest, opts ...grpc.CallOption) (*ReplayDryRunResponse, error) { out := new(ReplayDryRunResponse) err := c.cc.Invoke(ctx, "/odpf.optimus.RuntimeService/ReplayDryRun", in, out, opts...) if err != nil { @@ -354,6 +355,15 @@ func (c *runtimeServiceClient) ReplayDryRun(ctx context.Context, in *ReplayDryRu return out, nil } +func (c *runtimeServiceClient) Replay(ctx context.Context, in *ReplayRequest, opts ...grpc.CallOption) (*ReplayResponse, error) { + out := new(ReplayResponse) + err := c.cc.Invoke(ctx, "/odpf.optimus.RuntimeService/Replay", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // RuntimeServiceServer is the server API for RuntimeService service. // All implementations must embed UnimplementedRuntimeServiceServer // for forward compatibility @@ -407,7 +417,8 @@ type RuntimeServiceServer interface { CreateResource(context.Context, *CreateResourceRequest) (*CreateResourceResponse, error) ReadResource(context.Context, *ReadResourceRequest) (*ReadResourceResponse, error) UpdateResource(context.Context, *UpdateResourceRequest) (*UpdateResourceResponse, error) - ReplayDryRun(context.Context, *ReplayDryRunRequest) (*ReplayDryRunResponse, error) + ReplayDryRun(context.Context, *ReplayRequest) (*ReplayDryRunResponse, error) + Replay(context.Context, *ReplayRequest) (*ReplayResponse, error) mustEmbedUnimplementedRuntimeServiceServer() } @@ -481,9 +492,12 @@ func (UnimplementedRuntimeServiceServer) ReadResource(context.Context, *ReadReso func (UnimplementedRuntimeServiceServer) UpdateResource(context.Context, *UpdateResourceRequest) (*UpdateResourceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateResource not implemented") } -func (UnimplementedRuntimeServiceServer) ReplayDryRun(context.Context, *ReplayDryRunRequest) (*ReplayDryRunResponse, error) { +func (UnimplementedRuntimeServiceServer) ReplayDryRun(context.Context, *ReplayRequest) (*ReplayDryRunResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ReplayDryRun not implemented") } +func (UnimplementedRuntimeServiceServer) Replay(context.Context, *ReplayRequest) (*ReplayResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Replay not implemented") +} func (UnimplementedRuntimeServiceServer) mustEmbedUnimplementedRuntimeServiceServer() {} // UnsafeRuntimeServiceServer may be embedded to opt out of forward compatibility for this service. @@ -903,7 +917,7 @@ func _RuntimeService_UpdateResource_Handler(srv interface{}, ctx context.Context } func _RuntimeService_ReplayDryRun_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ReplayDryRunRequest) + in := new(ReplayRequest) if err := dec(in); err != nil { return nil, err } @@ -915,7 +929,25 @@ func _RuntimeService_ReplayDryRun_Handler(srv interface{}, ctx context.Context, FullMethod: "/odpf.optimus.RuntimeService/ReplayDryRun", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(RuntimeServiceServer).ReplayDryRun(ctx, req.(*ReplayDryRunRequest)) + return srv.(RuntimeServiceServer).ReplayDryRun(ctx, req.(*ReplayRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RuntimeService_Replay_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReplayRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RuntimeServiceServer).Replay(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/odpf.optimus.RuntimeService/Replay", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RuntimeServiceServer).Replay(ctx, req.(*ReplayRequest)) } return interceptor(ctx, in, info, handler) } @@ -1007,6 +1039,10 @@ var RuntimeService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ReplayDryRun", Handler: _RuntimeService_ReplayDryRun_Handler, }, + { + MethodName: "Replay", + Handler: _RuntimeService_Replay_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/cmd/replay.go b/cmd/replay.go index fda6433a05..b54d0e2895 100644 --- a/cmd/replay.go +++ b/cmd/replay.go @@ -111,19 +111,32 @@ ReplayDryRun date ranges are inclusive. return nil } - confirm := false - if err := survey.AskOne(&survey.Select{ - Message: "Proceed with replay?", - Options: []string{"Yes", "No"}, - Default: "Yes", - }, &confirm); err != nil { + answers := map[string]interface{}{} + questions := []*survey.Question{ + { + Name: "ProceedReplay", + Prompt: &survey.Select{ + + Message: "Proceed with replay?", + Options: []string{"Yes", "No"}, + Default: "Yes", + }, + }, + } + + if err := survey.Ask(questions, &answers); err != nil { return err } - if !confirm { - l.Print("aborting...") + if option, ok := answers["ProceedReplay"]; ok && option.(survey.OptionAnswer).Value == "No" { + l.Println("aborting...") return nil } + replayId, err := runReplayRequest(l, replayProject, namespace, args[0], args[1], endDate, conf) + if err != nil { + return err + } + l.Printf("🚀 replay request created with id %s\n", replayId) return nil } return reCmd @@ -148,14 +161,14 @@ func printReplayExecutionTree(l logger, projectName, namespace, jobName, startDa l.Println("please wait...") runtime := pb.NewRuntimeServiceClient(conn) // fetch compiled JobSpec by calling the optimus API - replayDryRunRequest := &pb.ReplayDryRunRequest{ + replayRequest := &pb.ReplayRequest{ ProjectName: projectName, JobName: jobName, Namespace: namespace, StartDate: startDate, EndDate: endDate, } - replayDryRunResponse, err := runtime.ReplayDryRun(dumpTimeoutCtx, replayDryRunRequest) + replayDryRunResponse, err := runtime.ReplayDryRun(dumpTimeoutCtx, replayRequest) if err != nil { if errors.Is(err, context.DeadlineExceeded) { l.Println("render process took too long, timing out") @@ -163,12 +176,12 @@ func printReplayExecutionTree(l logger, projectName, namespace, jobName, startDa return errors.Wrapf(err, "request failed for job %s", jobName) } - printReplayDryRunResponse(l, replayDryRunRequest, replayDryRunResponse) + printReplayDryRunResponse(l, replayRequest, replayDryRunResponse) return nil } -func printReplayDryRunResponse(l logger, replayDryRunRequest *pb.ReplayDryRunRequest, replayDryRunResponse *pb.ReplayDryRunResponse) { - l.Printf("For %s project and %s namespace\n\n", coloredNotice(replayDryRunRequest.ProjectName), coloredNotice(replayDryRunRequest.Namespace)) +func printReplayDryRunResponse(l logger, replayRequest *pb.ReplayRequest, replayDryRunResponse *pb.ReplayDryRunResponse) { + l.Printf("For %s project and %s namespace\n\n", coloredNotice(replayRequest.ProjectName), coloredNotice(replayRequest.Namespace)) l.Println(coloredNotice("REPLAY RUNS")) table := tablewriter.NewWriter(l.Writer()) table.SetBorder(false) @@ -202,7 +215,7 @@ func printReplayDryRunResponse(l logger, replayDryRunRequest *pb.ReplayDryRunReq l.Println(fmt.Sprintf("%s", printExecutionTree(replayDryRunResponse.Response, treeprint.New()))) } -// PrintExecutionTree creates a ascii tree to visually inspect +// printExecutionTree creates a ascii tree to visually inspect // instance dependencies that will be recomputed after replay operation func printExecutionTree(instance *pb.ReplayExecutionTreeNode, tree treeprint.Tree) treeprint.Tree { subtree := tree.AddBranch(instance.JobName) @@ -218,3 +231,39 @@ func printExecutionTree(instance *pb.ReplayExecutionTreeNode, tree treeprint.Tre } return tree } + +func runReplayRequest(l logger, projectName, namespace, jobName, startDate, endDate string, conf config.Provider) (string, error) { + dialTimeoutCtx, dialCancel := context.WithTimeout(context.Background(), OptimusDialTimeout) + defer dialCancel() + + conn, err := createConnection(dialTimeoutCtx, conf.GetHost()) + if err != nil { + if errors.Is(err, context.DeadlineExceeded) { + l.Println("can't reach optimus service") + } + return "", err + } + defer conn.Close() + + dumpTimeoutCtx, dumpCancel := context.WithTimeout(context.Background(), renderTimeout) + defer dumpCancel() + + l.Println("firing the replay request...") + runtime := pb.NewRuntimeServiceClient(conn) + // fetch compiled JobSpec by calling the optimus API + replayRequest := &pb.ReplayRequest{ + ProjectName: projectName, + JobName: jobName, + Namespace: namespace, + StartDate: startDate, + EndDate: endDate, + } + replayResponse, err := runtime.Replay(dumpTimeoutCtx, replayRequest) + if err != nil { + if errors.Is(err, context.DeadlineExceeded) { + l.Println("render process took too long, timing out") + } + return "", errors.Wrapf(err, "request failed for job %s", jobName) + } + return replayResponse.Id, nil +} diff --git a/job/replay.go b/job/replay.go index 780ea1e92d..e6e127b247 100644 --- a/job/replay.go +++ b/job/replay.go @@ -15,18 +15,20 @@ const ( ReplayDateFormat = "2006-01-02" ) -func (srv *Service) ReplayDryRun(namespace models.NamespaceSpec, replayJobSpec models.JobSpec, start, end time.Time) (*tree.TreeNode, error) { - projectJobSpecRepo := srv.projectJobSpecRepoFactory.New(namespace.ProjectSpec) - jobSpecs, err := srv.getDependencyResolvedSpecs(namespace.ProjectSpec, projectJobSpecRepo, nil) +func (srv *Service) ReplayDryRun(replayRequest *models.ReplayRequestInput) (*tree.TreeNode, error) { + projectJobSpecRepo := srv.projectJobSpecRepoFactory.New(replayRequest.Project) + jobSpecs, err := srv.getDependencyResolvedSpecs(replayRequest.Project, projectJobSpecRepo, nil) if err != nil { return nil, err } + dagSpecMap := make(map[string]models.JobSpec) for _, currSpec := range jobSpecs { dagSpecMap[currSpec.Name] = currSpec } + replayRequest.DagSpecMap = dagSpecMap - rootInstance, err := PrepareTree(dagSpecMap, replayJobSpec.Name, start, end) + rootInstance, err := prepareTree(replayRequest) if err != nil { return nil, err } @@ -34,23 +36,19 @@ func (srv *Service) ReplayDryRun(namespace models.NamespaceSpec, replayJobSpec m return rootInstance, nil } -func (srv *Service) Replay(namespace models.NamespaceSpec, replayJobSpec models.JobSpec, start, end time.Time) (string, error) { - projectJobSpecRepo := srv.projectJobSpecRepoFactory.New(namespace.ProjectSpec) - jobSpecs, err := srv.getDependencyResolvedSpecs(namespace.ProjectSpec, projectJobSpecRepo, nil) +func (srv *Service) Replay(replayRequest *models.ReplayRequestInput) (string, error) { + projectJobSpecRepo := srv.projectJobSpecRepoFactory.New(replayRequest.Project) + jobSpecs, err := srv.getDependencyResolvedSpecs(replayRequest.Project, projectJobSpecRepo, nil) if err != nil { return "", err } + dagSpecMap := make(map[string]models.JobSpec) for _, currSpec := range jobSpecs { dagSpecMap[currSpec.Name] = currSpec } - replayRequest := models.ReplayRequestInput{ - Job: replayJobSpec, - Start: start, - End: end, - Project: namespace.ProjectSpec, - DagSpecMap: dagSpecMap, - } + replayRequest.DagSpecMap = dagSpecMap + replayUUID, err := srv.replayManager.Replay(replayRequest) if err != nil { return "", err @@ -58,17 +56,17 @@ func (srv *Service) Replay(namespace models.NamespaceSpec, replayJobSpec models. return replayUUID, nil } -// PrepareTree creates a execution tree for replay operation -func PrepareTree(dagSpecMap map[string]models.JobSpec, replayJobName string, start, end time.Time) (*tree.TreeNode, error) { - replayJobSpec, found := dagSpecMap[replayJobName] +// prepareTree creates a execution tree for replay operation +func prepareTree(replayRequest *models.ReplayRequestInput) (*tree.TreeNode, error) { + replayJobSpec, found := replayRequest.DagSpecMap[replayRequest.Job.Name] if !found { - return nil, fmt.Errorf("couldn't find any job with name %s", replayJobName) + return nil, fmt.Errorf("couldn't find any job with name %s", replayRequest.Job.Name) } // compute runs that require replay dagTree := tree.NewMultiRootTree() parentNode := tree.NewTreeNode(replayJobSpec) - if runs, err := getRunsBetweenDates(start, end, replayJobSpec.Schedule.Interval); err == nil { + if runs, err := getRunsBetweenDates(replayRequest.Start, replayRequest.End, replayJobSpec.Schedule.Interval); err == nil { for _, run := range runs { parentNode.Runs.Add(run) } @@ -77,7 +75,7 @@ func PrepareTree(dagSpecMap map[string]models.JobSpec, replayJobName string, sta } dagTree.AddNode(parentNode) - rootInstance, err := populateDownstreamDAGs(dagTree, replayJobSpec, dagSpecMap) + rootInstance, err := populateDownstreamDAGs(dagTree, replayJobSpec, replayRequest.DagSpecMap) if err != nil { return nil, err } diff --git a/job/replay_manager.go b/job/replay_manager.go index 71f1a6a8ee..36f2bbfa25 100644 --- a/job/replay_manager.go +++ b/job/replay_manager.go @@ -19,7 +19,7 @@ var ( type ReplayManager interface { Init() - Replay(models.ReplayRequestInput) (string, error) + Replay(*models.ReplayRequestInput) (string, error) } // Manager for replaying operation(s). @@ -34,7 +34,7 @@ type Manager struct { mu sync.Mutex // request queue, used by workers - requestQ chan models.ReplayRequestInput + requestQ chan *models.ReplayRequestInput // request map, used for verifying if a request is // in queue without actually consuming it requestMap map[uuid.UUID]bool @@ -48,7 +48,7 @@ type Manager struct { // Replay a request asynchronously, returns a replay id that can // can be used to query its status -func (m *Manager) Replay(reqInput models.ReplayRequestInput) (string, error) { +func (m *Manager) Replay(reqInput *models.ReplayRequestInput) (string, error) { uuidOb, err := uuid.NewRandom() if err != nil { return "", err @@ -134,7 +134,7 @@ func NewManager(worker ReplayWorker, size int) *Manager { mgr := &Manager{ replayWorker: worker, requestMap: make(map[uuid.UUID]bool), - requestQ: make(chan models.ReplayRequestInput, size), + requestQ: make(chan *models.ReplayRequestInput, size), clearRequestMapListener: make(chan interface{}), } mgr.Init() diff --git a/job/replay_test.go b/job/replay_test.go index e78054c324..ea192b2426 100644 --- a/job/replay_test.go +++ b/job/replay_test.go @@ -12,7 +12,6 @@ import ( "github.com/hashicorp/go-multierror" "github.com/pkg/errors" - "github.com/google/uuid" "github.com/odpf/optimus/mock" "github.com/odpf/optimus/models" "github.com/stretchr/testify/assert" @@ -92,12 +91,6 @@ func TestReplay(t *testing.T) { Name: "proj", } - namespaceSpec := models.NamespaceSpec{ - ID: uuid.Must(uuid.NewRandom()), - Name: "dev-team-1", - ProjectSpec: projSpec, - } - t.Run("should fail if unable to fetch jobSpecs from project jobSpecRepo", func(t *testing.T) { projectJobSpecRepo := new(mock.ProjectJobSpecRepository) projectJobSpecRepo.On("GetAll").Return(nil, errors.New("error while getting all dags")) @@ -111,7 +104,13 @@ func TestReplay(t *testing.T) { replayEnd, _ := time.Parse(job.ReplayDateFormat, "2020-08-07") jobSvc := job.NewService(nil, nil, nil, dumpAssets, nil, nil, nil, projJobSpecRepoFac, nil) - _, err := jobSvc.ReplayDryRun(namespaceSpec, specs[spec1], replayStart, replayEnd) + replayRequest := &models.ReplayRequestInput{ + Job: specs[spec1], + Start: replayStart, + End: replayEnd, + Project: projSpec, + } + _, err := jobSvc.ReplayDryRun(replayRequest) assert.NotNil(t, err) }) @@ -139,7 +138,13 @@ func TestReplay(t *testing.T) { replayEnd, _ := time.Parse(job.ReplayDateFormat, "2020-08-07") jobSvc := job.NewService(nil, nil, nil, dumpAssets, depenResolver, nil, nil, projJobSpecRepoFac, nil) - _, err := jobSvc.ReplayDryRun(namespaceSpec, specs[spec1], replayStart, replayEnd) + replayRequest := &models.ReplayRequestInput{ + Job: specs[spec1], + Start: replayStart, + End: replayEnd, + Project: projSpec, + } + _, err := jobSvc.ReplayDryRun(replayRequest) assert.NotNil(t, err) merr := err.(*multierror.Error) @@ -176,7 +181,13 @@ func TestReplay(t *testing.T) { replayEnd, _ := time.Parse(job.ReplayDateFormat, "2020-08-07") jobSvc := job.NewService(nil, nil, nil, dumpAssets, depenResolver, nil, nil, projJobSpecRepoFac, nil) - _, err := jobSvc.ReplayDryRun(namespaceSpec, cyclicDagSpec[0], replayStart, replayEnd) + replayRequest := &models.ReplayRequestInput{ + Job: cyclicDagSpec[0], + Start: replayStart, + End: replayEnd, + Project: projSpec, + } + _, err := jobSvc.ReplayDryRun(replayRequest) assert.NotNil(t, err) assert.True(t, strings.Contains(err.Error(), "a cycle dependency encountered in the tree")) @@ -207,8 +218,14 @@ func TestReplay(t *testing.T) { jobSvc := job.NewService(nil, nil, compiler, dumpAssets, depenResolver, nil, nil, projJobSpecRepoFac, nil) replayStart, _ := time.Parse(job.ReplayDateFormat, "2020-08-05") replayEnd, _ := time.Parse(job.ReplayDateFormat, "2020-08-07") + replayRequest := &models.ReplayRequestInput{ + Job: specs[spec1], + Start: replayStart, + End: replayEnd, + Project: projSpec, + } - tree, err := jobSvc.ReplayDryRun(namespaceSpec, specs[spec1], replayStart, replayEnd) + tree, err := jobSvc.ReplayDryRun(replayRequest) assert.Nil(t, err) countMap := make(map[string][]time.Time) @@ -253,8 +270,14 @@ func TestReplay(t *testing.T) { jobSvc := job.NewService(nil, nil, compiler, dumpAssets, depenResolver, nil, nil, projJobSpecRepoFac, nil) replayStart, _ := time.Parse(job.ReplayDateFormat, "2020-08-05") replayEnd, _ := time.Parse(job.ReplayDateFormat, "2020-08-05") + replayRequest := &models.ReplayRequestInput{ + Job: specs[spec4], + Start: replayStart, + End: replayEnd, + Project: projSpec, + } - tree, err := jobSvc.ReplayDryRun(namespaceSpec, specs[spec4], replayStart, replayEnd) + tree, err := jobSvc.ReplayDryRun(replayRequest) assert.Nil(t, err) countMap := make(map[string][]time.Time) diff --git a/job/replay_worker.go b/job/replay_worker.go index d547e1298d..4edad0c14f 100644 --- a/job/replay_worker.go +++ b/job/replay_worker.go @@ -2,6 +2,7 @@ package job import ( "context" + "time" "github.com/odpf/optimus/core/bus" "github.com/odpf/optimus/core/tree" @@ -20,7 +21,7 @@ const ( ) type ReplayWorker interface { - Process(context.Context, models.ReplayRequestInput) error + Process(context.Context, *models.ReplayRequestInput) error } type replayWorker struct { @@ -28,7 +29,7 @@ type replayWorker struct { scheduler models.SchedulerUnit } -func (w *replayWorker) Process(ctx context.Context, input models.ReplayRequestInput) (err error) { +func (w *replayWorker) Process(ctx context.Context, input *models.ReplayRequestInput) (err error) { // save replay request replay := models.ReplaySpec{ ID: input.ID, @@ -36,14 +37,13 @@ func (w *replayWorker) Process(ctx context.Context, input models.ReplayRequestIn StartDate: input.Start, EndDate: input.End, Status: models.ReplayStatusAccepted, - Project: input.Project, } if err = w.replayRepo.Insert(&replay); err != nil { bus.Post(EvtFailedToPrepareForReplay, input.ID) return } - replayTree, err := PrepareTree(input.DagSpecMap, input.Job.Name, input.Start, input.End) + replayTree, err := prepareTree(input) if err != nil { return err } @@ -51,8 +51,11 @@ func (w *replayWorker) Process(ctx context.Context, input models.ReplayRequestIn replayDagsMap := make(map[string]*tree.TreeNode) replayTree.GetAllNodes(replayDagsMap) - for jobName := range replayDagsMap { - if err = w.scheduler.Clear(ctx, input.Project, jobName, input.Start, input.End); err != nil { + for jobName, treeNode := range replayDagsMap { + runTimes := treeNode.Runs.Values() + startTime := runTimes[0].(time.Time) + endTime := runTimes[treeNode.Runs.Size()-1].(time.Time) + if err = w.scheduler.Clear(ctx, input.Project, jobName, startTime, endTime); err != nil { return errors.Wrapf(err, "error while clearing dag runs for job %s", jobName) } } diff --git a/job/replay_worker_test.go b/job/replay_worker_test.go index 1cf63dec9d..5f8aaf5c61 100644 --- a/job/replay_worker_test.go +++ b/job/replay_worker_test.go @@ -17,7 +17,7 @@ func TestReplayWorker(t *testing.T) { startDate, _ := time.Parse(job.ReplayDateFormat, "2020-08-22") endDate, _ := time.Parse(job.ReplayDateFormat, "2020-08-26") currUUID := uuid.Must(uuid.NewRandom()) - replayRequest := models.ReplayRequestInput{ + replayRequest := &models.ReplayRequestInput{ ID: currUUID, Job: models.JobSpec{ Name: "job-name", @@ -34,7 +34,6 @@ func TestReplayWorker(t *testing.T) { StartDate: startDate, EndDate: endDate, Status: models.ReplayStatusAccepted, - Project: replayRequest.Project, Job: replayRequest.Job, } t.Run("Process", func(t *testing.T) { diff --git a/mock/job.go b/mock/job.go index 6e91014448..fdeb364818 100644 --- a/mock/job.go +++ b/mock/job.go @@ -2,7 +2,6 @@ package mock import ( "context" - "time" "github.com/odpf/optimus/core/tree" @@ -195,11 +194,16 @@ func (j *JobService) Delete(ctx context.Context, c models.NamespaceSpec, job mod return args.Error(0) } -func (j *JobService) ReplayDryRun(namespace models.NamespaceSpec, jobSpec models.JobSpec, start time.Time, end time.Time) (*tree.TreeNode, error) { - args := j.Called(namespace, jobSpec, start, end) +func (j *JobService) ReplayDryRun(replayRequest *models.ReplayRequestInput) (*tree.TreeNode, error) { + args := j.Called(replayRequest) return args.Get(0).(*tree.TreeNode), args.Error(1) } +func (j *JobService) Replay(replayRequest *models.ReplayRequestInput) (string, error) { + args := j.Called(replayRequest) + return args.Get(0).(string), args.Error(1) +} + type Compiler struct { mock.Mock } diff --git a/models/job.go b/models/job.go index 21d5fbf82f..fab28c2257 100644 --- a/models/job.go +++ b/models/job.go @@ -293,8 +293,10 @@ type JobService interface { GetByName(string, NamespaceSpec) (JobSpec, error) // Dump returns the compiled Job Dump(NamespaceSpec, JobSpec) (Job, error) - // ReplayDryRun replays the jobSpec and its dependencies between start and endDate - ReplayDryRun(NamespaceSpec, JobSpec, time.Time, time.Time) (*tree.TreeNode, error) + // ReplayDryRun returns the execution tree of jobSpec and its dependencies between start and endDate + ReplayDryRun(*ReplayRequestInput) (*tree.TreeNode, error) + // Replay replays the jobSpec and its dependencies between start and endDate + Replay(*ReplayRequestInput) (string, error) // KeepOnly deletes all jobs except the ones provided for a namespace KeepOnly(NamespaceSpec, []JobSpec, progress.Observer) error // GetAll reads all job specifications of the given namespace diff --git a/models/replay.go b/models/replay.go index 6c1c912dd9..ae523e5a88 100644 --- a/models/replay.go +++ b/models/replay.go @@ -28,7 +28,6 @@ type ReplaySpec struct { Status string Message string CommitID string - Project ProjectSpec } type Syncer interface { diff --git a/resources/pack/migrations/000009_create_replay_table.down.sql b/store/postgres/migrations/000010_create_replay_table.down.sql similarity index 100% rename from resources/pack/migrations/000009_create_replay_table.down.sql rename to store/postgres/migrations/000010_create_replay_table.down.sql diff --git a/resources/pack/migrations/000009_create_replay_table.up.sql b/store/postgres/migrations/000010_create_replay_table.up.sql similarity index 80% rename from resources/pack/migrations/000009_create_replay_table.up.sql rename to store/postgres/migrations/000010_create_replay_table.up.sql index bcb1d9a804..ee5ec8b3e1 100644 --- a/resources/pack/migrations/000009_create_replay_table.up.sql +++ b/store/postgres/migrations/000010_create_replay_table.up.sql @@ -1,10 +1,11 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE IF NOT EXISTS replay ( id UUID PRIMARY KEY NOT NULL, - dag_id TEXT NOT NULL, + job_id UUID NOT NULL, start_date TIMESTAMP WITH TIME ZONE NOT NULL, end_date TIMESTAMP WITH TIME ZONE NOT NULL, - status TEXT NOT NULL, + status varchar(20) NOT NULL, + commit_id varchar(20), message TEXT, created_at TIMESTAMP WITH TIME ZONE NOT NULL, updated_at TIMESTAMP WITH TIME ZONE NOT NULL diff --git a/store/postgres/replay_repository.go b/store/postgres/replay_repository.go index db8c2326ab..c5f930f298 100644 --- a/store/postgres/replay_repository.go +++ b/store/postgres/replay_repository.go @@ -16,12 +16,9 @@ type Replay struct { JobID uuid.UUID `gorm:"not null"` Job Job `gorm:"foreignKey:JobID"` - ProjectID uuid.UUID `gorm:"not null"` - Project Project `gorm:"foreignKey:ProjectID"` - - StartDate time.Time - EndDate time.Time - Status string + StartDate time.Time `gorm:"not null"` + EndDate time.Time `gorm:"not null"` + Status string `gorm:"not null"` Message string CommitID string @@ -33,7 +30,6 @@ func (p Replay) FromSpec(spec *models.ReplaySpec) (Replay, error) { return Replay{ ID: spec.ID, JobID: spec.Job.ID, - ProjectID: spec.Project.ID, StartDate: spec.StartDate, EndDate: spec.EndDate, Status: spec.Status, diff --git a/store/postgres/replay_repository_test.go b/store/postgres/replay_repository_test.go index 5be85f62ac..32cf307d6c 100644 --- a/store/postgres/replay_repository_test.go +++ b/store/postgres/replay_repository_test.go @@ -41,9 +41,6 @@ func TestReplayRepository(t *testing.T) { jobSpec := models.JobSpec{ Name: "job-name", } - projectSpec := models.ProjectSpec{ - Name: "project-name", - } startTime, _ := time.Parse(job.ReplayDateFormat, "2020-01-15") endTime, _ := time.Parse(job.ReplayDateFormat, "2020-01-20") @@ -55,7 +52,6 @@ func TestReplayRepository(t *testing.T) { StartDate: startTime, EndDate: endTime, Status: models.ReplayStatusAccepted, - Project: projectSpec, }, } diff --git a/third_party/OpenAPI/odpf/optimus/runtime_service.swagger.json b/third_party/OpenAPI/odpf/optimus/runtime_service.swagger.json index 7b630cfd65..27d277f2da 100644 --- a/third_party/OpenAPI/odpf/optimus/runtime_service.swagger.json +++ b/third_party/OpenAPI/odpf/optimus/runtime_service.swagger.json @@ -229,6 +229,60 @@ ] } }, + "/api/v1/project/{projectName}/job/{jobName}/replay": { + "get": { + "operationId": "RuntimeService_Replay", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/optimusReplayResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "projectName", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "jobName", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "namespace", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "startDate", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "endDate", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "RuntimeService" + ] + } + }, "/api/v1/project/{projectName}/job/{jobName}/replay-dry-run": { "get": { "operationId": "RuntimeService_ReplayDryRun", @@ -1476,6 +1530,14 @@ } } }, + "optimusReplayResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, "optimusResourceSpecification": { "type": "object", "properties": {