From 04cd64e76ced86b176fbfe8e2fc6d895542d32cf Mon Sep 17 00:00:00 2001 From: Damian Coln Date: Tue, 16 Jun 2026 23:50:45 -0700 Subject: [PATCH 01/15] saas-dr: phase 3 detection packs scaffolding Introduces a versioned detection-pack model that groups built-in rules into curated bundles per provider, so operators can reason about Aperio's SaaS detection coverage in coherent chunks instead of a flat toggle list. - New DetectionPack type and registry in internal/ingestionworker with 6 initial packs across GitHub, Slack, Okta, and Google Workspace (identity, mail, drive). - RuleCatalogEntry extended with PackID, MitreTechniques, Intent, and Tags. All 16 existing rules backfilled with MITRE ATT&CK mappings, attacker-intent statements, and canonical cross-provider tags. - New ListDetectionPacks Connect RPC with provider filter, Go handler in internal/bootstrap, TypeScript client wrapper, and fetchDetectionPacks on apps/web/lib/api.ts. - Tests pin pack-registry shape (semver, unique ids, known providers), catalog-to-pack linkage, MITRE id shape, canonical-tag membership, rules-in-pack ordering, and proto hydration. New evaluators (github.branch_protection_disabled, slack.external_user_added_to_private_channel, google_workspace.mass_drive_download) are tracked separately in #157 and will ship with their TS-parity fixtures. Phase 2 nice-to-haves moved to follow-ups: #151 (link/unlink findings), #152 (UpdateSaasIncident), #153 (note timeline events), #154 (CancelSaasResponseAction), #155 (SLA breach reactor), #156 (dashboard incidents widget). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- apps/web/lib/api.ts | 26 + gen/aperio/v1/aperiov1connect/api.connect.go | 29 + gen/aperio/v1/api.pb.go | 711 +++++++++++++----- internal/bootstrap/detection_packs.go | 61 ++ internal/bootstrap/detection_packs_test.go | 54 ++ internal/ingestionworker/detection_packs.go | 92 +++ .../ingestionworker/detection_packs_test.go | 135 ++++ internal/ingestionworker/rules_catalog.go | 338 +++++---- packages/connect/src/client.ts | 58 ++ packages/connect/src/gen/aperio/v1/api_pb.ts | 158 +++- proto/aperio/v1/api.proto | 30 + tests/fe-contracts.test.ts | 4 +- 12 files changed, 1349 insertions(+), 347 deletions(-) create mode 100644 internal/bootstrap/detection_packs.go create mode 100644 internal/bootstrap/detection_packs_test.go create mode 100644 internal/ingestionworker/detection_packs.go create mode 100644 internal/ingestionworker/detection_packs_test.go diff --git a/apps/web/lib/api.ts b/apps/web/lib/api.ts index 2767d9d0..9c26013c 100644 --- a/apps/web/lib/api.ts +++ b/apps/web/lib/api.ts @@ -165,6 +165,26 @@ export type ConnectorDefinition = { fields: ConnectorField[]; }; +export type DetectionPackRule = { + id: string; + title: string; + description: string; + severity: string; + eventTypes: string[]; + mitreTechniques: string[]; + intent: string; + tags: string[]; +}; + +export type DetectionPack = { + id: string; + provider: string; + name: string; + description: string; + version: string; + rules: DetectionPackRule[]; +}; + export type IntegrationConnection = { id: string; provider: Provider; @@ -493,6 +513,12 @@ export async function fetchConnectorCatalog() { }>; } +export async function fetchDetectionPacks(filters?: { provider?: string }) { + return aperioConnectClient.listDetectionPacks(filters) as Promise<{ + data: DetectionPack[]; + }>; +} + export async function fetchIntegrations() { return aperioConnectClient.listIntegrations() as Promise<{ data: IntegrationConnection[]; diff --git a/gen/aperio/v1/aperiov1connect/api.connect.go b/gen/aperio/v1/aperiov1connect/api.connect.go index a5b2c5f0..fef896df 100644 --- a/gen/aperio/v1/aperiov1connect/api.connect.go +++ b/gen/aperio/v1/aperiov1connect/api.connect.go @@ -107,6 +107,9 @@ const ( // AperioServiceExecuteSaasResponseActionProcedure is the fully-qualified name of the // AperioService's ExecuteSaasResponseAction RPC. AperioServiceExecuteSaasResponseActionProcedure = "/aperio.v1.AperioService/ExecuteSaasResponseAction" + // AperioServiceListDetectionPacksProcedure is the fully-qualified name of the AperioService's + // ListDetectionPacks RPC. + AperioServiceListDetectionPacksProcedure = "/aperio.v1.AperioService/ListDetectionPacks" // AperioServiceListConnectorCatalogProcedure is the fully-qualified name of the AperioService's // ListConnectorCatalog RPC. AperioServiceListConnectorCatalogProcedure = "/aperio.v1.AperioService/ListConnectorCatalog" @@ -290,6 +293,7 @@ type AperioServiceClient interface { ProposeSaasResponseAction(context.Context, *connect.Request[v1.ProposeSaasResponseActionRequest]) (*connect.Response[v1.ProposeSaasResponseActionResponse], error) ApproveSaasResponseAction(context.Context, *connect.Request[v1.ApproveSaasResponseActionRequest]) (*connect.Response[v1.ApproveSaasResponseActionResponse], error) ExecuteSaasResponseAction(context.Context, *connect.Request[v1.ExecuteSaasResponseActionRequest]) (*connect.Response[v1.ExecuteSaasResponseActionResponse], error) + ListDetectionPacks(context.Context, *connect.Request[v1.ListDetectionPacksRequest]) (*connect.Response[v1.ListDetectionPacksResponse], error) ListConnectorCatalog(context.Context, *connect.Request[v1.ListConnectorCatalogRequest]) (*connect.Response[v1.ListConnectorCatalogResponse], error) ListIntegrations(context.Context, *connect.Request[v1.ListIntegrationsRequest]) (*connect.Response[v1.ListIntegrationsResponse], error) CreateIntegration(context.Context, *connect.Request[v1.CreateIntegrationRequest]) (*connect.Response[v1.CreateIntegrationResponse], error) @@ -510,6 +514,12 @@ func NewAperioServiceClient(httpClient connect.HTTPClient, baseURL string, opts connect.WithSchema(aperioServiceMethods.ByName("ExecuteSaasResponseAction")), connect.WithClientOptions(opts...), ), + listDetectionPacks: connect.NewClient[v1.ListDetectionPacksRequest, v1.ListDetectionPacksResponse]( + httpClient, + baseURL+AperioServiceListDetectionPacksProcedure, + connect.WithSchema(aperioServiceMethods.ByName("ListDetectionPacks")), + connect.WithClientOptions(opts...), + ), listConnectorCatalog: connect.NewClient[v1.ListConnectorCatalogRequest, v1.ListConnectorCatalogResponse]( httpClient, baseURL+AperioServiceListConnectorCatalogProcedure, @@ -847,6 +857,7 @@ type aperioServiceClient struct { proposeSaasResponseAction *connect.Client[v1.ProposeSaasResponseActionRequest, v1.ProposeSaasResponseActionResponse] approveSaasResponseAction *connect.Client[v1.ApproveSaasResponseActionRequest, v1.ApproveSaasResponseActionResponse] executeSaasResponseAction *connect.Client[v1.ExecuteSaasResponseActionRequest, v1.ExecuteSaasResponseActionResponse] + listDetectionPacks *connect.Client[v1.ListDetectionPacksRequest, v1.ListDetectionPacksResponse] listConnectorCatalog *connect.Client[v1.ListConnectorCatalogRequest, v1.ListConnectorCatalogResponse] listIntegrations *connect.Client[v1.ListIntegrationsRequest, v1.ListIntegrationsResponse] createIntegration *connect.Client[v1.CreateIntegrationRequest, v1.CreateIntegrationResponse] @@ -1030,6 +1041,11 @@ func (c *aperioServiceClient) ExecuteSaasResponseAction(ctx context.Context, req return c.executeSaasResponseAction.CallUnary(ctx, req) } +// ListDetectionPacks calls aperio.v1.AperioService.ListDetectionPacks. +func (c *aperioServiceClient) ListDetectionPacks(ctx context.Context, req *connect.Request[v1.ListDetectionPacksRequest]) (*connect.Response[v1.ListDetectionPacksResponse], error) { + return c.listDetectionPacks.CallUnary(ctx, req) +} + // ListConnectorCatalog calls aperio.v1.AperioService.ListConnectorCatalog. func (c *aperioServiceClient) ListConnectorCatalog(ctx context.Context, req *connect.Request[v1.ListConnectorCatalogRequest]) (*connect.Response[v1.ListConnectorCatalogResponse], error) { return c.listConnectorCatalog.CallUnary(ctx, req) @@ -1315,6 +1331,7 @@ type AperioServiceHandler interface { ProposeSaasResponseAction(context.Context, *connect.Request[v1.ProposeSaasResponseActionRequest]) (*connect.Response[v1.ProposeSaasResponseActionResponse], error) ApproveSaasResponseAction(context.Context, *connect.Request[v1.ApproveSaasResponseActionRequest]) (*connect.Response[v1.ApproveSaasResponseActionResponse], error) ExecuteSaasResponseAction(context.Context, *connect.Request[v1.ExecuteSaasResponseActionRequest]) (*connect.Response[v1.ExecuteSaasResponseActionResponse], error) + ListDetectionPacks(context.Context, *connect.Request[v1.ListDetectionPacksRequest]) (*connect.Response[v1.ListDetectionPacksResponse], error) ListConnectorCatalog(context.Context, *connect.Request[v1.ListConnectorCatalogRequest]) (*connect.Response[v1.ListConnectorCatalogResponse], error) ListIntegrations(context.Context, *connect.Request[v1.ListIntegrationsRequest]) (*connect.Response[v1.ListIntegrationsResponse], error) CreateIntegration(context.Context, *connect.Request[v1.CreateIntegrationRequest]) (*connect.Response[v1.CreateIntegrationResponse], error) @@ -1531,6 +1548,12 @@ func NewAperioServiceHandler(svc AperioServiceHandler, opts ...connect.HandlerOp connect.WithSchema(aperioServiceMethods.ByName("ExecuteSaasResponseAction")), connect.WithHandlerOptions(opts...), ) + aperioServiceListDetectionPacksHandler := connect.NewUnaryHandler( + AperioServiceListDetectionPacksProcedure, + svc.ListDetectionPacks, + connect.WithSchema(aperioServiceMethods.ByName("ListDetectionPacks")), + connect.WithHandlerOptions(opts...), + ) aperioServiceListConnectorCatalogHandler := connect.NewUnaryHandler( AperioServiceListConnectorCatalogProcedure, svc.ListConnectorCatalog, @@ -1891,6 +1914,8 @@ func NewAperioServiceHandler(svc AperioServiceHandler, opts ...connect.HandlerOp aperioServiceApproveSaasResponseActionHandler.ServeHTTP(w, r) case AperioServiceExecuteSaasResponseActionProcedure: aperioServiceExecuteSaasResponseActionHandler.ServeHTTP(w, r) + case AperioServiceListDetectionPacksProcedure: + aperioServiceListDetectionPacksHandler.ServeHTTP(w, r) case AperioServiceListConnectorCatalogProcedure: aperioServiceListConnectorCatalogHandler.ServeHTTP(w, r) case AperioServiceListIntegrationsProcedure: @@ -2106,6 +2131,10 @@ func (UnimplementedAperioServiceHandler) ExecuteSaasResponseAction(context.Conte return nil, connect.NewError(connect.CodeUnimplemented, errors.New("aperio.v1.AperioService.ExecuteSaasResponseAction is not implemented")) } +func (UnimplementedAperioServiceHandler) ListDetectionPacks(context.Context, *connect.Request[v1.ListDetectionPacksRequest]) (*connect.Response[v1.ListDetectionPacksResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("aperio.v1.AperioService.ListDetectionPacks is not implemented")) +} + func (UnimplementedAperioServiceHandler) ListConnectorCatalog(context.Context, *connect.Request[v1.ListConnectorCatalogRequest]) (*connect.Response[v1.ListConnectorCatalogResponse], error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("aperio.v1.AperioService.ListConnectorCatalog is not implemented")) } diff --git a/gen/aperio/v1/api.pb.go b/gen/aperio/v1/api.pb.go index 6c9b1f4a..c3fb7787 100644 --- a/gen/aperio/v1/api.pb.go +++ b/gen/aperio/v1/api.pb.go @@ -14855,6 +14855,279 @@ func (x *ConnectorBuiltInRule) GetEnabled() bool { return false } +type ListDetectionPacksRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional provider filter (e.g. "GOOGLE_WORKSPACE"). Empty returns every pack. + Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListDetectionPacksRequest) Reset() { + *x = ListDetectionPacksRequest{} + mi := &file_aperio_v1_api_proto_msgTypes[224] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListDetectionPacksRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListDetectionPacksRequest) ProtoMessage() {} + +func (x *ListDetectionPacksRequest) ProtoReflect() protoreflect.Message { + mi := &file_aperio_v1_api_proto_msgTypes[224] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListDetectionPacksRequest.ProtoReflect.Descriptor instead. +func (*ListDetectionPacksRequest) Descriptor() ([]byte, []int) { + return file_aperio_v1_api_proto_rawDescGZIP(), []int{224} +} + +func (x *ListDetectionPacksRequest) GetProvider() string { + if x != nil { + return x.Provider + } + return "" +} + +type ListDetectionPacksResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []*DetectionPack `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListDetectionPacksResponse) Reset() { + *x = ListDetectionPacksResponse{} + mi := &file_aperio_v1_api_proto_msgTypes[225] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListDetectionPacksResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListDetectionPacksResponse) ProtoMessage() {} + +func (x *ListDetectionPacksResponse) ProtoReflect() protoreflect.Message { + mi := &file_aperio_v1_api_proto_msgTypes[225] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListDetectionPacksResponse.ProtoReflect.Descriptor instead. +func (*ListDetectionPacksResponse) Descriptor() ([]byte, []int) { + return file_aperio_v1_api_proto_rawDescGZIP(), []int{225} +} + +func (x *ListDetectionPacksResponse) GetData() []*DetectionPack { + if x != nil { + return x.Data + } + return nil +} + +type DetectionPack struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + Version string `protobuf:"bytes,5,opt,name=version,proto3" json:"version,omitempty"` + Rules []*DetectionPackRule `protobuf:"bytes,6,rep,name=rules,proto3" json:"rules,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DetectionPack) Reset() { + *x = DetectionPack{} + mi := &file_aperio_v1_api_proto_msgTypes[226] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DetectionPack) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DetectionPack) ProtoMessage() {} + +func (x *DetectionPack) ProtoReflect() protoreflect.Message { + mi := &file_aperio_v1_api_proto_msgTypes[226] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DetectionPack.ProtoReflect.Descriptor instead. +func (*DetectionPack) Descriptor() ([]byte, []int) { + return file_aperio_v1_api_proto_rawDescGZIP(), []int{226} +} + +func (x *DetectionPack) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *DetectionPack) GetProvider() string { + if x != nil { + return x.Provider + } + return "" +} + +func (x *DetectionPack) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DetectionPack) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *DetectionPack) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *DetectionPack) GetRules() []*DetectionPackRule { + if x != nil { + return x.Rules + } + return nil +} + +type DetectionPackRule struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Severity string `protobuf:"bytes,4,opt,name=severity,proto3" json:"severity,omitempty"` + EventTypes []string `protobuf:"bytes,5,rep,name=event_types,json=eventTypes,proto3" json:"event_types,omitempty"` + MitreTechniques []string `protobuf:"bytes,6,rep,name=mitre_techniques,json=mitreTechniques,proto3" json:"mitre_techniques,omitempty"` + Intent string `protobuf:"bytes,7,opt,name=intent,proto3" json:"intent,omitempty"` + Tags []string `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DetectionPackRule) Reset() { + *x = DetectionPackRule{} + mi := &file_aperio_v1_api_proto_msgTypes[227] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DetectionPackRule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DetectionPackRule) ProtoMessage() {} + +func (x *DetectionPackRule) ProtoReflect() protoreflect.Message { + mi := &file_aperio_v1_api_proto_msgTypes[227] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DetectionPackRule.ProtoReflect.Descriptor instead. +func (*DetectionPackRule) Descriptor() ([]byte, []int) { + return file_aperio_v1_api_proto_rawDescGZIP(), []int{227} +} + +func (x *DetectionPackRule) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *DetectionPackRule) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *DetectionPackRule) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *DetectionPackRule) GetSeverity() string { + if x != nil { + return x.Severity + } + return "" +} + +func (x *DetectionPackRule) GetEventTypes() []string { + if x != nil { + return x.EventTypes + } + return nil +} + +func (x *DetectionPackRule) GetMitreTechniques() []string { + if x != nil { + return x.MitreTechniques + } + return nil +} + +func (x *DetectionPackRule) GetIntent() string { + if x != nil { + return x.Intent + } + return "" +} + +func (x *DetectionPackRule) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + type ConnectorCustomRule struct { state protoimpl.MessageState `protogen:"open.v1"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` @@ -14871,7 +15144,7 @@ type ConnectorCustomRule struct { func (x *ConnectorCustomRule) Reset() { *x = ConnectorCustomRule{} - mi := &file_aperio_v1_api_proto_msgTypes[224] + mi := &file_aperio_v1_api_proto_msgTypes[228] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14883,7 +15156,7 @@ func (x *ConnectorCustomRule) String() string { func (*ConnectorCustomRule) ProtoMessage() {} func (x *ConnectorCustomRule) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[224] + mi := &file_aperio_v1_api_proto_msgTypes[228] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14896,7 +15169,7 @@ func (x *ConnectorCustomRule) ProtoReflect() protoreflect.Message { // Deprecated: Use ConnectorCustomRule.ProtoReflect.Descriptor instead. func (*ConnectorCustomRule) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{224} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{228} } func (x *ConnectorCustomRule) GetId() string { @@ -14964,7 +15237,7 @@ type ListConnectorRulesRequest struct { func (x *ListConnectorRulesRequest) Reset() { *x = ListConnectorRulesRequest{} - mi := &file_aperio_v1_api_proto_msgTypes[225] + mi := &file_aperio_v1_api_proto_msgTypes[229] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -14976,7 +15249,7 @@ func (x *ListConnectorRulesRequest) String() string { func (*ListConnectorRulesRequest) ProtoMessage() {} func (x *ListConnectorRulesRequest) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[225] + mi := &file_aperio_v1_api_proto_msgTypes[229] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -14989,7 +15262,7 @@ func (x *ListConnectorRulesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListConnectorRulesRequest.ProtoReflect.Descriptor instead. func (*ListConnectorRulesRequest) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{225} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{229} } func (x *ListConnectorRulesRequest) GetIntegrationId() string { @@ -15011,7 +15284,7 @@ type ListConnectorRulesResponse struct { func (x *ListConnectorRulesResponse) Reset() { *x = ListConnectorRulesResponse{} - mi := &file_aperio_v1_api_proto_msgTypes[226] + mi := &file_aperio_v1_api_proto_msgTypes[230] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15023,7 +15296,7 @@ func (x *ListConnectorRulesResponse) String() string { func (*ListConnectorRulesResponse) ProtoMessage() {} func (x *ListConnectorRulesResponse) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[226] + mi := &file_aperio_v1_api_proto_msgTypes[230] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15036,7 +15309,7 @@ func (x *ListConnectorRulesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListConnectorRulesResponse.ProtoReflect.Descriptor instead. func (*ListConnectorRulesResponse) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{226} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{230} } func (x *ListConnectorRulesResponse) GetIntegrationId() string { @@ -15082,7 +15355,7 @@ type CreateCustomRuleRequest struct { func (x *CreateCustomRuleRequest) Reset() { *x = CreateCustomRuleRequest{} - mi := &file_aperio_v1_api_proto_msgTypes[227] + mi := &file_aperio_v1_api_proto_msgTypes[231] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15094,7 +15367,7 @@ func (x *CreateCustomRuleRequest) String() string { func (*CreateCustomRuleRequest) ProtoMessage() {} func (x *CreateCustomRuleRequest) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[227] + mi := &file_aperio_v1_api_proto_msgTypes[231] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15107,7 +15380,7 @@ func (x *CreateCustomRuleRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateCustomRuleRequest.ProtoReflect.Descriptor instead. func (*CreateCustomRuleRequest) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{227} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{231} } func (x *CreateCustomRuleRequest) GetIntegrationId() string { @@ -15168,7 +15441,7 @@ type CreateCustomRuleResponse struct { func (x *CreateCustomRuleResponse) Reset() { *x = CreateCustomRuleResponse{} - mi := &file_aperio_v1_api_proto_msgTypes[228] + mi := &file_aperio_v1_api_proto_msgTypes[232] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15180,7 +15453,7 @@ func (x *CreateCustomRuleResponse) String() string { func (*CreateCustomRuleResponse) ProtoMessage() {} func (x *CreateCustomRuleResponse) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[228] + mi := &file_aperio_v1_api_proto_msgTypes[232] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15193,7 +15466,7 @@ func (x *CreateCustomRuleResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateCustomRuleResponse.ProtoReflect.Descriptor instead. func (*CreateCustomRuleResponse) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{228} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{232} } func (x *CreateCustomRuleResponse) GetId() string { @@ -15219,7 +15492,7 @@ type UpdateCustomRuleRequest struct { func (x *UpdateCustomRuleRequest) Reset() { *x = UpdateCustomRuleRequest{} - mi := &file_aperio_v1_api_proto_msgTypes[229] + mi := &file_aperio_v1_api_proto_msgTypes[233] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15231,7 +15504,7 @@ func (x *UpdateCustomRuleRequest) String() string { func (*UpdateCustomRuleRequest) ProtoMessage() {} func (x *UpdateCustomRuleRequest) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[229] + mi := &file_aperio_v1_api_proto_msgTypes[233] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15244,7 +15517,7 @@ func (x *UpdateCustomRuleRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateCustomRuleRequest.ProtoReflect.Descriptor instead. func (*UpdateCustomRuleRequest) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{229} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{233} } func (x *UpdateCustomRuleRequest) GetIntegrationId() string { @@ -15312,7 +15585,7 @@ type UpdateCustomRuleResponse struct { func (x *UpdateCustomRuleResponse) Reset() { *x = UpdateCustomRuleResponse{} - mi := &file_aperio_v1_api_proto_msgTypes[230] + mi := &file_aperio_v1_api_proto_msgTypes[234] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15324,7 +15597,7 @@ func (x *UpdateCustomRuleResponse) String() string { func (*UpdateCustomRuleResponse) ProtoMessage() {} func (x *UpdateCustomRuleResponse) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[230] + mi := &file_aperio_v1_api_proto_msgTypes[234] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15337,7 +15610,7 @@ func (x *UpdateCustomRuleResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateCustomRuleResponse.ProtoReflect.Descriptor instead. func (*UpdateCustomRuleResponse) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{230} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{234} } func (x *UpdateCustomRuleResponse) GetId() string { @@ -15357,7 +15630,7 @@ type DeleteCustomRuleRequest struct { func (x *DeleteCustomRuleRequest) Reset() { *x = DeleteCustomRuleRequest{} - mi := &file_aperio_v1_api_proto_msgTypes[231] + mi := &file_aperio_v1_api_proto_msgTypes[235] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15369,7 +15642,7 @@ func (x *DeleteCustomRuleRequest) String() string { func (*DeleteCustomRuleRequest) ProtoMessage() {} func (x *DeleteCustomRuleRequest) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[231] + mi := &file_aperio_v1_api_proto_msgTypes[235] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15382,7 +15655,7 @@ func (x *DeleteCustomRuleRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteCustomRuleRequest.ProtoReflect.Descriptor instead. func (*DeleteCustomRuleRequest) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{231} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{235} } func (x *DeleteCustomRuleRequest) GetIntegrationId() string { @@ -15408,7 +15681,7 @@ type DeleteCustomRuleResponse struct { func (x *DeleteCustomRuleResponse) Reset() { *x = DeleteCustomRuleResponse{} - mi := &file_aperio_v1_api_proto_msgTypes[232] + mi := &file_aperio_v1_api_proto_msgTypes[236] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -15420,7 +15693,7 @@ func (x *DeleteCustomRuleResponse) String() string { func (*DeleteCustomRuleResponse) ProtoMessage() {} func (x *DeleteCustomRuleResponse) ProtoReflect() protoreflect.Message { - mi := &file_aperio_v1_api_proto_msgTypes[232] + mi := &file_aperio_v1_api_proto_msgTypes[236] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -15433,7 +15706,7 @@ func (x *DeleteCustomRuleResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteCustomRuleResponse.ProtoReflect.Descriptor instead. func (*DeleteCustomRuleResponse) Descriptor() ([]byte, []int) { - return file_aperio_v1_api_proto_rawDescGZIP(), []int{232} + return file_aperio_v1_api_proto_rawDescGZIP(), []int{236} } func (x *DeleteCustomRuleResponse) GetId() string { @@ -16717,7 +16990,28 @@ const file_aperio_v1_api_proto_rawDesc = "" + "\bseverity\x18\x05 \x01(\tR\bseverity\x12\x1f\n" + "\vevent_types\x18\x06 \x03(\tR\n" + "eventTypes\x12\x18\n" + - "\aenabled\x18\a \x01(\bR\aenabled\"\xf9\x01\n" + + "\aenabled\x18\a \x01(\bR\aenabled\"7\n" + + "\x19ListDetectionPacksRequest\x12\x1a\n" + + "\bprovider\x18\x01 \x01(\tR\bprovider\"J\n" + + "\x1aListDetectionPacksResponse\x12,\n" + + "\x04data\x18\x01 \x03(\v2\x18.aperio.v1.DetectionPackR\x04data\"\xbf\x01\n" + + "\rDetectionPack\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1a\n" + + "\bprovider\x18\x02 \x01(\tR\bprovider\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\x12 \n" + + "\vdescription\x18\x04 \x01(\tR\vdescription\x12\x18\n" + + "\aversion\x18\x05 \x01(\tR\aversion\x122\n" + + "\x05rules\x18\x06 \x03(\v2\x1c.aperio.v1.DetectionPackRuleR\x05rules\"\xef\x01\n" + + "\x11DetectionPackRule\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x14\n" + + "\x05title\x18\x02 \x01(\tR\x05title\x12 \n" + + "\vdescription\x18\x03 \x01(\tR\vdescription\x12\x1a\n" + + "\bseverity\x18\x04 \x01(\tR\bseverity\x12\x1f\n" + + "\vevent_types\x18\x05 \x03(\tR\n" + + "eventTypes\x12)\n" + + "\x10mitre_techniques\x18\x06 \x03(\tR\x0fmitreTechniques\x12\x16\n" + + "\x06intent\x18\a \x01(\tR\x06intent\x12\x12\n" + + "\x04tags\x18\b \x03(\tR\x04tags\"\xf9\x01\n" + "\x13ConnectorCustomRule\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1a\n" + @@ -16763,7 +17057,7 @@ const file_aperio_v1_api_proto_rawDesc = "" + "\x0eintegration_id\x18\x01 \x01(\tR\rintegrationId\x12\x17\n" + "\arule_id\x18\x02 \x01(\tR\x06ruleId\"*\n" + "\x18DeleteCustomRuleResponse\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id2\xe8=\n" + + "\x02id\x18\x01 \x01(\tR\x02id2\xcb>\n" + "\rAperioService\x12@\n" + "\aCallApi\x12\x19.aperio.v1.CallApiRequest\x1a\x1a.aperio.v1.CallApiResponse\x12=\n" + "\x06Signup\x12\x18.aperio.v1.SignupRequest\x1a\x19.aperio.v1.SignupResponse\x12:\n" + @@ -16792,7 +17086,8 @@ const file_aperio_v1_api_proto_rawDesc = "" + "\x18UpdateSaasIncidentStatus\x12*.aperio.v1.UpdateSaasIncidentStatusRequest\x1a+.aperio.v1.UpdateSaasIncidentStatusResponse\x12v\n" + "\x19ProposeSaasResponseAction\x12+.aperio.v1.ProposeSaasResponseActionRequest\x1a,.aperio.v1.ProposeSaasResponseActionResponse\x12v\n" + "\x19ApproveSaasResponseAction\x12+.aperio.v1.ApproveSaasResponseActionRequest\x1a,.aperio.v1.ApproveSaasResponseActionResponse\x12v\n" + - "\x19ExecuteSaasResponseAction\x12+.aperio.v1.ExecuteSaasResponseActionRequest\x1a,.aperio.v1.ExecuteSaasResponseActionResponse\x12g\n" + + "\x19ExecuteSaasResponseAction\x12+.aperio.v1.ExecuteSaasResponseActionRequest\x1a,.aperio.v1.ExecuteSaasResponseActionResponse\x12a\n" + + "\x12ListDetectionPacks\x12$.aperio.v1.ListDetectionPacksRequest\x1a%.aperio.v1.ListDetectionPacksResponse\x12g\n" + "\x14ListConnectorCatalog\x12&.aperio.v1.ListConnectorCatalogRequest\x1a'.aperio.v1.ListConnectorCatalogResponse\x12[\n" + "\x10ListIntegrations\x12\".aperio.v1.ListIntegrationsRequest\x1a#.aperio.v1.ListIntegrationsResponse\x12^\n" + "\x11CreateIntegration\x12#.aperio.v1.CreateIntegrationRequest\x1a$.aperio.v1.CreateIntegrationResponse\x12^\n" + @@ -16857,7 +17152,7 @@ func file_aperio_v1_api_proto_rawDescGZIP() []byte { return file_aperio_v1_api_proto_rawDescData } -var file_aperio_v1_api_proto_msgTypes = make([]protoimpl.MessageInfo, 233) +var file_aperio_v1_api_proto_msgTypes = make([]protoimpl.MessageInfo, 237) var file_aperio_v1_api_proto_goTypes = []any{ (*CallApiRequest)(nil), // 0: aperio.v1.CallApiRequest (*CallApiResponse)(nil), // 1: aperio.v1.CallApiResponse @@ -17083,16 +17378,20 @@ var file_aperio_v1_api_proto_goTypes = []any{ (*DeleteExecutiveReportRequest)(nil), // 221: aperio.v1.DeleteExecutiveReportRequest (*DeleteExecutiveReportResponse)(nil), // 222: aperio.v1.DeleteExecutiveReportResponse (*ConnectorBuiltInRule)(nil), // 223: aperio.v1.ConnectorBuiltInRule - (*ConnectorCustomRule)(nil), // 224: aperio.v1.ConnectorCustomRule - (*ListConnectorRulesRequest)(nil), // 225: aperio.v1.ListConnectorRulesRequest - (*ListConnectorRulesResponse)(nil), // 226: aperio.v1.ListConnectorRulesResponse - (*CreateCustomRuleRequest)(nil), // 227: aperio.v1.CreateCustomRuleRequest - (*CreateCustomRuleResponse)(nil), // 228: aperio.v1.CreateCustomRuleResponse - (*UpdateCustomRuleRequest)(nil), // 229: aperio.v1.UpdateCustomRuleRequest - (*UpdateCustomRuleResponse)(nil), // 230: aperio.v1.UpdateCustomRuleResponse - (*DeleteCustomRuleRequest)(nil), // 231: aperio.v1.DeleteCustomRuleRequest - (*DeleteCustomRuleResponse)(nil), // 232: aperio.v1.DeleteCustomRuleResponse - (*timestamppb.Timestamp)(nil), // 233: google.protobuf.Timestamp + (*ListDetectionPacksRequest)(nil), // 224: aperio.v1.ListDetectionPacksRequest + (*ListDetectionPacksResponse)(nil), // 225: aperio.v1.ListDetectionPacksResponse + (*DetectionPack)(nil), // 226: aperio.v1.DetectionPack + (*DetectionPackRule)(nil), // 227: aperio.v1.DetectionPackRule + (*ConnectorCustomRule)(nil), // 228: aperio.v1.ConnectorCustomRule + (*ListConnectorRulesRequest)(nil), // 229: aperio.v1.ListConnectorRulesRequest + (*ListConnectorRulesResponse)(nil), // 230: aperio.v1.ListConnectorRulesResponse + (*CreateCustomRuleRequest)(nil), // 231: aperio.v1.CreateCustomRuleRequest + (*CreateCustomRuleResponse)(nil), // 232: aperio.v1.CreateCustomRuleResponse + (*UpdateCustomRuleRequest)(nil), // 233: aperio.v1.UpdateCustomRuleRequest + (*UpdateCustomRuleResponse)(nil), // 234: aperio.v1.UpdateCustomRuleResponse + (*DeleteCustomRuleRequest)(nil), // 235: aperio.v1.DeleteCustomRuleRequest + (*DeleteCustomRuleResponse)(nil), // 236: aperio.v1.DeleteCustomRuleResponse + (*timestamppb.Timestamp)(nil), // 237: google.protobuf.Timestamp } var file_aperio_v1_api_proto_depIdxs = []int32{ 26, // 0: aperio.v1.SignupResponse.data:type_name -> aperio.v1.AuthSession @@ -17110,7 +17409,7 @@ var file_aperio_v1_api_proto_depIdxs = []int32{ 27, // 12: aperio.v1.AuthSession.user:type_name -> aperio.v1.AuthUser 28, // 13: aperio.v1.AuthSession.organization:type_name -> aperio.v1.AuthOrganization 29, // 14: aperio.v1.AuthSession.auth_context:type_name -> aperio.v1.AuthContext - 233, // 15: aperio.v1.CheckHealthResponse.checked_at:type_name -> google.protobuf.Timestamp + 237, // 15: aperio.v1.CheckHealthResponse.checked_at:type_name -> google.protobuf.Timestamp 35, // 16: aperio.v1.CheckHealthResponse.components:type_name -> aperio.v1.HealthComponent 38, // 17: aperio.v1.GetDashboardMetricsResponse.data:type_name -> aperio.v1.DashboardMetrics 49, // 18: aperio.v1.ListFindingsResponse.data:type_name -> aperio.v1.Finding @@ -17229,167 +17528,171 @@ var file_aperio_v1_api_proto_depIdxs = []int32{ 214, // 131: aperio.v1.ListExecutiveReportsResponse.data:type_name -> aperio.v1.ExecutiveReport 214, // 132: aperio.v1.GetExecutiveReportResponse.data:type_name -> aperio.v1.ExecutiveReport 214, // 133: aperio.v1.CreateExecutiveReportResponse.data:type_name -> aperio.v1.ExecutiveReport - 223, // 134: aperio.v1.ListConnectorRulesResponse.built_in:type_name -> aperio.v1.ConnectorBuiltInRule - 224, // 135: aperio.v1.ListConnectorRulesResponse.custom:type_name -> aperio.v1.ConnectorCustomRule - 0, // 136: aperio.v1.AperioService.CallApi:input_type -> aperio.v1.CallApiRequest - 2, // 137: aperio.v1.AperioService.Signup:input_type -> aperio.v1.SignupRequest - 4, // 138: aperio.v1.AperioService.Login:input_type -> aperio.v1.LoginRequest - 6, // 139: aperio.v1.AperioService.GetCurrentSession:input_type -> aperio.v1.GetCurrentSessionRequest - 8, // 140: aperio.v1.AperioService.LogoutCurrentSession:input_type -> aperio.v1.LogoutCurrentSessionRequest - 10, // 141: aperio.v1.AperioService.ListWorkspaces:input_type -> aperio.v1.ListWorkspacesRequest - 12, // 142: aperio.v1.AperioService.SwitchWorkspace:input_type -> aperio.v1.SwitchWorkspaceRequest - 14, // 143: aperio.v1.AperioService.RequestPasswordReset:input_type -> aperio.v1.RequestPasswordResetRequest - 16, // 144: aperio.v1.AperioService.ResetPassword:input_type -> aperio.v1.ResetPasswordRequest - 18, // 145: aperio.v1.AperioService.AcceptInvite:input_type -> aperio.v1.AcceptInviteRequest - 20, // 146: aperio.v1.AperioService.BeginMfaEnrollment:input_type -> aperio.v1.BeginMfaEnrollmentRequest - 22, // 147: aperio.v1.AperioService.EnableMfa:input_type -> aperio.v1.EnableMfaRequest - 24, // 148: aperio.v1.AperioService.DisableMfa:input_type -> aperio.v1.DisableMfaRequest - 33, // 149: aperio.v1.AperioService.CheckHealth:input_type -> aperio.v1.CheckHealthRequest - 36, // 150: aperio.v1.AperioService.GetDashboardMetrics:input_type -> aperio.v1.GetDashboardMetricsRequest - 39, // 151: aperio.v1.AperioService.ListFindings:input_type -> aperio.v1.ListFindingsRequest - 41, // 152: aperio.v1.AperioService.GetFinding:input_type -> aperio.v1.GetFindingRequest - 43, // 153: aperio.v1.AperioService.UpdateFindingStatus:input_type -> aperio.v1.UpdateFindingStatusRequest - 46, // 154: aperio.v1.AperioService.RemediateFinding:input_type -> aperio.v1.RemediateFindingRequest - 58, // 155: aperio.v1.AperioService.ListSaasIncidents:input_type -> aperio.v1.ListSaasIncidentsRequest - 60, // 156: aperio.v1.AperioService.GetSaasIncident:input_type -> aperio.v1.GetSaasIncidentRequest - 62, // 157: aperio.v1.AperioService.CreateSaasIncident:input_type -> aperio.v1.CreateSaasIncidentRequest - 64, // 158: aperio.v1.AperioService.UpdateSaasIncidentStatus:input_type -> aperio.v1.UpdateSaasIncidentStatusRequest - 66, // 159: aperio.v1.AperioService.ProposeSaasResponseAction:input_type -> aperio.v1.ProposeSaasResponseActionRequest - 68, // 160: aperio.v1.AperioService.ApproveSaasResponseAction:input_type -> aperio.v1.ApproveSaasResponseActionRequest - 70, // 161: aperio.v1.AperioService.ExecuteSaasResponseAction:input_type -> aperio.v1.ExecuteSaasResponseActionRequest - 78, // 162: aperio.v1.AperioService.ListConnectorCatalog:input_type -> aperio.v1.ListConnectorCatalogRequest - 84, // 163: aperio.v1.AperioService.ListIntegrations:input_type -> aperio.v1.ListIntegrationsRequest - 87, // 164: aperio.v1.AperioService.CreateIntegration:input_type -> aperio.v1.CreateIntegrationRequest - 90, // 165: aperio.v1.AperioService.DeleteIntegration:input_type -> aperio.v1.DeleteIntegrationRequest - 93, // 166: aperio.v1.AperioService.GetIntegrationChecks:input_type -> aperio.v1.GetIntegrationChecksRequest - 95, // 167: aperio.v1.AperioService.UpdateIntegrationChecks:input_type -> aperio.v1.UpdateIntegrationChecksRequest - 225, // 168: aperio.v1.AperioService.ListConnectorRules:input_type -> aperio.v1.ListConnectorRulesRequest - 227, // 169: aperio.v1.AperioService.CreateCustomRule:input_type -> aperio.v1.CreateCustomRuleRequest - 229, // 170: aperio.v1.AperioService.UpdateCustomRule:input_type -> aperio.v1.UpdateCustomRuleRequest - 231, // 171: aperio.v1.AperioService.DeleteCustomRule:input_type -> aperio.v1.DeleteCustomRuleRequest - 99, // 172: aperio.v1.AperioService.GetGoogleMailboxScanConfig:input_type -> aperio.v1.GetGoogleMailboxScanConfigRequest - 101, // 173: aperio.v1.AperioService.UpdateGoogleMailboxScanConfig:input_type -> aperio.v1.UpdateGoogleMailboxScanConfigRequest - 104, // 174: aperio.v1.AperioService.GetGoogleWorkspaceBigQueryConfig:input_type -> aperio.v1.GetGoogleWorkspaceBigQueryConfigRequest - 106, // 175: aperio.v1.AperioService.UpdateGoogleWorkspaceBigQueryConfig:input_type -> aperio.v1.UpdateGoogleWorkspaceBigQueryConfigRequest - 109, // 176: aperio.v1.AperioService.ValidateGoogleWorkspaceBigQueryConfig:input_type -> aperio.v1.ValidateGoogleWorkspaceBigQueryConfigRequest - 112, // 177: aperio.v1.AperioService.StartGoogleWorkspaceOAuth:input_type -> aperio.v1.StartGoogleWorkspaceOAuthRequest - 115, // 178: aperio.v1.AperioService.GetIntegrationOAuthClient:input_type -> aperio.v1.GetIntegrationOAuthClientRequest - 117, // 179: aperio.v1.AperioService.SetIntegrationOAuthClient:input_type -> aperio.v1.SetIntegrationOAuthClientRequest - 119, // 180: aperio.v1.AperioService.ClearIntegrationOAuthClient:input_type -> aperio.v1.ClearIntegrationOAuthClientRequest - 122, // 181: aperio.v1.AperioService.ForceSyncIntegration:input_type -> aperio.v1.ForceSyncIntegrationRequest - 125, // 182: aperio.v1.AperioService.GetIntegrationSyncStatus:input_type -> aperio.v1.GetIntegrationSyncStatusRequest - 127, // 183: aperio.v1.AperioService.RunIntegrationSourceSync:input_type -> aperio.v1.RunIntegrationSourceSyncRequest - 129, // 184: aperio.v1.AperioService.BackfillIntegrationSource:input_type -> aperio.v1.BackfillIntegrationSourceRequest - 134, // 185: aperio.v1.AperioService.ListSiemCatalog:input_type -> aperio.v1.ListSiemCatalogRequest - 138, // 186: aperio.v1.AperioService.ListSiemDestinations:input_type -> aperio.v1.ListSiemDestinationsRequest - 141, // 187: aperio.v1.AperioService.CreateSiemDestination:input_type -> aperio.v1.CreateSiemDestinationRequest - 143, // 188: aperio.v1.AperioService.DeleteSiemDestination:input_type -> aperio.v1.DeleteSiemDestinationRequest - 145, // 189: aperio.v1.AperioService.TestSiemDestination:input_type -> aperio.v1.TestSiemDestinationRequest - 148, // 190: aperio.v1.AperioService.ListShadowItOauthApps:input_type -> aperio.v1.ListShadowItOauthAppsRequest - 151, // 191: aperio.v1.AperioService.ListShadowItOauthAppGrants:input_type -> aperio.v1.ListShadowItOauthAppGrantsRequest - 156, // 192: aperio.v1.AperioService.GetTenantSettings:input_type -> aperio.v1.GetTenantSettingsRequest - 158, // 193: aperio.v1.AperioService.UpdateTenantSettings:input_type -> aperio.v1.UpdateTenantSettingsRequest - 161, // 194: aperio.v1.AperioService.ListTenantMembers:input_type -> aperio.v1.ListTenantMembersRequest - 163, // 195: aperio.v1.AperioService.CreateTenantMember:input_type -> aperio.v1.CreateTenantMemberRequest - 165, // 196: aperio.v1.AperioService.CreateMemberResetLink:input_type -> aperio.v1.CreateMemberResetLinkRequest - 167, // 197: aperio.v1.AperioService.UpdateMemberRole:input_type -> aperio.v1.UpdateMemberRoleRequest - 171, // 198: aperio.v1.AperioService.ListAuditLogs:input_type -> aperio.v1.ListAuditLogsRequest - 174, // 199: aperio.v1.AperioService.GetSecurityOverview:input_type -> aperio.v1.GetSecurityOverviewRequest - 186, // 200: aperio.v1.AperioService.ListEmailDomainHealth:input_type -> aperio.v1.ListEmailDomainHealthRequest - 188, // 201: aperio.v1.AperioService.GetEmailDomainHealth:input_type -> aperio.v1.GetEmailDomainHealthRequest - 190, // 202: aperio.v1.AperioService.RefreshEmailDomainHealth:input_type -> aperio.v1.RefreshEmailDomainHealthRequest - 197, // 203: aperio.v1.AperioService.ListSecurityAssets:input_type -> aperio.v1.ListSecurityAssetsRequest - 201, // 204: aperio.v1.AperioService.CreateSecurityAsset:input_type -> aperio.v1.CreateSecurityAssetRequest - 203, // 205: aperio.v1.AperioService.UpdateSecurityAsset:input_type -> aperio.v1.UpdateSecurityAssetRequest - 205, // 206: aperio.v1.AperioService.ListRiskExceptions:input_type -> aperio.v1.ListRiskExceptionsRequest - 210, // 207: aperio.v1.AperioService.CreateRiskException:input_type -> aperio.v1.CreateRiskExceptionRequest - 212, // 208: aperio.v1.AperioService.UpdateRiskException:input_type -> aperio.v1.UpdateRiskExceptionRequest - 215, // 209: aperio.v1.AperioService.ListExecutiveReports:input_type -> aperio.v1.ListExecutiveReportsRequest - 217, // 210: aperio.v1.AperioService.GetExecutiveReport:input_type -> aperio.v1.GetExecutiveReportRequest - 219, // 211: aperio.v1.AperioService.CreateExecutiveReport:input_type -> aperio.v1.CreateExecutiveReportRequest - 221, // 212: aperio.v1.AperioService.DeleteExecutiveReport:input_type -> aperio.v1.DeleteExecutiveReportRequest - 1, // 213: aperio.v1.AperioService.CallApi:output_type -> aperio.v1.CallApiResponse - 3, // 214: aperio.v1.AperioService.Signup:output_type -> aperio.v1.SignupResponse - 5, // 215: aperio.v1.AperioService.Login:output_type -> aperio.v1.LoginResponse - 7, // 216: aperio.v1.AperioService.GetCurrentSession:output_type -> aperio.v1.GetCurrentSessionResponse - 9, // 217: aperio.v1.AperioService.LogoutCurrentSession:output_type -> aperio.v1.LogoutCurrentSessionResponse - 11, // 218: aperio.v1.AperioService.ListWorkspaces:output_type -> aperio.v1.ListWorkspacesResponse - 13, // 219: aperio.v1.AperioService.SwitchWorkspace:output_type -> aperio.v1.SwitchWorkspaceResponse - 15, // 220: aperio.v1.AperioService.RequestPasswordReset:output_type -> aperio.v1.RequestPasswordResetResponse - 17, // 221: aperio.v1.AperioService.ResetPassword:output_type -> aperio.v1.ResetPasswordResponse - 19, // 222: aperio.v1.AperioService.AcceptInvite:output_type -> aperio.v1.AcceptInviteResponse - 21, // 223: aperio.v1.AperioService.BeginMfaEnrollment:output_type -> aperio.v1.BeginMfaEnrollmentResponse - 23, // 224: aperio.v1.AperioService.EnableMfa:output_type -> aperio.v1.EnableMfaResponse - 25, // 225: aperio.v1.AperioService.DisableMfa:output_type -> aperio.v1.DisableMfaResponse - 34, // 226: aperio.v1.AperioService.CheckHealth:output_type -> aperio.v1.CheckHealthResponse - 37, // 227: aperio.v1.AperioService.GetDashboardMetrics:output_type -> aperio.v1.GetDashboardMetricsResponse - 40, // 228: aperio.v1.AperioService.ListFindings:output_type -> aperio.v1.ListFindingsResponse - 42, // 229: aperio.v1.AperioService.GetFinding:output_type -> aperio.v1.GetFindingResponse - 44, // 230: aperio.v1.AperioService.UpdateFindingStatus:output_type -> aperio.v1.UpdateFindingStatusResponse - 47, // 231: aperio.v1.AperioService.RemediateFinding:output_type -> aperio.v1.RemediateFindingResponse - 59, // 232: aperio.v1.AperioService.ListSaasIncidents:output_type -> aperio.v1.ListSaasIncidentsResponse - 61, // 233: aperio.v1.AperioService.GetSaasIncident:output_type -> aperio.v1.GetSaasIncidentResponse - 63, // 234: aperio.v1.AperioService.CreateSaasIncident:output_type -> aperio.v1.CreateSaasIncidentResponse - 65, // 235: aperio.v1.AperioService.UpdateSaasIncidentStatus:output_type -> aperio.v1.UpdateSaasIncidentStatusResponse - 67, // 236: aperio.v1.AperioService.ProposeSaasResponseAction:output_type -> aperio.v1.ProposeSaasResponseActionResponse - 69, // 237: aperio.v1.AperioService.ApproveSaasResponseAction:output_type -> aperio.v1.ApproveSaasResponseActionResponse - 71, // 238: aperio.v1.AperioService.ExecuteSaasResponseAction:output_type -> aperio.v1.ExecuteSaasResponseActionResponse - 79, // 239: aperio.v1.AperioService.ListConnectorCatalog:output_type -> aperio.v1.ListConnectorCatalogResponse - 85, // 240: aperio.v1.AperioService.ListIntegrations:output_type -> aperio.v1.ListIntegrationsResponse - 89, // 241: aperio.v1.AperioService.CreateIntegration:output_type -> aperio.v1.CreateIntegrationResponse - 91, // 242: aperio.v1.AperioService.DeleteIntegration:output_type -> aperio.v1.DeleteIntegrationResponse - 94, // 243: aperio.v1.AperioService.GetIntegrationChecks:output_type -> aperio.v1.GetIntegrationChecksResponse - 96, // 244: aperio.v1.AperioService.UpdateIntegrationChecks:output_type -> aperio.v1.UpdateIntegrationChecksResponse - 226, // 245: aperio.v1.AperioService.ListConnectorRules:output_type -> aperio.v1.ListConnectorRulesResponse - 228, // 246: aperio.v1.AperioService.CreateCustomRule:output_type -> aperio.v1.CreateCustomRuleResponse - 230, // 247: aperio.v1.AperioService.UpdateCustomRule:output_type -> aperio.v1.UpdateCustomRuleResponse - 232, // 248: aperio.v1.AperioService.DeleteCustomRule:output_type -> aperio.v1.DeleteCustomRuleResponse - 100, // 249: aperio.v1.AperioService.GetGoogleMailboxScanConfig:output_type -> aperio.v1.GetGoogleMailboxScanConfigResponse - 102, // 250: aperio.v1.AperioService.UpdateGoogleMailboxScanConfig:output_type -> aperio.v1.UpdateGoogleMailboxScanConfigResponse - 105, // 251: aperio.v1.AperioService.GetGoogleWorkspaceBigQueryConfig:output_type -> aperio.v1.GetGoogleWorkspaceBigQueryConfigResponse - 107, // 252: aperio.v1.AperioService.UpdateGoogleWorkspaceBigQueryConfig:output_type -> aperio.v1.UpdateGoogleWorkspaceBigQueryConfigResponse - 110, // 253: aperio.v1.AperioService.ValidateGoogleWorkspaceBigQueryConfig:output_type -> aperio.v1.ValidateGoogleWorkspaceBigQueryConfigResponse - 113, // 254: aperio.v1.AperioService.StartGoogleWorkspaceOAuth:output_type -> aperio.v1.StartGoogleWorkspaceOAuthResponse - 116, // 255: aperio.v1.AperioService.GetIntegrationOAuthClient:output_type -> aperio.v1.GetIntegrationOAuthClientResponse - 118, // 256: aperio.v1.AperioService.SetIntegrationOAuthClient:output_type -> aperio.v1.SetIntegrationOAuthClientResponse - 120, // 257: aperio.v1.AperioService.ClearIntegrationOAuthClient:output_type -> aperio.v1.ClearIntegrationOAuthClientResponse - 123, // 258: aperio.v1.AperioService.ForceSyncIntegration:output_type -> aperio.v1.ForceSyncIntegrationResponse - 126, // 259: aperio.v1.AperioService.GetIntegrationSyncStatus:output_type -> aperio.v1.GetIntegrationSyncStatusResponse - 128, // 260: aperio.v1.AperioService.RunIntegrationSourceSync:output_type -> aperio.v1.RunIntegrationSourceSyncResponse - 130, // 261: aperio.v1.AperioService.BackfillIntegrationSource:output_type -> aperio.v1.BackfillIntegrationSourceResponse - 135, // 262: aperio.v1.AperioService.ListSiemCatalog:output_type -> aperio.v1.ListSiemCatalogResponse - 139, // 263: aperio.v1.AperioService.ListSiemDestinations:output_type -> aperio.v1.ListSiemDestinationsResponse - 142, // 264: aperio.v1.AperioService.CreateSiemDestination:output_type -> aperio.v1.CreateSiemDestinationResponse - 144, // 265: aperio.v1.AperioService.DeleteSiemDestination:output_type -> aperio.v1.DeleteSiemDestinationResponse - 146, // 266: aperio.v1.AperioService.TestSiemDestination:output_type -> aperio.v1.TestSiemDestinationResponse - 149, // 267: aperio.v1.AperioService.ListShadowItOauthApps:output_type -> aperio.v1.ListShadowItOauthAppsResponse - 152, // 268: aperio.v1.AperioService.ListShadowItOauthAppGrants:output_type -> aperio.v1.ListShadowItOauthAppGrantsResponse - 157, // 269: aperio.v1.AperioService.GetTenantSettings:output_type -> aperio.v1.GetTenantSettingsResponse - 159, // 270: aperio.v1.AperioService.UpdateTenantSettings:output_type -> aperio.v1.UpdateTenantSettingsResponse - 162, // 271: aperio.v1.AperioService.ListTenantMembers:output_type -> aperio.v1.ListTenantMembersResponse - 164, // 272: aperio.v1.AperioService.CreateTenantMember:output_type -> aperio.v1.CreateTenantMemberResponse - 166, // 273: aperio.v1.AperioService.CreateMemberResetLink:output_type -> aperio.v1.CreateMemberResetLinkResponse - 168, // 274: aperio.v1.AperioService.UpdateMemberRole:output_type -> aperio.v1.UpdateMemberRoleResponse - 172, // 275: aperio.v1.AperioService.ListAuditLogs:output_type -> aperio.v1.ListAuditLogsResponse - 175, // 276: aperio.v1.AperioService.GetSecurityOverview:output_type -> aperio.v1.GetSecurityOverviewResponse - 187, // 277: aperio.v1.AperioService.ListEmailDomainHealth:output_type -> aperio.v1.ListEmailDomainHealthResponse - 189, // 278: aperio.v1.AperioService.GetEmailDomainHealth:output_type -> aperio.v1.GetEmailDomainHealthResponse - 191, // 279: aperio.v1.AperioService.RefreshEmailDomainHealth:output_type -> aperio.v1.RefreshEmailDomainHealthResponse - 198, // 280: aperio.v1.AperioService.ListSecurityAssets:output_type -> aperio.v1.ListSecurityAssetsResponse - 202, // 281: aperio.v1.AperioService.CreateSecurityAsset:output_type -> aperio.v1.CreateSecurityAssetResponse - 204, // 282: aperio.v1.AperioService.UpdateSecurityAsset:output_type -> aperio.v1.UpdateSecurityAssetResponse - 206, // 283: aperio.v1.AperioService.ListRiskExceptions:output_type -> aperio.v1.ListRiskExceptionsResponse - 211, // 284: aperio.v1.AperioService.CreateRiskException:output_type -> aperio.v1.CreateRiskExceptionResponse - 213, // 285: aperio.v1.AperioService.UpdateRiskException:output_type -> aperio.v1.UpdateRiskExceptionResponse - 216, // 286: aperio.v1.AperioService.ListExecutiveReports:output_type -> aperio.v1.ListExecutiveReportsResponse - 218, // 287: aperio.v1.AperioService.GetExecutiveReport:output_type -> aperio.v1.GetExecutiveReportResponse - 220, // 288: aperio.v1.AperioService.CreateExecutiveReport:output_type -> aperio.v1.CreateExecutiveReportResponse - 222, // 289: aperio.v1.AperioService.DeleteExecutiveReport:output_type -> aperio.v1.DeleteExecutiveReportResponse - 213, // [213:290] is the sub-list for method output_type - 136, // [136:213] is the sub-list for method input_type - 136, // [136:136] is the sub-list for extension type_name - 136, // [136:136] is the sub-list for extension extendee - 0, // [0:136] is the sub-list for field type_name + 226, // 134: aperio.v1.ListDetectionPacksResponse.data:type_name -> aperio.v1.DetectionPack + 227, // 135: aperio.v1.DetectionPack.rules:type_name -> aperio.v1.DetectionPackRule + 223, // 136: aperio.v1.ListConnectorRulesResponse.built_in:type_name -> aperio.v1.ConnectorBuiltInRule + 228, // 137: aperio.v1.ListConnectorRulesResponse.custom:type_name -> aperio.v1.ConnectorCustomRule + 0, // 138: aperio.v1.AperioService.CallApi:input_type -> aperio.v1.CallApiRequest + 2, // 139: aperio.v1.AperioService.Signup:input_type -> aperio.v1.SignupRequest + 4, // 140: aperio.v1.AperioService.Login:input_type -> aperio.v1.LoginRequest + 6, // 141: aperio.v1.AperioService.GetCurrentSession:input_type -> aperio.v1.GetCurrentSessionRequest + 8, // 142: aperio.v1.AperioService.LogoutCurrentSession:input_type -> aperio.v1.LogoutCurrentSessionRequest + 10, // 143: aperio.v1.AperioService.ListWorkspaces:input_type -> aperio.v1.ListWorkspacesRequest + 12, // 144: aperio.v1.AperioService.SwitchWorkspace:input_type -> aperio.v1.SwitchWorkspaceRequest + 14, // 145: aperio.v1.AperioService.RequestPasswordReset:input_type -> aperio.v1.RequestPasswordResetRequest + 16, // 146: aperio.v1.AperioService.ResetPassword:input_type -> aperio.v1.ResetPasswordRequest + 18, // 147: aperio.v1.AperioService.AcceptInvite:input_type -> aperio.v1.AcceptInviteRequest + 20, // 148: aperio.v1.AperioService.BeginMfaEnrollment:input_type -> aperio.v1.BeginMfaEnrollmentRequest + 22, // 149: aperio.v1.AperioService.EnableMfa:input_type -> aperio.v1.EnableMfaRequest + 24, // 150: aperio.v1.AperioService.DisableMfa:input_type -> aperio.v1.DisableMfaRequest + 33, // 151: aperio.v1.AperioService.CheckHealth:input_type -> aperio.v1.CheckHealthRequest + 36, // 152: aperio.v1.AperioService.GetDashboardMetrics:input_type -> aperio.v1.GetDashboardMetricsRequest + 39, // 153: aperio.v1.AperioService.ListFindings:input_type -> aperio.v1.ListFindingsRequest + 41, // 154: aperio.v1.AperioService.GetFinding:input_type -> aperio.v1.GetFindingRequest + 43, // 155: aperio.v1.AperioService.UpdateFindingStatus:input_type -> aperio.v1.UpdateFindingStatusRequest + 46, // 156: aperio.v1.AperioService.RemediateFinding:input_type -> aperio.v1.RemediateFindingRequest + 58, // 157: aperio.v1.AperioService.ListSaasIncidents:input_type -> aperio.v1.ListSaasIncidentsRequest + 60, // 158: aperio.v1.AperioService.GetSaasIncident:input_type -> aperio.v1.GetSaasIncidentRequest + 62, // 159: aperio.v1.AperioService.CreateSaasIncident:input_type -> aperio.v1.CreateSaasIncidentRequest + 64, // 160: aperio.v1.AperioService.UpdateSaasIncidentStatus:input_type -> aperio.v1.UpdateSaasIncidentStatusRequest + 66, // 161: aperio.v1.AperioService.ProposeSaasResponseAction:input_type -> aperio.v1.ProposeSaasResponseActionRequest + 68, // 162: aperio.v1.AperioService.ApproveSaasResponseAction:input_type -> aperio.v1.ApproveSaasResponseActionRequest + 70, // 163: aperio.v1.AperioService.ExecuteSaasResponseAction:input_type -> aperio.v1.ExecuteSaasResponseActionRequest + 224, // 164: aperio.v1.AperioService.ListDetectionPacks:input_type -> aperio.v1.ListDetectionPacksRequest + 78, // 165: aperio.v1.AperioService.ListConnectorCatalog:input_type -> aperio.v1.ListConnectorCatalogRequest + 84, // 166: aperio.v1.AperioService.ListIntegrations:input_type -> aperio.v1.ListIntegrationsRequest + 87, // 167: aperio.v1.AperioService.CreateIntegration:input_type -> aperio.v1.CreateIntegrationRequest + 90, // 168: aperio.v1.AperioService.DeleteIntegration:input_type -> aperio.v1.DeleteIntegrationRequest + 93, // 169: aperio.v1.AperioService.GetIntegrationChecks:input_type -> aperio.v1.GetIntegrationChecksRequest + 95, // 170: aperio.v1.AperioService.UpdateIntegrationChecks:input_type -> aperio.v1.UpdateIntegrationChecksRequest + 229, // 171: aperio.v1.AperioService.ListConnectorRules:input_type -> aperio.v1.ListConnectorRulesRequest + 231, // 172: aperio.v1.AperioService.CreateCustomRule:input_type -> aperio.v1.CreateCustomRuleRequest + 233, // 173: aperio.v1.AperioService.UpdateCustomRule:input_type -> aperio.v1.UpdateCustomRuleRequest + 235, // 174: aperio.v1.AperioService.DeleteCustomRule:input_type -> aperio.v1.DeleteCustomRuleRequest + 99, // 175: aperio.v1.AperioService.GetGoogleMailboxScanConfig:input_type -> aperio.v1.GetGoogleMailboxScanConfigRequest + 101, // 176: aperio.v1.AperioService.UpdateGoogleMailboxScanConfig:input_type -> aperio.v1.UpdateGoogleMailboxScanConfigRequest + 104, // 177: aperio.v1.AperioService.GetGoogleWorkspaceBigQueryConfig:input_type -> aperio.v1.GetGoogleWorkspaceBigQueryConfigRequest + 106, // 178: aperio.v1.AperioService.UpdateGoogleWorkspaceBigQueryConfig:input_type -> aperio.v1.UpdateGoogleWorkspaceBigQueryConfigRequest + 109, // 179: aperio.v1.AperioService.ValidateGoogleWorkspaceBigQueryConfig:input_type -> aperio.v1.ValidateGoogleWorkspaceBigQueryConfigRequest + 112, // 180: aperio.v1.AperioService.StartGoogleWorkspaceOAuth:input_type -> aperio.v1.StartGoogleWorkspaceOAuthRequest + 115, // 181: aperio.v1.AperioService.GetIntegrationOAuthClient:input_type -> aperio.v1.GetIntegrationOAuthClientRequest + 117, // 182: aperio.v1.AperioService.SetIntegrationOAuthClient:input_type -> aperio.v1.SetIntegrationOAuthClientRequest + 119, // 183: aperio.v1.AperioService.ClearIntegrationOAuthClient:input_type -> aperio.v1.ClearIntegrationOAuthClientRequest + 122, // 184: aperio.v1.AperioService.ForceSyncIntegration:input_type -> aperio.v1.ForceSyncIntegrationRequest + 125, // 185: aperio.v1.AperioService.GetIntegrationSyncStatus:input_type -> aperio.v1.GetIntegrationSyncStatusRequest + 127, // 186: aperio.v1.AperioService.RunIntegrationSourceSync:input_type -> aperio.v1.RunIntegrationSourceSyncRequest + 129, // 187: aperio.v1.AperioService.BackfillIntegrationSource:input_type -> aperio.v1.BackfillIntegrationSourceRequest + 134, // 188: aperio.v1.AperioService.ListSiemCatalog:input_type -> aperio.v1.ListSiemCatalogRequest + 138, // 189: aperio.v1.AperioService.ListSiemDestinations:input_type -> aperio.v1.ListSiemDestinationsRequest + 141, // 190: aperio.v1.AperioService.CreateSiemDestination:input_type -> aperio.v1.CreateSiemDestinationRequest + 143, // 191: aperio.v1.AperioService.DeleteSiemDestination:input_type -> aperio.v1.DeleteSiemDestinationRequest + 145, // 192: aperio.v1.AperioService.TestSiemDestination:input_type -> aperio.v1.TestSiemDestinationRequest + 148, // 193: aperio.v1.AperioService.ListShadowItOauthApps:input_type -> aperio.v1.ListShadowItOauthAppsRequest + 151, // 194: aperio.v1.AperioService.ListShadowItOauthAppGrants:input_type -> aperio.v1.ListShadowItOauthAppGrantsRequest + 156, // 195: aperio.v1.AperioService.GetTenantSettings:input_type -> aperio.v1.GetTenantSettingsRequest + 158, // 196: aperio.v1.AperioService.UpdateTenantSettings:input_type -> aperio.v1.UpdateTenantSettingsRequest + 161, // 197: aperio.v1.AperioService.ListTenantMembers:input_type -> aperio.v1.ListTenantMembersRequest + 163, // 198: aperio.v1.AperioService.CreateTenantMember:input_type -> aperio.v1.CreateTenantMemberRequest + 165, // 199: aperio.v1.AperioService.CreateMemberResetLink:input_type -> aperio.v1.CreateMemberResetLinkRequest + 167, // 200: aperio.v1.AperioService.UpdateMemberRole:input_type -> aperio.v1.UpdateMemberRoleRequest + 171, // 201: aperio.v1.AperioService.ListAuditLogs:input_type -> aperio.v1.ListAuditLogsRequest + 174, // 202: aperio.v1.AperioService.GetSecurityOverview:input_type -> aperio.v1.GetSecurityOverviewRequest + 186, // 203: aperio.v1.AperioService.ListEmailDomainHealth:input_type -> aperio.v1.ListEmailDomainHealthRequest + 188, // 204: aperio.v1.AperioService.GetEmailDomainHealth:input_type -> aperio.v1.GetEmailDomainHealthRequest + 190, // 205: aperio.v1.AperioService.RefreshEmailDomainHealth:input_type -> aperio.v1.RefreshEmailDomainHealthRequest + 197, // 206: aperio.v1.AperioService.ListSecurityAssets:input_type -> aperio.v1.ListSecurityAssetsRequest + 201, // 207: aperio.v1.AperioService.CreateSecurityAsset:input_type -> aperio.v1.CreateSecurityAssetRequest + 203, // 208: aperio.v1.AperioService.UpdateSecurityAsset:input_type -> aperio.v1.UpdateSecurityAssetRequest + 205, // 209: aperio.v1.AperioService.ListRiskExceptions:input_type -> aperio.v1.ListRiskExceptionsRequest + 210, // 210: aperio.v1.AperioService.CreateRiskException:input_type -> aperio.v1.CreateRiskExceptionRequest + 212, // 211: aperio.v1.AperioService.UpdateRiskException:input_type -> aperio.v1.UpdateRiskExceptionRequest + 215, // 212: aperio.v1.AperioService.ListExecutiveReports:input_type -> aperio.v1.ListExecutiveReportsRequest + 217, // 213: aperio.v1.AperioService.GetExecutiveReport:input_type -> aperio.v1.GetExecutiveReportRequest + 219, // 214: aperio.v1.AperioService.CreateExecutiveReport:input_type -> aperio.v1.CreateExecutiveReportRequest + 221, // 215: aperio.v1.AperioService.DeleteExecutiveReport:input_type -> aperio.v1.DeleteExecutiveReportRequest + 1, // 216: aperio.v1.AperioService.CallApi:output_type -> aperio.v1.CallApiResponse + 3, // 217: aperio.v1.AperioService.Signup:output_type -> aperio.v1.SignupResponse + 5, // 218: aperio.v1.AperioService.Login:output_type -> aperio.v1.LoginResponse + 7, // 219: aperio.v1.AperioService.GetCurrentSession:output_type -> aperio.v1.GetCurrentSessionResponse + 9, // 220: aperio.v1.AperioService.LogoutCurrentSession:output_type -> aperio.v1.LogoutCurrentSessionResponse + 11, // 221: aperio.v1.AperioService.ListWorkspaces:output_type -> aperio.v1.ListWorkspacesResponse + 13, // 222: aperio.v1.AperioService.SwitchWorkspace:output_type -> aperio.v1.SwitchWorkspaceResponse + 15, // 223: aperio.v1.AperioService.RequestPasswordReset:output_type -> aperio.v1.RequestPasswordResetResponse + 17, // 224: aperio.v1.AperioService.ResetPassword:output_type -> aperio.v1.ResetPasswordResponse + 19, // 225: aperio.v1.AperioService.AcceptInvite:output_type -> aperio.v1.AcceptInviteResponse + 21, // 226: aperio.v1.AperioService.BeginMfaEnrollment:output_type -> aperio.v1.BeginMfaEnrollmentResponse + 23, // 227: aperio.v1.AperioService.EnableMfa:output_type -> aperio.v1.EnableMfaResponse + 25, // 228: aperio.v1.AperioService.DisableMfa:output_type -> aperio.v1.DisableMfaResponse + 34, // 229: aperio.v1.AperioService.CheckHealth:output_type -> aperio.v1.CheckHealthResponse + 37, // 230: aperio.v1.AperioService.GetDashboardMetrics:output_type -> aperio.v1.GetDashboardMetricsResponse + 40, // 231: aperio.v1.AperioService.ListFindings:output_type -> aperio.v1.ListFindingsResponse + 42, // 232: aperio.v1.AperioService.GetFinding:output_type -> aperio.v1.GetFindingResponse + 44, // 233: aperio.v1.AperioService.UpdateFindingStatus:output_type -> aperio.v1.UpdateFindingStatusResponse + 47, // 234: aperio.v1.AperioService.RemediateFinding:output_type -> aperio.v1.RemediateFindingResponse + 59, // 235: aperio.v1.AperioService.ListSaasIncidents:output_type -> aperio.v1.ListSaasIncidentsResponse + 61, // 236: aperio.v1.AperioService.GetSaasIncident:output_type -> aperio.v1.GetSaasIncidentResponse + 63, // 237: aperio.v1.AperioService.CreateSaasIncident:output_type -> aperio.v1.CreateSaasIncidentResponse + 65, // 238: aperio.v1.AperioService.UpdateSaasIncidentStatus:output_type -> aperio.v1.UpdateSaasIncidentStatusResponse + 67, // 239: aperio.v1.AperioService.ProposeSaasResponseAction:output_type -> aperio.v1.ProposeSaasResponseActionResponse + 69, // 240: aperio.v1.AperioService.ApproveSaasResponseAction:output_type -> aperio.v1.ApproveSaasResponseActionResponse + 71, // 241: aperio.v1.AperioService.ExecuteSaasResponseAction:output_type -> aperio.v1.ExecuteSaasResponseActionResponse + 225, // 242: aperio.v1.AperioService.ListDetectionPacks:output_type -> aperio.v1.ListDetectionPacksResponse + 79, // 243: aperio.v1.AperioService.ListConnectorCatalog:output_type -> aperio.v1.ListConnectorCatalogResponse + 85, // 244: aperio.v1.AperioService.ListIntegrations:output_type -> aperio.v1.ListIntegrationsResponse + 89, // 245: aperio.v1.AperioService.CreateIntegration:output_type -> aperio.v1.CreateIntegrationResponse + 91, // 246: aperio.v1.AperioService.DeleteIntegration:output_type -> aperio.v1.DeleteIntegrationResponse + 94, // 247: aperio.v1.AperioService.GetIntegrationChecks:output_type -> aperio.v1.GetIntegrationChecksResponse + 96, // 248: aperio.v1.AperioService.UpdateIntegrationChecks:output_type -> aperio.v1.UpdateIntegrationChecksResponse + 230, // 249: aperio.v1.AperioService.ListConnectorRules:output_type -> aperio.v1.ListConnectorRulesResponse + 232, // 250: aperio.v1.AperioService.CreateCustomRule:output_type -> aperio.v1.CreateCustomRuleResponse + 234, // 251: aperio.v1.AperioService.UpdateCustomRule:output_type -> aperio.v1.UpdateCustomRuleResponse + 236, // 252: aperio.v1.AperioService.DeleteCustomRule:output_type -> aperio.v1.DeleteCustomRuleResponse + 100, // 253: aperio.v1.AperioService.GetGoogleMailboxScanConfig:output_type -> aperio.v1.GetGoogleMailboxScanConfigResponse + 102, // 254: aperio.v1.AperioService.UpdateGoogleMailboxScanConfig:output_type -> aperio.v1.UpdateGoogleMailboxScanConfigResponse + 105, // 255: aperio.v1.AperioService.GetGoogleWorkspaceBigQueryConfig:output_type -> aperio.v1.GetGoogleWorkspaceBigQueryConfigResponse + 107, // 256: aperio.v1.AperioService.UpdateGoogleWorkspaceBigQueryConfig:output_type -> aperio.v1.UpdateGoogleWorkspaceBigQueryConfigResponse + 110, // 257: aperio.v1.AperioService.ValidateGoogleWorkspaceBigQueryConfig:output_type -> aperio.v1.ValidateGoogleWorkspaceBigQueryConfigResponse + 113, // 258: aperio.v1.AperioService.StartGoogleWorkspaceOAuth:output_type -> aperio.v1.StartGoogleWorkspaceOAuthResponse + 116, // 259: aperio.v1.AperioService.GetIntegrationOAuthClient:output_type -> aperio.v1.GetIntegrationOAuthClientResponse + 118, // 260: aperio.v1.AperioService.SetIntegrationOAuthClient:output_type -> aperio.v1.SetIntegrationOAuthClientResponse + 120, // 261: aperio.v1.AperioService.ClearIntegrationOAuthClient:output_type -> aperio.v1.ClearIntegrationOAuthClientResponse + 123, // 262: aperio.v1.AperioService.ForceSyncIntegration:output_type -> aperio.v1.ForceSyncIntegrationResponse + 126, // 263: aperio.v1.AperioService.GetIntegrationSyncStatus:output_type -> aperio.v1.GetIntegrationSyncStatusResponse + 128, // 264: aperio.v1.AperioService.RunIntegrationSourceSync:output_type -> aperio.v1.RunIntegrationSourceSyncResponse + 130, // 265: aperio.v1.AperioService.BackfillIntegrationSource:output_type -> aperio.v1.BackfillIntegrationSourceResponse + 135, // 266: aperio.v1.AperioService.ListSiemCatalog:output_type -> aperio.v1.ListSiemCatalogResponse + 139, // 267: aperio.v1.AperioService.ListSiemDestinations:output_type -> aperio.v1.ListSiemDestinationsResponse + 142, // 268: aperio.v1.AperioService.CreateSiemDestination:output_type -> aperio.v1.CreateSiemDestinationResponse + 144, // 269: aperio.v1.AperioService.DeleteSiemDestination:output_type -> aperio.v1.DeleteSiemDestinationResponse + 146, // 270: aperio.v1.AperioService.TestSiemDestination:output_type -> aperio.v1.TestSiemDestinationResponse + 149, // 271: aperio.v1.AperioService.ListShadowItOauthApps:output_type -> aperio.v1.ListShadowItOauthAppsResponse + 152, // 272: aperio.v1.AperioService.ListShadowItOauthAppGrants:output_type -> aperio.v1.ListShadowItOauthAppGrantsResponse + 157, // 273: aperio.v1.AperioService.GetTenantSettings:output_type -> aperio.v1.GetTenantSettingsResponse + 159, // 274: aperio.v1.AperioService.UpdateTenantSettings:output_type -> aperio.v1.UpdateTenantSettingsResponse + 162, // 275: aperio.v1.AperioService.ListTenantMembers:output_type -> aperio.v1.ListTenantMembersResponse + 164, // 276: aperio.v1.AperioService.CreateTenantMember:output_type -> aperio.v1.CreateTenantMemberResponse + 166, // 277: aperio.v1.AperioService.CreateMemberResetLink:output_type -> aperio.v1.CreateMemberResetLinkResponse + 168, // 278: aperio.v1.AperioService.UpdateMemberRole:output_type -> aperio.v1.UpdateMemberRoleResponse + 172, // 279: aperio.v1.AperioService.ListAuditLogs:output_type -> aperio.v1.ListAuditLogsResponse + 175, // 280: aperio.v1.AperioService.GetSecurityOverview:output_type -> aperio.v1.GetSecurityOverviewResponse + 187, // 281: aperio.v1.AperioService.ListEmailDomainHealth:output_type -> aperio.v1.ListEmailDomainHealthResponse + 189, // 282: aperio.v1.AperioService.GetEmailDomainHealth:output_type -> aperio.v1.GetEmailDomainHealthResponse + 191, // 283: aperio.v1.AperioService.RefreshEmailDomainHealth:output_type -> aperio.v1.RefreshEmailDomainHealthResponse + 198, // 284: aperio.v1.AperioService.ListSecurityAssets:output_type -> aperio.v1.ListSecurityAssetsResponse + 202, // 285: aperio.v1.AperioService.CreateSecurityAsset:output_type -> aperio.v1.CreateSecurityAssetResponse + 204, // 286: aperio.v1.AperioService.UpdateSecurityAsset:output_type -> aperio.v1.UpdateSecurityAssetResponse + 206, // 287: aperio.v1.AperioService.ListRiskExceptions:output_type -> aperio.v1.ListRiskExceptionsResponse + 211, // 288: aperio.v1.AperioService.CreateRiskException:output_type -> aperio.v1.CreateRiskExceptionResponse + 213, // 289: aperio.v1.AperioService.UpdateRiskException:output_type -> aperio.v1.UpdateRiskExceptionResponse + 216, // 290: aperio.v1.AperioService.ListExecutiveReports:output_type -> aperio.v1.ListExecutiveReportsResponse + 218, // 291: aperio.v1.AperioService.GetExecutiveReport:output_type -> aperio.v1.GetExecutiveReportResponse + 220, // 292: aperio.v1.AperioService.CreateExecutiveReport:output_type -> aperio.v1.CreateExecutiveReportResponse + 222, // 293: aperio.v1.AperioService.DeleteExecutiveReport:output_type -> aperio.v1.DeleteExecutiveReportResponse + 216, // [216:294] is the sub-list for method output_type + 138, // [138:216] is the sub-list for method input_type + 138, // [138:138] is the sub-list for extension type_name + 138, // [138:138] is the sub-list for extension extendee + 0, // [0:138] is the sub-list for field type_name } func init() { file_aperio_v1_api_proto_init() } @@ -17408,7 +17711,7 @@ func file_aperio_v1_api_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_aperio_v1_api_proto_rawDesc), len(file_aperio_v1_api_proto_rawDesc)), NumEnums: 0, - NumMessages: 233, + NumMessages: 237, NumExtensions: 0, NumServices: 1, }, diff --git a/internal/bootstrap/detection_packs.go b/internal/bootstrap/detection_packs.go new file mode 100644 index 00000000..89d87bd9 --- /dev/null +++ b/internal/bootstrap/detection_packs.go @@ -0,0 +1,61 @@ +package bootstrap + +import ( + "context" + + connect "connectrpc.com/connect" + + aperiov1 "github.com/writer/aperio/gen/aperio/v1" + "github.com/writer/aperio/internal/ingestionworker" +) + +// ListDetectionPacks returns every detection pack the worker knows about, +// each hydrated with the rules it owns. The shape is intentionally flat +// so the operator UI can render the catalog in a single render pass +// without follow-up requests. Provider filter is optional; an empty +// provider returns every pack in display order. +func (a *App) ListDetectionPacks( + ctx context.Context, + req *connect.Request[aperiov1.ListDetectionPacksRequest], +) (*connect.Response[aperiov1.ListDetectionPacksResponse], error) { + if _, err := a.authenticatedOrganization(ctx, req.Header()); err != nil { + return nil, err + } + providerFilter := "" + if req.Msg != nil { + providerFilter = req.Msg.Provider + } + out := &aperiov1.ListDetectionPacksResponse{} + for _, pack := range ingestionworker.DetectionPacks { + if providerFilter != "" && providerFilter != pack.Provider { + continue + } + out.Data = append(out.Data, detectionPackProto(pack)) + } + return connect.NewResponse(out), nil +} + +func detectionPackProto(pack ingestionworker.DetectionPack) *aperiov1.DetectionPack { + rules := ingestionworker.RulesInPack(pack.ID) + out := &aperiov1.DetectionPack{ + Id: pack.ID, + Provider: pack.Provider, + Name: pack.Name, + Description: pack.Description, + Version: pack.Version, + Rules: make([]*aperiov1.DetectionPackRule, 0, len(rules)), + } + for _, rule := range rules { + out.Rules = append(out.Rules, &aperiov1.DetectionPackRule{ + Id: rule.ID, + Title: rule.Title, + Description: rule.Description, + Severity: rule.Severity, + EventTypes: append([]string(nil), rule.EventTypes...), + MitreTechniques: append([]string(nil), rule.MitreTechniques...), + Intent: rule.Intent, + Tags: append([]string(nil), rule.Tags...), + }) + } + return out +} diff --git a/internal/bootstrap/detection_packs_test.go b/internal/bootstrap/detection_packs_test.go new file mode 100644 index 00000000..1908bfb3 --- /dev/null +++ b/internal/bootstrap/detection_packs_test.go @@ -0,0 +1,54 @@ +package bootstrap + +import ( + "testing" + + "github.com/writer/aperio/internal/ingestionworker" +) + +// TestDetectionPackProtoHydratesRules pins the API surface: every pack +// returned to the UI must carry its full rule metadata so the catalog +// page can render in one shot. Drift here would either drop pack-level +// fields the UI relies on or leave rule arrays empty. +func TestDetectionPackProtoHydratesRules(t *testing.T) { + for _, pack := range ingestionworker.DetectionPacks { + got := detectionPackProto(pack) + if got.Id != pack.ID { + t.Errorf("pack %q: proto Id = %q", pack.ID, got.Id) + } + if got.Provider != pack.Provider { + t.Errorf("pack %q: proto Provider = %q", pack.ID, got.Provider) + } + if got.Version != pack.Version { + t.Errorf("pack %q: proto Version = %q", pack.ID, got.Version) + } + if got.Name == "" { + t.Errorf("pack %q: proto Name empty", pack.ID) + } + wantRules := ingestionworker.RulesInPack(pack.ID) + if len(got.Rules) != len(wantRules) { + t.Errorf("pack %q: rule count = %d, want %d", pack.ID, len(got.Rules), len(wantRules)) + } + for i, rule := range got.Rules { + if i >= len(wantRules) { + break + } + want := wantRules[i] + if rule.Id != want.ID { + t.Errorf("pack %q rule[%d]: Id = %q want %q", pack.ID, i, rule.Id, want.ID) + } + if rule.Severity != want.Severity { + t.Errorf("pack %q rule[%d]: Severity = %q want %q", pack.ID, i, rule.Severity, want.Severity) + } + if rule.Intent == "" { + t.Errorf("pack %q rule[%d]: Intent empty", pack.ID, i) + } + if len(rule.MitreTechniques) == 0 { + t.Errorf("pack %q rule[%d]: MitreTechniques empty", pack.ID, i) + } + if len(rule.Tags) == 0 { + t.Errorf("pack %q rule[%d]: Tags empty", pack.ID, i) + } + } + } +} diff --git a/internal/ingestionworker/detection_packs.go b/internal/ingestionworker/detection_packs.go new file mode 100644 index 00000000..e820e14c --- /dev/null +++ b/internal/ingestionworker/detection_packs.go @@ -0,0 +1,92 @@ +package ingestionworker + +// DetectionPack is a versioned, curated bundle of built-in finding rules +// scoped to a provider and a coherent threat surface (admin-state, +// OAuth, mailbox abuse, repo hygiene, ...). Packs are how Aperio +// communicates coverage to operators: instead of a flat list of 16+ +// toggles, the UI groups by pack so a buyer can answer "what does +// Aperio detect on Google Workspace for mailbox exfiltration?" in one +// glance. +// +// Pack IDs are stable contracts; once a pack ships, never change its +// ID. Bump Version on every content change (semver). Description should +// read like a one-line analyst-facing capability statement. +type DetectionPack struct { + ID string + Provider string + Name string + Description string + Version string +} + +// DetectionPacks is the registry of every pack the worker knows about. +// Every RuleCatalogEntry.PackID must point into this table; the parity +// test in detection_packs_test.go pins the contract. +var DetectionPacks = []DetectionPack{ + { + ID: "aperio.github.core.v1", + Provider: "GITHUB", + Name: "GitHub repository hygiene", + Description: "Public repository creation, branch protection bypass, and personal access token misuse on GitHub.", + Version: "1.0.0", + }, + { + ID: "aperio.slack.core.v1", + Provider: "SLACK", + Name: "Slack workspace access", + Description: "Multi-factor authentication state and external-collaborator access events on Slack.", + Version: "1.0.0", + }, + { + ID: "aperio.okta.core.v1", + Provider: "OKTA", + Name: "Okta identity threats", + Description: "Privileged role assignment, MFA factor reset, password policy weakening, and suspicious sign-in signals from Okta.", + Version: "1.0.0", + }, + { + ID: "aperio.google_workspace.identity.v1", + Provider: "GOOGLE_WORKSPACE", + Name: "Google Workspace identity & admin", + Description: "Super-admin and delegated-admin grants, admin MFA enforcement, and admin recovery-email risk in Google Workspace.", + Version: "1.0.0", + }, + { + ID: "aperio.google_workspace.mail.v1", + Provider: "GOOGLE_WORKSPACE", + Name: "Google Workspace mailbox exfiltration", + Description: "Mail forwarding, mailbox delegation, send-as, and legacy IMAP/SMTP auth paths attackers use to siphon Gmail.", + Version: "1.0.0", + }, + { + ID: "aperio.google_workspace.drive.v1", + Provider: "GOOGLE_WORKSPACE", + Name: "Google Workspace Drive sharing & OAuth", + Description: "External Drive sharing, risky OAuth grants, and mass-download exfiltration patterns in Google Workspace.", + Version: "1.0.0", + }, +} + +// DetectionPackByID returns the pack with the given ID, or false if no +// pack matches. The API uses this to validate referenced pack IDs and +// to hydrate the rules under each pack for the operator UI. +func DetectionPackByID(id string) (DetectionPack, bool) { + for _, pack := range DetectionPacks { + if pack.ID == id { + return pack, true + } + } + return DetectionPack{}, false +} + +// RulesInPack returns every RuleCatalog entry that names the given pack +// ID, preserving catalog display order. An unknown pack returns nil. +func RulesInPack(packID string) []RuleCatalogEntry { + out := make([]RuleCatalogEntry, 0, 4) + for _, entry := range RuleCatalog { + if entry.PackID == packID { + out = append(out, entry) + } + } + return out +} diff --git a/internal/ingestionworker/detection_packs_test.go b/internal/ingestionworker/detection_packs_test.go new file mode 100644 index 00000000..1a277207 --- /dev/null +++ b/internal/ingestionworker/detection_packs_test.go @@ -0,0 +1,135 @@ +package ingestionworker + +import ( + "regexp" + "testing" +) + +// TestDetectionPackRegistryShape pins the registry's invariants the +// connectors UI and the ListDetectionPacks RPC depend on: unique IDs, +// known providers, populated names, and semver-shaped versions. A drift +// here would break operator-facing pack pages. +func TestDetectionPackRegistryShape(t *testing.T) { + if len(DetectionPacks) == 0 { + t.Fatal("DetectionPacks must not be empty") + } + knownProviders := map[string]bool{ + "GITHUB": true, + "SLACK": true, + "OKTA": true, + "GOOGLE_WORKSPACE": true, + } + semver := regexp.MustCompile(`^\d+\.\d+\.\d+$`) + seen := map[string]bool{} + for _, pack := range DetectionPacks { + if seen[pack.ID] { + t.Errorf("duplicate pack id %q", pack.ID) + } + seen[pack.ID] = true + if !knownProviders[pack.Provider] { + t.Errorf("pack %q has unknown provider %q", pack.ID, pack.Provider) + } + if pack.Name == "" { + t.Errorf("pack %q missing Name", pack.ID) + } + if pack.Description == "" { + t.Errorf("pack %q missing Description", pack.ID) + } + if !semver.MatchString(pack.Version) { + t.Errorf("pack %q version %q is not semver (MAJOR.MINOR.PATCH)", pack.ID, pack.Version) + } + } +} + +// TestRuleCatalogPackLinkage guarantees that every RuleCatalog entry +// carries pack metadata and that the referenced pack actually exists. +// This also enforces that the rule's provider matches the pack's +// provider, so an operator filtering by provider cannot end up with a +// pack containing a rule from a different SaaS. +func TestRuleCatalogPackLinkage(t *testing.T) { + for _, entry := range RuleCatalog { + if entry.PackID == "" { + t.Errorf("rule %q is missing PackID", entry.ID) + continue + } + pack, ok := DetectionPackByID(entry.PackID) + if !ok { + t.Errorf("rule %q references unknown pack %q", entry.ID, entry.PackID) + continue + } + if pack.Provider != entry.Provider { + t.Errorf("rule %q (provider=%s) is in pack %q (provider=%s)", entry.ID, entry.Provider, pack.ID, pack.Provider) + } + if entry.Intent == "" { + t.Errorf("rule %q is missing Intent", entry.ID) + } + if len(entry.MitreTechniques) == 0 { + t.Errorf("rule %q is missing MitreTechniques", entry.ID) + } + if len(entry.Tags) == 0 { + t.Errorf("rule %q is missing Tags", entry.ID) + } + } +} + +// TestRuleCatalogMitreTechniqueShape pins the MITRE technique id shape +// so an analyst can mechanically cross-reference attack.mitre.org. We +// accept top-level techniques (Txxxx) and one-level sub-techniques +// (Txxxx.yyy). Anything else is almost certainly a typo. +func TestRuleCatalogMitreTechniqueShape(t *testing.T) { + techniqueRE := regexp.MustCompile(`^T\d{4}(\.\d{3})?$`) + for _, entry := range RuleCatalog { + for _, technique := range entry.MitreTechniques { + if !techniqueRE.MatchString(technique) { + t.Errorf("rule %q has malformed MITRE technique %q (want Txxxx or Txxxx.yyy)", entry.ID, technique) + } + } + } +} + +// TestRuleCatalogTagsAreCanonical asserts every catalog Tag is a tag +// the worker actually recognizes. Adding a tag elsewhere without +// registering it in tags.go would silently route findings into an +// orphan bucket the UI cannot filter on. +func TestRuleCatalogTagsAreCanonical(t *testing.T) { + canonical := map[string]bool{} + for _, tag := range AllTags { + canonical[tag] = true + } + for _, entry := range RuleCatalog { + for _, tag := range entry.Tags { + if !canonical[tag] { + t.Errorf("rule %q references non-canonical tag %q (add it to tags.go or use an existing tag)", entry.ID, tag) + } + } + } +} + +// TestRulesInPackPreservesCatalogOrder pins the helper used to render +// each pack's rule list in the UI; alphabetical resort would scramble +// the carefully-chosen display order in RuleCatalog. +func TestRulesInPackPreservesCatalogOrder(t *testing.T) { + gotIDs := []string{} + for _, entry := range RulesInPack("aperio.google_workspace.mail.v1") { + gotIDs = append(gotIDs, entry.ID) + } + if len(gotIDs) == 0 { + t.Fatal("expected at least one rule in the mail pack") + } + wantIDs := []string{} + for _, entry := range RuleCatalog { + if entry.PackID == "aperio.google_workspace.mail.v1" { + wantIDs = append(wantIDs, entry.ID) + } + } + if len(gotIDs) != len(wantIDs) { + t.Fatalf("rules-in-pack length mismatch: got %d want %d", len(gotIDs), len(wantIDs)) + } + for i := range wantIDs { + if gotIDs[i] != wantIDs[i] { + t.Errorf("rules-in-pack order drift at %d: got %s want %s", i, gotIDs[i], wantIDs[i]) + } + } +} + + diff --git a/internal/ingestionworker/rules_catalog.go b/internal/ingestionworker/rules_catalog.go index 4ddaa7bc..1aab8581 100644 --- a/internal/ingestionworker/rules_catalog.go +++ b/internal/ingestionworker/rules_catalog.go @@ -7,145 +7,219 @@ package ingestionworker // rule means: (1) write the evaluator, (2) add it to Evaluate(), (3) add // it to the corresponding supportedIngestionEventTypes provider, (4) add // an entry here so it appears in the UI. +// +// Rules also carry detection-pack metadata so operators can reason about +// coverage in terms of curated, versioned bundles. PackID points into +// DetectionPacks (detection_packs.go); MITRE techniques and intent give +// the SOC immediate context when a finding fires; and Tags is the canon +// cross-provider categorization (see tags.go). type RuleCatalogEntry struct { - ID string - Provider string - Title string - Description string - Severity string - EventTypes []string + ID string + Provider string + Title string + Description string + Severity string + EventTypes []string + PackID string + MitreTechniques []string + Intent string + Tags []string } // RuleCatalog is the registered list of built-in rules. Order is the // display order in the UI. var RuleCatalog = []RuleCatalogEntry{ { - ID: "github.public_repository_created", - Provider: "GITHUB", - Title: "Public GitHub repository created", - Description: "A repository was created or changed to public visibility, which can expose source code, secrets, or customer data.", - Severity: "CRITICAL", - EventTypes: []string{"PUBLIC_REPOSITORY_CREATED", "REPOSITORY_PUBLICIZED"}, - }, - { - ID: "slack.mfa_disabled", - Provider: "SLACK", - Title: "Slack multi-factor authentication disabled", - Description: "A Slack user disabled MFA, increasing the likelihood of account takeover and lateral movement.", - Severity: "CRITICAL", - EventTypes: []string{"MFA_DISABLED", "TWO_FACTOR_AUTH_DISABLED"}, - }, - { - ID: "okta.admin_role_assigned", - Provider: "OKTA", - Title: "Okta admin role assigned", - Description: "A user was granted an Okta administrator role, expanding their tenant-wide privileges.", - Severity: "CRITICAL", - EventTypes: []string{"USER_ACCOUNT_PRIVILEGE_GRANT", "USER_ACCOUNT_PRIVILEGE_GRANTED", "ADMIN_ROLE_ASSIGNED", "ROLE_ASSIGNMENT_CREATED"}, - }, - { - ID: "okta.mfa_factor_reset", - Provider: "OKTA", - Title: "Okta MFA factor reset", - Description: "A user's MFA factors were reset, which can be abused for account-takeover bypass during phishing.", - Severity: "HIGH", - EventTypes: []string{"USER_MFA_FACTOR_RESET", "USER_MFA_FACTOR_RESET_ALL", "MFA_FACTOR_RESET"}, - }, - { - ID: "okta.password_policy_weakened", - Provider: "OKTA", - Title: "Okta password policy weakened", - Description: "An Okta password policy was changed to relax length, complexity, or rotation requirements.", - Severity: "HIGH", - EventTypes: []string{"POLICY_LIFECYCLE_UPDATE", "PASSWORD_POLICY_UPDATED"}, - }, - { - ID: "okta.suspicious_signin", - Provider: "OKTA", - Title: "Okta suspicious sign-in", - Description: "A sign-in matched Okta's suspicious-activity signal (impossible travel, anomalous device, or threat intel hit).", - Severity: "MEDIUM", - EventTypes: []string{"SECURITY_THREAT_DETECTED", "USER_AUTHENTICATION_FAILED", "USER_SESSION_START"}, - }, - { - ID: "google_workspace.external_sharing_enabled", - Provider: "GOOGLE_WORKSPACE", - Title: "Google Drive external sharing enabled", - Description: "A Drive resource was shared outside the tenant domain or set to a public visibility scope.", - Severity: "HIGH", - EventTypes: []string{"EXTERNAL_SHARING_ENABLED"}, - }, - { - ID: "google_workspace.super_admin_granted", - Provider: "GOOGLE_WORKSPACE", - Title: "Google Workspace Super Admin role granted", - Description: "A user was promoted to Super Admin, granting tenant-wide control over Workspace.", - Severity: "CRITICAL", - EventTypes: []string{"SUPER_ADMIN_GRANTED"}, - }, - { - ID: "google_workspace.admin_role_granted", - Provider: "GOOGLE_WORKSPACE", - Title: "Google Workspace admin role granted", - Description: "A user received a delegated administrator role, expanding their tenant privileges.", - Severity: "HIGH", - EventTypes: []string{"ADMIN_ROLE_GRANTED"}, - }, - { - ID: "google_workspace.risky_oauth_grant", - Provider: "GOOGLE_WORKSPACE", - Title: "Risky third-party OAuth grant", - Description: "A third-party OAuth app was authorized with sensitive scopes that broaden tenant data access.", - Severity: "HIGH", - EventTypes: []string{"RISKY_OAUTH_GRANT"}, - }, - { - ID: "google_workspace.admin_mfa_not_enforced", - Provider: "GOOGLE_WORKSPACE", - Title: "Admin MFA enforcement disabled", - Description: "Strong authentication enforcement was disabled for an admin, weakening the privileged-account perimeter.", - Severity: "HIGH", - EventTypes: []string{"ADMIN_MFA_NOT_ENFORCED"}, - }, - { - ID: "google_workspace.admin_external_recovery_email", - Provider: "GOOGLE_WORKSPACE", - Title: "Admin external recovery email set", - Description: "An admin's recovery email was changed to an external domain, creating an out-of-band account-takeover path.", - Severity: "HIGH", - EventTypes: []string{"ADMIN_EXTERNAL_RECOVERY_EMAIL"}, - }, - { - ID: "google_workspace.email_forwarding_enabled", - Provider: "GOOGLE_WORKSPACE", - Title: "Email forwarding enabled", - Description: "Mail forwarding or IMAP was enabled on a mailbox, opening a data-exfiltration channel.", - Severity: "HIGH", - EventTypes: []string{"EMAIL_FORWARDING_ENABLED"}, - }, - { - ID: "google_workspace.mailbox_delegation_granted", - Provider: "GOOGLE_WORKSPACE", - Title: "Mailbox delegation granted", - Description: "Mailbox delegation was granted, letting another account read or send mail on the mailbox owner's behalf.", - Severity: "HIGH", - EventTypes: []string{"MAILBOX_DELEGATION_GRANTED"}, - }, - { - ID: "google_workspace.legacy_mail_auth_used", - Provider: "GOOGLE_WORKSPACE", - Title: "Legacy mail authentication used", - Description: "A legacy IMAP/SMTP authentication path was used, which bypasses modern MFA and risk-based sign-in controls.", - Severity: "HIGH", - EventTypes: []string{"LEGACY_MAIL_AUTH_USED"}, - }, - { - ID: "google_workspace.forwarding_delegate_send_as_combo", - Provider: "GOOGLE_WORKSPACE", - Title: "Forwarding + delegation + send-as combo", - Description: "A mailbox simultaneously has forwarding, delegation, and send-as configured — a classic exfiltration staging pattern.", - Severity: "CRITICAL", - EventTypes: []string{"FORWARDING_DELEGATE_SEND_AS_COMBO"}, + ID: "github.public_repository_created", + Provider: "GITHUB", + Title: "Public GitHub repository created", + Description: "A repository was created or changed to public visibility, which can expose source code, secrets, or customer data.", + Severity: "CRITICAL", + EventTypes: []string{"PUBLIC_REPOSITORY_CREATED", "REPOSITORY_PUBLICIZED"}, + PackID: "aperio.github.core.v1", + MitreTechniques: []string{"T1213"}, + Intent: "Adversary publishes a private repo to exfiltrate source, secrets, or customer data outside the tenant boundary.", + Tags: []string{TagDataPublicExposure}, + }, + { + ID: "slack.mfa_disabled", + Provider: "SLACK", + Title: "Slack multi-factor authentication disabled", + Description: "A Slack user disabled MFA, increasing the likelihood of account takeover and lateral movement.", + Severity: "CRITICAL", + EventTypes: []string{"MFA_DISABLED", "TWO_FACTOR_AUTH_DISABLED"}, + PackID: "aperio.slack.core.v1", + MitreTechniques: []string{"T1556.006"}, + Intent: "Adversary or compromised insider weakens the account's auth posture to maintain access without triggering MFA prompts.", + Tags: []string{TagAuthMFAWeakened}, + }, + { + ID: "okta.admin_role_assigned", + Provider: "OKTA", + Title: "Okta admin role assigned", + Description: "A user was granted an Okta administrator role, expanding their tenant-wide privileges.", + Severity: "CRITICAL", + EventTypes: []string{"USER_ACCOUNT_PRIVILEGE_GRANT", "USER_ACCOUNT_PRIVILEGE_GRANTED", "ADMIN_ROLE_ASSIGNED", "ROLE_ASSIGNMENT_CREATED"}, + PackID: "aperio.okta.core.v1", + MitreTechniques: []string{"T1098.003"}, + Intent: "Adversary promotes an attacker-controlled identity to administrator to persist and broaden access across the tenant.", + Tags: []string{TagIAMPrivilegeEscalation}, + }, + { + ID: "okta.mfa_factor_reset", + Provider: "OKTA", + Title: "Okta MFA factor reset", + Description: "A user's MFA factors were reset, which can be abused for account-takeover bypass during phishing.", + Severity: "HIGH", + EventTypes: []string{"USER_MFA_FACTOR_RESET", "USER_MFA_FACTOR_RESET_ALL", "MFA_FACTOR_RESET"}, + PackID: "aperio.okta.core.v1", + MitreTechniques: []string{"T1556.006"}, + Intent: "Adversary clears MFA factors so the next sign-in can enroll an attacker-controlled device.", + Tags: []string{TagAuthMFAWeakened}, + }, + { + ID: "okta.password_policy_weakened", + Provider: "OKTA", + Title: "Okta password policy weakened", + Description: "An Okta password policy was changed to relax length, complexity, or rotation requirements.", + Severity: "HIGH", + EventTypes: []string{"POLICY_LIFECYCLE_UPDATE", "PASSWORD_POLICY_UPDATED"}, + PackID: "aperio.okta.core.v1", + MitreTechniques: []string{"T1556"}, + Intent: "Adversary reduces password strength requirements to make brute-force and credential stuffing viable.", + Tags: []string{TagAuthPassword, TagPolicyWeakened}, + }, + { + ID: "okta.suspicious_signin", + Provider: "OKTA", + Title: "Okta suspicious sign-in", + Description: "A sign-in matched Okta's suspicious-activity signal (impossible travel, anomalous device, or threat intel hit).", + Severity: "MEDIUM", + EventTypes: []string{"SECURITY_THREAT_DETECTED", "USER_AUTHENTICATION_FAILED", "USER_SESSION_START"}, + PackID: "aperio.okta.core.v1", + MitreTechniques: []string{"T1078.004"}, + Intent: "Adversary attempts to ride a compromised credential into the tenant using an anomalous device or location.", + Tags: []string{TagAuthSuspiciousLogin}, + }, + { + ID: "google_workspace.external_sharing_enabled", + Provider: "GOOGLE_WORKSPACE", + Title: "Google Drive external sharing enabled", + Description: "A Drive resource was shared outside the tenant domain or set to a public visibility scope.", + Severity: "HIGH", + EventTypes: []string{"EXTERNAL_SHARING_ENABLED"}, + PackID: "aperio.google_workspace.drive.v1", + MitreTechniques: []string{"T1530"}, + Intent: "Adversary or insider expands a Drive resource's audience to exfiltrate it through legitimate-looking sharing links.", + Tags: []string{TagDataExternalShare}, + }, + { + ID: "google_workspace.super_admin_granted", + Provider: "GOOGLE_WORKSPACE", + Title: "Google Workspace Super Admin role granted", + Description: "A user was promoted to Super Admin, granting tenant-wide control over Workspace.", + Severity: "CRITICAL", + EventTypes: []string{"SUPER_ADMIN_GRANTED"}, + PackID: "aperio.google_workspace.identity.v1", + MitreTechniques: []string{"T1098.003"}, + Intent: "Adversary obtains the highest Workspace role to persist, disable controls, and reach any tenant data.", + Tags: []string{TagIAMPrivilegeEscalation}, + }, + { + ID: "google_workspace.admin_role_granted", + Provider: "GOOGLE_WORKSPACE", + Title: "Google Workspace admin role granted", + Description: "A user received a delegated administrator role, expanding their tenant privileges.", + Severity: "HIGH", + EventTypes: []string{"ADMIN_ROLE_GRANTED"}, + PackID: "aperio.google_workspace.identity.v1", + MitreTechniques: []string{"T1098.003"}, + Intent: "Adversary expands a foothold by granting an attacker-controlled account a delegated admin role.", + Tags: []string{TagIAMPrivilegeEscalation}, + }, + { + ID: "google_workspace.risky_oauth_grant", + Provider: "GOOGLE_WORKSPACE", + Title: "Risky third-party OAuth grant", + Description: "A third-party OAuth app was authorized with sensitive scopes that broaden tenant data access.", + Severity: "HIGH", + EventTypes: []string{"RISKY_OAUTH_GRANT"}, + PackID: "aperio.google_workspace.drive.v1", + MitreTechniques: []string{"T1550.001", "T1528"}, + Intent: "Adversary tricks a user into authorizing an OAuth app that grants long-lived access to mail and drive data.", + Tags: []string{TagOAuthRiskyGrant}, + }, + { + ID: "google_workspace.admin_mfa_not_enforced", + Provider: "GOOGLE_WORKSPACE", + Title: "Admin MFA enforcement disabled", + Description: "Strong authentication enforcement was disabled for an admin, weakening the privileged-account perimeter.", + Severity: "HIGH", + EventTypes: []string{"ADMIN_MFA_NOT_ENFORCED"}, + PackID: "aperio.google_workspace.identity.v1", + MitreTechniques: []string{"T1556.006"}, + Intent: "Adversary weakens the admin auth posture to keep stolen credentials viable across sessions.", + Tags: []string{TagAuthMFAWeakened, TagPolicyWeakened}, + }, + { + ID: "google_workspace.admin_external_recovery_email", + Provider: "GOOGLE_WORKSPACE", + Title: "Admin external recovery email set", + Description: "An admin's recovery email was changed to an external domain, creating an out-of-band account-takeover path.", + Severity: "HIGH", + EventTypes: []string{"ADMIN_EXTERNAL_RECOVERY_EMAIL"}, + PackID: "aperio.google_workspace.identity.v1", + MitreTechniques: []string{"T1556.003"}, + Intent: "Adversary stages an off-tenant recovery path so a future password reset hands them the admin account.", + Tags: []string{TagAuthAccountRecovery}, + }, + { + ID: "google_workspace.email_forwarding_enabled", + Provider: "GOOGLE_WORKSPACE", + Title: "Email forwarding enabled", + Description: "Mail forwarding or IMAP was enabled on a mailbox, opening a data-exfiltration channel.", + Severity: "HIGH", + EventTypes: []string{"EMAIL_FORWARDING_ENABLED"}, + PackID: "aperio.google_workspace.mail.v1", + MitreTechniques: []string{"T1114.003"}, + Intent: "Adversary auto-forwards mailbox contents to an attacker-controlled address to silently exfiltrate mail.", + Tags: []string{TagEmailForwarding}, + }, + { + ID: "google_workspace.mailbox_delegation_granted", + Provider: "GOOGLE_WORKSPACE", + Title: "Mailbox delegation granted", + Description: "Mailbox delegation was granted, letting another account read or send mail on the mailbox owner's behalf.", + Severity: "HIGH", + EventTypes: []string{"MAILBOX_DELEGATION_GRANTED"}, + PackID: "aperio.google_workspace.mail.v1", + MitreTechniques: []string{"T1098.002"}, + Intent: "Adversary persists access to the mailbox by delegating it to an attacker-controlled account.", + Tags: []string{TagEmailDelegation}, + }, + { + ID: "google_workspace.legacy_mail_auth_used", + Provider: "GOOGLE_WORKSPACE", + Title: "Legacy mail authentication used", + Description: "A legacy IMAP/SMTP authentication path was used, which bypasses modern MFA and risk-based sign-in controls.", + Severity: "HIGH", + EventTypes: []string{"LEGACY_MAIL_AUTH_USED"}, + PackID: "aperio.google_workspace.mail.v1", + MitreTechniques: []string{"T1078.004", "T1556.006"}, + Intent: "Adversary rides a legacy protocol that does not enforce MFA, often after harvesting an app password.", + Tags: []string{TagAuthLegacyProtocol}, + }, + { + ID: "google_workspace.forwarding_delegate_send_as_combo", + Provider: "GOOGLE_WORKSPACE", + Title: "Forwarding + delegation + send-as combo", + Description: "A mailbox simultaneously has forwarding, delegation, and send-as configured, a classic exfiltration staging pattern.", + Severity: "CRITICAL", + EventTypes: []string{"FORWARDING_DELEGATE_SEND_AS_COMBO"}, + PackID: "aperio.google_workspace.mail.v1", + MitreTechniques: []string{"T1114.003", "T1098.002"}, + Intent: "Adversary stages a multi-vector mailbox takeover that survives password rotation and silently routes mail outbound.", + Tags: []string{TagEmailForwarding, TagEmailDelegation}, }, } diff --git a/packages/connect/src/client.ts b/packages/connect/src/client.ts index 12ad292a..e934199f 100644 --- a/packages/connect/src/client.ts +++ b/packages/connect/src/client.ts @@ -12,6 +12,8 @@ import { type CerebroMCPContext as ProtoCerebroMCPContext, type CerebroMCPResourceTemplate as ProtoCerebroMCPResourceTemplate, type ConnectorDefinition as ProtoConnectorDefinition, + type DetectionPack as ProtoDetectionPack, + type DetectionPackRule as ProtoDetectionPackRule, type EmailDomainDkimSelector as ProtoEmailDomainDkimSelector, type EmailDomainHealth as ProtoEmailDomainHealth, type EmailDomainHealthDetail as ProtoEmailDomainHealthDetail, @@ -388,6 +390,26 @@ export type ConnectIntegrationOAuthClient = { updatedAt: string | null; }; +export type ConnectDetectionPackRule = { + id: string; + title: string; + description: string; + severity: string; + eventTypes: string[]; + mitreTechniques: string[]; + intent: string; + tags: string[]; +}; + +export type ConnectDetectionPack = { + id: string; + provider: string; + name: string; + description: string; + version: string; + rules: ConnectDetectionPackRule[]; +}; + export type ConnectConnectorDefinition = { provider: ConnectProvider; name: string; @@ -1672,6 +1694,34 @@ function integrationFromProto( }; } +function detectionPackRuleFromProto( + rule: ProtoDetectionPackRule +): ConnectDetectionPackRule { + return { + id: rule.id, + title: rule.title, + description: rule.description, + severity: rule.severity, + eventTypes: [...rule.eventTypes], + mitreTechniques: [...rule.mitreTechniques], + intent: rule.intent, + tags: [...rule.tags] + }; +} + +function detectionPackFromProto( + pack: ProtoDetectionPack +): ConnectDetectionPack { + return { + id: pack.id, + provider: pack.provider, + name: pack.name, + description: pack.description, + version: pack.version, + rules: pack.rules.map(detectionPackRuleFromProto) + }; +} + function connectorDefinitionFromProto( definition: ProtoConnectorDefinition ): ConnectConnectorDefinition { @@ -2622,6 +2672,14 @@ export const aperioConnectClient = { const response = await client.listConnectorCatalog({}); return { data: response.data.map(connectorDefinitionFromProto) }; }, + async listDetectionPacks( + filters?: { provider?: string } + ): Promise<{ data: ConnectDetectionPack[] }> { + const response = await client.listDetectionPacks({ + provider: filters?.provider ?? "" + }); + return { data: response.data.map(detectionPackFromProto) }; + }, async listIntegrations(): Promise<{ data: ConnectIntegrationConnection[] }> { const response = await client.listIntegrations({}); return { data: response.data.map(integrationFromProto) }; diff --git a/packages/connect/src/gen/aperio/v1/api_pb.ts b/packages/connect/src/gen/aperio/v1/api_pb.ts index 0eee326b..bf992c60 100644 --- a/packages/connect/src/gen/aperio/v1/api_pb.ts +++ b/packages/connect/src/gen/aperio/v1/api_pb.ts @@ -12,7 +12,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file aperio/v1/api.proto. */ export const file_aperio_v1_api: GenFile = /*@__PURE__*/ - fileDesc("ChNhcGVyaW8vdjEvYXBpLnByb3RvEglhcGVyaW8udjEiQQoOQ2FsbEFwaVJlcXVlc3QSDgoGbWV0aG9kGAEgASgJEgwKBHBhdGgYAiABKAkSEQoJYm9keV9qc29uGAMgASgJIiQKD0NhbGxBcGlSZXNwb25zZRIRCglib2R5X2pzb24YASABKAkipAEKDVNpZ251cFJlcXVlc3QSGQoRb3JnYW5pemF0aW9uX25hbWUYASABKAkSGQoRb3JnYW5pemF0aW9uX3NsdWcYAiABKAkSGgoSbm90aWZpY2F0aW9uX2VtYWlsGAMgASgJEhMKC293bmVyX2VtYWlsGAQgASgJEhoKEm93bmVyX2Rpc3BsYXlfbmFtZRgFIAEoCRIQCghwYXNzd29yZBgGIAEoCSI2Cg5TaWdudXBSZXNwb25zZRIkCgRkYXRhGAEgASgLMhYuYXBlcmlvLnYxLkF1dGhTZXNzaW9uIl0KDExvZ2luUmVxdWVzdBIZChFvcmdhbml6YXRpb25fc2x1ZxgBIAEoCRINCgVlbWFpbBgCIAEoCRIQCghwYXNzd29yZBgDIAEoCRIRCgl0b3RwX2NvZGUYBCABKAkiNQoNTG9naW5SZXNwb25zZRIkCgRkYXRhGAEgASgLMhYuYXBlcmlvLnYxLkF1dGhTZXNzaW9uIhoKGEdldEN1cnJlbnRTZXNzaW9uUmVxdWVzdCJBChlHZXRDdXJyZW50U2Vzc2lvblJlc3BvbnNlEiQKBGRhdGEYASABKAsyFi5hcGVyaW8udjEuQXV0aFNlc3Npb24iHQobTG9nb3V0Q3VycmVudFNlc3Npb25SZXF1ZXN0IkUKHExvZ291dEN1cnJlbnRTZXNzaW9uUmVzcG9uc2USJQoEZGF0YRgBIAEoCzIXLmFwZXJpby52MS5EZWxldGVSZXN1bHQiFwoVTGlzdFdvcmtzcGFjZXNSZXF1ZXN0IkYKFkxpc3RXb3Jrc3BhY2VzUmVzcG9uc2USLAoEZGF0YRgBIAMoCzIeLmFwZXJpby52MS5Xb3Jrc3BhY2VNZW1iZXJzaGlwIlgKFlN3aXRjaFdvcmtzcGFjZVJlcXVlc3QSGQoRb3JnYW5pemF0aW9uX3NsdWcYASABKAkSEQoJdG90cF9jb2RlGAIgASgJEhAKCHBhc3N3b3JkGAMgASgJIj8KF1N3aXRjaFdvcmtzcGFjZVJlc3BvbnNlEiQKBGRhdGEYASABKAsyFi5hcGVyaW8udjEuQXV0aFNlc3Npb24iRwobUmVxdWVzdFBhc3N3b3JkUmVzZXRSZXF1ZXN0EhkKEW9yZ2FuaXphdGlvbl9zbHVnGAEgASgJEg0KBWVtYWlsGAIgASgJIkwKHFJlcXVlc3RQYXNzd29yZFJlc2V0UmVzcG9uc2USLAoEZGF0YRgBIAEoCzIeLmFwZXJpby52MS5QYXNzd29yZFJlc2V0UmVzdWx0IjcKFFJlc2V0UGFzc3dvcmRSZXF1ZXN0Eg0KBXRva2VuGAEgASgJEhAKCHBhc3N3b3JkGAIgASgJIj0KFVJlc2V0UGFzc3dvcmRSZXNwb25zZRIkCgRkYXRhGAEgASgLMhYuYXBlcmlvLnYxLkF1dGhTZXNzaW9uIkwKE0FjY2VwdEludml0ZVJlcXVlc3QSDQoFdG9rZW4YASABKAkSFAoMZGlzcGxheV9uYW1lGAIgASgJEhAKCHBhc3N3b3JkGAMgASgJIjwKFEFjY2VwdEludml0ZVJlc3BvbnNlEiQKBGRhdGEYASABKAsyFi5hcGVyaW8udjEuQXV0aFNlc3Npb24iGwoZQmVnaW5NZmFFbnJvbGxtZW50UmVxdWVzdCJEChpCZWdpbk1mYUVucm9sbG1lbnRSZXNwb25zZRImCgRkYXRhGAEgASgLMhguYXBlcmlvLnYxLk1mYUVucm9sbG1lbnQiIAoQRW5hYmxlTWZhUmVxdWVzdBIMCgRjb2RlGAEgASgJIjkKEUVuYWJsZU1mYVJlc3BvbnNlEiQKBGRhdGEYASABKAsyFi5hcGVyaW8udjEuQXV0aFNlc3Npb24iMwoRRGlzYWJsZU1mYVJlcXVlc3QSEAoIcGFzc3dvcmQYASABKAkSDAoEY29kZRgCIAEoCSI6ChJEaXNhYmxlTWZhUmVzcG9uc2USJAoEZGF0YRgBIAEoCzIWLmFwZXJpby52MS5BdXRoU2Vzc2lvbiKgAQoLQXV0aFNlc3Npb24SDQoFdG9rZW4YASABKAkSIQoEdXNlchgCIAEoCzITLmFwZXJpby52MS5BdXRoVXNlchIxCgxvcmdhbml6YXRpb24YAyABKAsyGy5hcGVyaW8udjEuQXV0aE9yZ2FuaXphdGlvbhIsCgxhdXRoX2NvbnRleHQYBCABKAsyFi5hcGVyaW8udjEuQXV0aENvbnRleHQiXgoIQXV0aFVzZXISCgoCaWQYASABKAkSDQoFZW1haWwYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJEhMKC21mYV9lbmFibGVkGAQgASgIEgwKBHJvbGUYBSABKAkiOgoQQXV0aE9yZ2FuaXphdGlvbhIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEgwKBHNsdWcYAyABKAkisQMKC0F1dGhDb250ZXh0EhEKCXByaW5jaXBhbBgBIAEoCRIRCgl0ZW5hbnRfaWQYAiABKAkSEwoLdGVuYW50X3NsdWcYAyABKAkSFwoPY3JlZGVudGlhbF9raW5kGAQgASgJEhEKCWF1dGhfbW9kZRgFIAEoCRIXCg90b2tlbl90cmFuc3BvcnQYBiABKAkSGAoQY2VyZWJyb19yZXNvdXJjZRgHIAEoCRIXCg9hbGxvd2VkX3RlbmFudHMYCCADKAkSFgoOY2VyZWJyb19zY29wZXMYCSADKAkSDgoGZ3JvdXBzGAogAygJEhwKFGNlcmVicm9fbWNwX3Jlc291cmNlGAsgASgJEioKImNlcmVicm9fbWNwX3Jlc291cmNlX21ldGFkYXRhX3BhdGgYDCABKAkSOAowY2VyZWJyb19vYXV0aF9hdXRob3JpemF0aW9uX3NlcnZlcl9tZXRhZGF0YV9wYXRoGA0gASgJEh8KF2NlcmVicm9fbWNwX2dyYW50X3R5cGVzGA4gAygJEiIKGmNlcmVicm9fbWNwX2JlYXJlcl9tZXRob2RzGA8gAygJIlwKE1dvcmtzcGFjZU1lbWJlcnNoaXASCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRIMCgRzbHVnGAMgASgJEgwKBHJvbGUYBCABKAkSDwoHY3VycmVudBgFIAEoCCJ7ChNQYXNzd29yZFJlc2V0UmVzdWx0EhAKCGFjY2VwdGVkGAEgASgIEhAKCGRlbGl2ZXJ5GAIgASgJEhEKCXJlc2V0X3VybBgDIAEoCRISCgpleHBpcmVzX2F0GAQgASgJEhkKEW9yZ2FuaXphdGlvbl9uYW1lGAUgASgJIjQKDU1mYUVucm9sbG1lbnQSDgoGc2VjcmV0GAEgASgJEhMKC290cGF1dGhfdXJsGAIgASgJIhQKEkNoZWNrSGVhbHRoUmVxdWVzdCKWAQoTQ2hlY2tIZWFsdGhSZXNwb25zZRIOCgZzdGF0dXMYASABKAkSDwoHc2VydmljZRgCIAEoCRIuCgpjaGVja2VkX2F0GAMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIuCgpjb21wb25lbnRzGAQgAygLMhouYXBlcmlvLnYxLkhlYWx0aENvbXBvbmVudCI/Cg9IZWFsdGhDb21wb25lbnQSDAoEbmFtZRgBIAEoCRIOCgZzdGF0dXMYAiABKAkSDgoGZGV0YWlsGAMgASgJIhwKGkdldERhc2hib2FyZE1ldHJpY3NSZXF1ZXN0IkgKG0dldERhc2hib2FyZE1ldHJpY3NSZXNwb25zZRIpCgRkYXRhGAEgASgLMhsuYXBlcmlvLnYxLkRhc2hib2FyZE1ldHJpY3MiggEKEERhc2hib2FyZE1ldHJpY3MSGAoQdG90YWxfcmlza19zY29yZRgBIAEoBRIeChZvcGVuX2NyaXRpY2FsX2ZpbmRpbmdzGAIgASgFEhYKDmNvbm5lY3RlZF9hcHBzGAMgASgFEhwKFGV2ZW50X2luZ2VzdGlvbl9yYXRlGAQgASgFIoABChNMaXN0RmluZGluZ3NSZXF1ZXN0EhAKCHNldmVyaXR5GAEgASgJEg4KBnN0YXR1cxgCIAEoCRIQCghwcm92aWRlchgDIAEoCRIWCg5pbnRlZ3JhdGlvbl9pZBgEIAEoCRINCgVsaW1pdBgFIAEoBRIOCgZjdXJzb3IYBiABKAkiYAoUTGlzdEZpbmRpbmdzUmVzcG9uc2USIAoEZGF0YRgBIAMoCzISLmFwZXJpby52MS5GaW5kaW5nEiYKCXBhZ2VfaW5mbxgCIAEoCzITLmFwZXJpby52MS5QYWdlSW5mbyIfChFHZXRGaW5kaW5nUmVxdWVzdBIKCgJpZBgBIAEoCSI2ChJHZXRGaW5kaW5nUmVzcG9uc2USIAoEZGF0YRgBIAEoCzISLmFwZXJpby52MS5GaW5kaW5nIlEKGlVwZGF0ZUZpbmRpbmdTdGF0dXNSZXF1ZXN0EgoKAmlkGAEgASgJEg4KBnN0YXR1cxgCIAEoCRIXCg9yZXNvbHV0aW9uX25vdGUYAyABKAkiSwobVXBkYXRlRmluZGluZ1N0YXR1c1Jlc3BvbnNlEiwKBGRhdGEYASABKAsyHi5hcGVyaW8udjEuRmluZGluZ1N0YXR1c1VwZGF0ZSIxChNGaW5kaW5nU3RhdHVzVXBkYXRlEgoKAmlkGAEgASgJEg4KBnN0YXR1cxgCIAEoCSJmChdSZW1lZGlhdGVGaW5kaW5nUmVxdWVzdBISCgpmaW5kaW5nX2lkGAEgASgJEg4KBmFjdGlvbhgCIAEoCRIZChF0YXJnZXRfaWRlbnRpZmllchgDIAEoCRIMCgRub3RlGAQgASgJIkYKGFJlbWVkaWF0ZUZpbmRpbmdSZXNwb25zZRIqCgRkYXRhGAEgASgLMhwuYXBlcmlvLnYxLlJlbWVkaWF0aW9uUmVzdWx0IocBChFSZW1lZGlhdGlvblJlc3VsdBISCgpmaW5kaW5nX2lkGAEgASgJEg4KBmFjdGlvbhgCIAEoCRIPCgdzdWNjZXNzGAMgASgIEg8KB21lc3NhZ2UYBCABKAkSGwoTcHJvdmlkZXJfcmVxdWVzdF9pZBgFIAEoCRIPCgdlZmZlY3RzGAYgAygJItoCCgdGaW5kaW5nEgoKAmlkGAEgASgJEhAKCGFzc2V0X2lkGAIgASgJEg0KBXRpdGxlGAMgASgJEhMKC2Rlc2NyaXB0aW9uGAQgASgJEhAKCHNldmVyaXR5GAUgASgJEg4KBnN0YXR1cxgGIAEoCRISCgpyaXNrX3Njb3JlGAcgASgFEhkKEXJlbWVkaWF0aW9uX3N0ZXBzGAggAygJEhUKDWV2aWRlbmNlX2pzb24YCSABKAkSEwoLZGV0ZWN0ZWRfYXQYCiABKAkSEwoLcmVzb2x2ZWRfYXQYCyABKAkSMgoLaW50ZWdyYXRpb24YDCABKAsyHS5hcGVyaW8udjEuRmluZGluZ0ludGVncmF0aW9uEgwKBHRhZ3MYDSADKAkSOQoPY2VyZWJyb19jb250ZXh0GA4gASgLMiAuYXBlcmlvLnYxLkZpbmRpbmdDZXJlYnJvQ29udGV4dCJIChJGaW5kaW5nSW50ZWdyYXRpb24SCgoCaWQYASABKAkSEAoIcHJvdmlkZXIYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJIqsDChVGaW5kaW5nQ2VyZWJyb0NvbnRleHQSDgoGc291cmNlGAEgASgJEgwKBG1vZGUYAiABKAkSGQoRc291cmNlX3J1bnRpbWVfaWQYAyABKAkSGAoQZmluZGluZ19jb250cmFjdBgEIAEoCRIXCg9zb3VyY2VfZXZlbnRfaWQYBSABKAkSEwoLY2xhaW1fY291bnQYBiABKAUSNwoPY2xhaW1fc3VtbWFyaWVzGAcgAygLMh4uYXBlcmlvLnYxLkNlcmVicm9DbGFpbVN1bW1hcnkSNAoNZ3JhcGhfc2lnbmFscxgIIAMoCzIdLmFwZXJpby52MS5DZXJlYnJvR3JhcGhTaWduYWwSLQoIZW50aXRpZXMYCSADKAsyGy5hcGVyaW8udjEuQ2VyZWJyb0VudGl0eVJlZhIwCgtncmFwaF9wYXRocxgKIAMoCzIbLmFwZXJpby52MS5DZXJlYnJvR3JhcGhQYXRoEikKA21jcBgLIAEoCzIcLmFwZXJpby52MS5DZXJlYnJvTUNQQ29udGV4dBIWCg5yZXNwb25zZV9oaW50cxgMIAMoCSJ7ChNDZXJlYnJvQ2xhaW1TdW1tYXJ5EhIKCmNsYWltX3R5cGUYASABKAkSEQoJcHJlZGljYXRlGAIgASgJEhMKC3N1YmplY3RfdXJuGAMgASgJEhIKCm9iamVjdF91cm4YBCABKAkSFAoMc291cmNlX2V2ZW50GAUgASgJInAKEkNlcmVicm9HcmFwaFNpZ25hbBINCgVsYWJlbBgBIAEoCRIRCglwcmVkaWNhdGUYAiABKAkSEgoKY29uZmlkZW5jZRgDIAEoBRISCgplbnRpdHlfdXJuGAQgASgJEhAKCGV2aWRlbmNlGAUgASgJIk4KEENlcmVicm9FbnRpdHlSZWYSCwoDdXJuGAEgASgJEgwKBHR5cGUYAiABKAkSDQoFbGFiZWwYAyABKAkSEAoIcHJvdmlkZXIYBCABKAkiZwoQQ2VyZWJyb0dyYXBoUGF0aBIKCgJpZBgBIAEoCRINCgV0aXRsZRgCIAEoCRIMCgRyaXNrGAMgASgJEioKBW5vZGVzGAQgAygLMhsuYXBlcmlvLnYxLkNlcmVicm9FbnRpdHlSZWYingEKEUNlcmVicm9NQ1BDb250ZXh0Eg4KBnNlcnZlchgBIAEoCRIUCgxyZXNvdXJjZV91cmkYAiABKAkSEQoJbWltZV90eXBlGAMgASgJEg0KBXRvb2xzGAQgAygJEkEKEnJlc291cmNlX3RlbXBsYXRlcxgFIAMoCzIlLmFwZXJpby52MS5DZXJlYnJvTUNQUmVzb3VyY2VUZW1wbGF0ZSJoChpDZXJlYnJvTUNQUmVzb3VyY2VUZW1wbGF0ZRIUCgx1cmlfdGVtcGxhdGUYASABKAkSDAoEbmFtZRgCIAEoCRITCgtkZXNjcmlwdGlvbhgDIAEoCRIRCgltaW1lX3R5cGUYBCABKAkidQoYTGlzdFNhYXNJbmNpZGVudHNSZXF1ZXN0Eg4KBnN0YXR1cxgBIAEoCRIQCghzZXZlcml0eRgCIAEoCRIYChBhc3NpZ25lZV91c2VyX2lkGAMgASgJEg0KBWxpbWl0GAQgASgFEg4KBmN1cnNvchgFIAEoCSKbAQoZTGlzdFNhYXNJbmNpZGVudHNSZXNwb25zZRIlCgRkYXRhGAEgAygLMhcuYXBlcmlvLnYxLlNhYXNJbmNpZGVudBImCglwYWdlX2luZm8YAiABKAsyEy5hcGVyaW8udjEuUGFnZUluZm8SLwoHbWV0cmljcxgDIAEoCzIeLmFwZXJpby52MS5TYWFzSW5jaWRlbnRNZXRyaWNzIiQKFkdldFNhYXNJbmNpZGVudFJlcXVlc3QSCgoCaWQYASABKAkiRgoXR2V0U2Fhc0luY2lkZW50UmVzcG9uc2USKwoEZGF0YRgBIAEoCzIdLmFwZXJpby52MS5TYWFzSW5jaWRlbnREZXRhaWwikAEKGUNyZWF0ZVNhYXNJbmNpZGVudFJlcXVlc3QSDQoFdGl0bGUYASABKAkSDwoHc3VtbWFyeRgCIAEoCRIQCghzZXZlcml0eRgDIAEoCRITCgtmaW5kaW5nX2lkcxgEIAMoCRISCgpvd25lcl90ZWFtGAUgASgJEhgKEGFzc2lnbmVlX3VzZXJfaWQYBiABKAkiSQoaQ3JlYXRlU2Fhc0luY2lkZW50UmVzcG9uc2USKwoEZGF0YRgBIAEoCzIdLmFwZXJpby52MS5TYWFzSW5jaWRlbnREZXRhaWwiSwofVXBkYXRlU2Fhc0luY2lkZW50U3RhdHVzUmVxdWVzdBIKCgJpZBgBIAEoCRIOCgZzdGF0dXMYAiABKAkSDAoEbm90ZRgDIAEoCSJJCiBVcGRhdGVTYWFzSW5jaWRlbnRTdGF0dXNSZXNwb25zZRIlCgRkYXRhGAEgASgLMhcuYXBlcmlvLnYxLlNhYXNJbmNpZGVudCLmAQogUHJvcG9zZVNhYXNSZXNwb25zZUFjdGlvblJlcXVlc3QSEwoLaW5jaWRlbnRfaWQYASABKAkSEgoKZmluZGluZ19pZBgCIAEoCRIOCgZhY3Rpb24YAyABKAkSEAoIcHJvdmlkZXIYBCABKAkSEwoLdGFyZ2V0X3R5cGUYBSABKAkSGQoRdGFyZ2V0X2lkZW50aWZpZXIYBiABKAkSEQoJcmF0aW9uYWxlGAcgASgJEh4KEWFwcHJvdmFsX3JlcXVpcmVkGAggASgISACIAQFCFAoSX2FwcHJvdmFsX3JlcXVpcmVkIlAKIVByb3Bvc2VTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRIrCgRkYXRhGAEgASgLMh0uYXBlcmlvLnYxLlNhYXNSZXNwb25zZUFjdGlvbiI8CiBBcHByb3ZlU2Fhc1Jlc3BvbnNlQWN0aW9uUmVxdWVzdBIKCgJpZBgBIAEoCRIMCgRub3RlGAIgASgJIlAKIUFwcHJvdmVTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRIrCgRkYXRhGAEgASgLMh0uYXBlcmlvLnYxLlNhYXNSZXNwb25zZUFjdGlvbiI8CiBFeGVjdXRlU2Fhc1Jlc3BvbnNlQWN0aW9uUmVxdWVzdBIKCgJpZBgBIAEoCRIMCgRub3RlGAIgASgJIlAKIUV4ZWN1dGVTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRIrCgRkYXRhGAEgASgLMh0uYXBlcmlvLnYxLlNhYXNSZXNwb25zZUFjdGlvbiKYAQoTU2Fhc0luY2lkZW50TWV0cmljcxIMCgRvcGVuGAEgASgFEhUKDWludmVzdGlnYXRpbmcYAiABKAUSEQoJY29udGFpbmVkGAMgASgFEhAKCHJlc29sdmVkGAQgASgFEhUKDWNyaXRpY2FsX29wZW4YBSABKAUSIAoYcmVzcG9uc2VfYWN0aW9uc19wZW5kaW5nGAYgASgFItkDCgxTYWFzSW5jaWRlbnQSCgoCaWQYASABKAkSDQoFdGl0bGUYAiABKAkSDwoHc3VtbWFyeRgDIAEoCRIQCghzZXZlcml0eRgEIAEoCRIOCgZzdGF0dXMYBSABKAkSGAoQY29uZmlkZW5jZV9zY29yZRgGIAEoBRISCgpvd25lcl90ZWFtGAcgASgJEi4KCGFzc2lnbmVlGAggASgLMhwuYXBlcmlvLnYxLlNlY3VyaXR5UHJpbmNpcGFsEhkKEWZpcnN0X2RldGVjdGVkX2F0GAkgASgJEhgKEGxhc3RfYWN0aXZpdHlfYXQYCiABKAkSEgoKc2xhX2R1ZV9hdBgLIAEoCRITCgtyZXNvbHZlZF9hdBgMIAEoCRIcChRjZXJlYnJvX2NvbnRleHRfanNvbhgNIAEoCRISCgpjcmVhdGVkX2F0GA4gASgJEhIKCnVwZGF0ZWRfYXQYDyABKAkSFQoNZmluZGluZ19jb3VudBgQIAEoBRIaChJvcGVuX2ZpbmRpbmdfY291bnQYESABKAUSHQoVcmVzcG9uc2VfYWN0aW9uX2NvdW50GBIgASgFEicKH2NvbXBsZXRlZF9yZXNwb25zZV9hY3Rpb25fY291bnQYEyABKAUi1gEKElNhYXNJbmNpZGVudERldGFpbBIpCghpbmNpZGVudBgBIAEoCzIXLmFwZXJpby52MS5TYWFzSW5jaWRlbnQSJAoIZmluZGluZ3MYAiADKAsyEi5hcGVyaW8udjEuRmluZGluZxI2Cgh0aW1lbGluZRgDIAMoCzIkLmFwZXJpby52MS5TYWFzSW5jaWRlbnRUaW1lbGluZUV2ZW50EjcKEHJlc3BvbnNlX2FjdGlvbnMYBCADKAsyHS5hcGVyaW8udjEuU2Fhc1Jlc3BvbnNlQWN0aW9uIv0BChlTYWFzSW5jaWRlbnRUaW1lbGluZUV2ZW50EgoKAmlkGAEgASgJEhMKC2luY2lkZW50X2lkGAIgASgJEhIKCmZpbmRpbmdfaWQYAyABKAkSGgoScmVzcG9uc2VfYWN0aW9uX2lkGAQgASgJEgwKBGtpbmQYBSABKAkSDQoFdGl0bGUYBiABKAkSEwoLZGVzY3JpcHRpb24YByABKAkSDQoFYWN0b3IYCCABKAkSDgoGc291cmNlGAkgASgJEhUKDWV2aWRlbmNlX2pzb24YCiABKAkSEwoLb2NjdXJyZWRfYXQYCyABKAkSEgoKY3JlYXRlZF9hdBgMIAEoCSLwAwoSU2Fhc1Jlc3BvbnNlQWN0aW9uEgoKAmlkGAEgASgJEhMKC2luY2lkZW50X2lkGAIgASgJEhIKCmZpbmRpbmdfaWQYAyABKAkSDgoGYWN0aW9uGAQgASgJEhAKCHByb3ZpZGVyGAUgASgJEhMKC3RhcmdldF90eXBlGAYgASgJEhkKEXRhcmdldF9pZGVudGlmaWVyGAcgASgJEg4KBnN0YXR1cxgIIAEoCRIZChFhcHByb3ZhbF9yZXF1aXJlZBgJIAEoCBIRCglyYXRpb25hbGUYCiABKAkSMQoLYXBwcm92ZWRfYnkYCyABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwSEwoLYXBwcm92ZWRfYXQYDCABKAkSEwoLZXhlY3V0ZWRfYXQYDSABKAkSFQoNZXJyb3JfbWVzc2FnZRgOIAEoCRITCgtyZXN1bHRfanNvbhgPIAEoCRISCgpjcmVhdGVkX2F0GBAgASgJEhIKCnVwZGF0ZWRfYXQYESABKAkSMQoLcHJvcG9zZWRfYnkYEiABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwSMQoLZXhlY3V0ZWRfYnkYEyABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwiLgoIUGFnZUluZm8SDQoFdG90YWwYASABKAUSEwoLbmV4dF9jdXJzb3IYAiABKAkiHQobTGlzdENvbm5lY3RvckNhdGFsb2dSZXF1ZXN0IkwKHExpc3RDb25uZWN0b3JDYXRhbG9nUmVzcG9uc2USLAoEZGF0YRgBIAMoCzIeLmFwZXJpby52MS5Db25uZWN0b3JEZWZpbml0aW9uIuQCChNDb25uZWN0b3JEZWZpbml0aW9uEhAKCHByb3ZpZGVyGAEgASgJEgwKBG5hbWUYAiABKAkSEAoIY2F0ZWdvcnkYAyABKAkSFAoMYXZhaWxhYmlsaXR5GAQgASgJEhYKDnJlYWRpbmVzc19ub3RlGAUgASgJEhMKC2Rlc2NyaXB0aW9uGAYgASgJEhMKC3JlYWRfc2NvcGVzGAcgAygJEhoKEnJlbWVkaWF0aW9uX3Njb3BlcxgIIAMoCRI5ChNyZW1lZGlhdGlvbl9hY3Rpb25zGAkgAygLMhwuYXBlcmlvLnYxLlJlbWVkaWF0aW9uQWN0aW9uEi8KDmZpbmRpbmdfY2hlY2tzGAogAygLMhcuYXBlcmlvLnYxLkZpbmRpbmdDaGVjaxIQCghkb2NzX3VybBgLIAEoCRIpCgZmaWVsZHMYDCADKAsyGS5hcGVyaW8udjEuQ29ubmVjdG9yRmllbGQigQEKDkNvbm5lY3RvckZpZWxkEgsKA2tleRgBIAEoCRINCgVsYWJlbBgCIAEoCRITCgtwbGFjZWhvbGRlchgDIAEoCRIOCgZoZWxwZXIYBCABKAkSDAoEdHlwZRgFIAEoCRIQCghyZXF1aXJlZBgGIAEoCBIOCgZzZWNyZXQYByABKAgiWwoRUmVtZWRpYXRpb25BY3Rpb24SCwoDa2V5GAEgASgJEg0KBWxhYmVsGAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJEhUKDXNldmVyaXR5X2hpbnQYBCABKAkibwoMRmluZGluZ0NoZWNrEgsKA2tleRgBIAEoCRINCgV0aXRsZRgCIAEoCRITCgtkZXNjcmlwdGlvbhgDIAEoCRIVCg1zZXZlcml0eV9oaW50GAQgASgJEhcKD2RlZmF1bHRfZW5hYmxlZBgFIAEoCCIZChdMaXN0SW50ZWdyYXRpb25zUmVxdWVzdCJKChhMaXN0SW50ZWdyYXRpb25zUmVzcG9uc2USLgoEZGF0YRgBIAMoCzIgLmFwZXJpby52MS5JbnRlZ3JhdGlvbkNvbm5lY3Rpb24iqAIKFUludGVncmF0aW9uQ29ubmVjdGlvbhIKCgJpZBgBIAEoCRIQCghwcm92aWRlchgCIAEoCRIUCgxkaXNwbGF5X25hbWUYAyABKAkSGwoTZXh0ZXJuYWxfYWNjb3VudF9pZBgEIAEoCRIOCgZzdGF0dXMYBSABKAkSDAoEbW9kZRgGIAEoCRIOCgZzY29wZXMYByADKAkSFwoPZGlzYWJsZWRfY2hlY2tzGAggAygJEiMKG2dvb2dsZV9tYWlsYm94X3NjYW5fZW5hYmxlZBgJIAEoCBIoCiBnb29nbGVfbWFpbGJveF9zY2FuX2NsaWVudF9lbWFpbBgKIAEoCRIUCgxsYXN0X3N5bmNfYXQYCyABKAkSEgoKY3JlYXRlZF9hdBgMIAEoCSKlAQoYQ3JlYXRlSW50ZWdyYXRpb25SZXF1ZXN0EhAKCHByb3ZpZGVyGAEgASgJEhQKDGRpc3BsYXlfbmFtZRgCIAEoCRIbChNleHRlcm5hbF9hY2NvdW50X2lkGAMgASgJEgwKBG1vZGUYBCABKAkSNgoLY3JlZGVudGlhbHMYBSABKAsyIS5hcGVyaW8udjEuSW50ZWdyYXRpb25DcmVkZW50aWFscyJdChZJbnRlZ3JhdGlvbkNyZWRlbnRpYWxzEhQKDGFjY2Vzc190b2tlbhgBIAEoCRIVCg1yZWZyZXNoX3Rva2VuGAIgASgJEhYKDndlYmhvb2tfc2VjcmV0GAMgASgJIksKGUNyZWF0ZUludGVncmF0aW9uUmVzcG9uc2USLgoEZGF0YRgBIAEoCzIgLmFwZXJpby52MS5JbnRlZ3JhdGlvbkNvbm5lY3Rpb24iJgoYRGVsZXRlSW50ZWdyYXRpb25SZXF1ZXN0EgoKAmlkGAEgASgJIkIKGURlbGV0ZUludGVncmF0aW9uUmVzcG9uc2USJQoEZGF0YRgBIAEoCzIXLmFwZXJpby52MS5EZWxldGVSZXN1bHQiGgoMRGVsZXRlUmVzdWx0EgoKAm9rGAEgASgIIjUKG0dldEludGVncmF0aW9uQ2hlY2tzUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCSJOChxHZXRJbnRlZ3JhdGlvbkNoZWNrc1Jlc3BvbnNlEi4KBGRhdGEYASABKAsyIC5hcGVyaW8udjEuSW50ZWdyYXRpb25DaGVja1N0YXRlIoUBCh5VcGRhdGVJbnRlZ3JhdGlvbkNoZWNrc1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkSFwoPZGlzYWJsZWRfY2hlY2tzGAIgAygJEhYKDmRpc2FibGVfcmVhc29uGAMgASgJEhoKEmRpc2FibGVfZXhwaXJlc19hdBgEIAEoCSJRCh9VcGRhdGVJbnRlZ3JhdGlvbkNoZWNrc1Jlc3BvbnNlEi4KBGRhdGEYASABKAsyIC5hcGVyaW8udjEuSW50ZWdyYXRpb25DaGVja1N0YXRlIncKFUludGVncmF0aW9uQ2hlY2tTdGF0ZRIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRIXCg9kaXNhYmxlZF9jaGVja3MYAiADKAkSLQoGY2hlY2tzGAMgAygLMh0uYXBlcmlvLnYxLkZpbmRpbmdDaGVja1N0YXR1cyKGAQoSRmluZGluZ0NoZWNrU3RhdHVzEgsKA2tleRgBIAEoCRINCgV0aXRsZRgCIAEoCRITCgtkZXNjcmlwdGlvbhgDIAEoCRIVCg1zZXZlcml0eV9oaW50GAQgASgJEhcKD2RlZmF1bHRfZW5hYmxlZBgFIAEoCBIPCgdlbmFibGVkGAYgASgIIjsKIUdldEdvb2dsZU1haWxib3hTY2FuQ29uZmlnUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCSJWCiJHZXRHb29nbGVNYWlsYm94U2NhbkNvbmZpZ1Jlc3BvbnNlEjAKBGRhdGEYASABKAsyIi5hcGVyaW8udjEuR29vZ2xlTWFpbGJveFNjYW5Db25maWciigEKJFVwZGF0ZUdvb2dsZU1haWxib3hTY2FuQ29uZmlnUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRIPCgdlbmFibGVkGAIgASgIEiQKHHNlcnZpY2VfYWNjb3VudF9jbGllbnRfZW1haWwYAyABKAkSEwoLcHJpdmF0ZV9rZXkYBCABKAkiWQolVXBkYXRlR29vZ2xlTWFpbGJveFNjYW5Db25maWdSZXNwb25zZRIwCgRkYXRhGAEgASgLMiIuYXBlcmlvLnYxLkdvb2dsZU1haWxib3hTY2FuQ29uZmlnIlAKF0dvb2dsZU1haWxib3hTY2FuQ29uZmlnEg8KB2VuYWJsZWQYASABKAgSJAocc2VydmljZV9hY2NvdW50X2NsaWVudF9lbWFpbBgCIAEoCSJBCidHZXRHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkiYgooR2V0R29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWdSZXNwb25zZRI2CgRkYXRhGAEgASgLMiguYXBlcmlvLnYxLkdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnIv8BCipVcGRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkSDwoHZW5hYmxlZBgCIAEoCBISCgpwcm9qZWN0X2lkGAMgASgJEhYKDnJhd19kYXRhc2V0X2lkGAQgASgJEhIKCmRhdGFzZXRfaWQYBSABKAkSEAoIbG9jYXRpb24YBiABKAkSHQoVc2VydmljZV9hY2NvdW50X2VtYWlsGAcgASgJEiIKGndvcmtsb2FkX2lkZW50aXR5X3Byb3ZpZGVyGAggASgJEhMKC2FjY2Vzc19tb2RlGAkgASgJImUKK1VwZGF0ZUdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnUmVzcG9uc2USNgoEZGF0YRgBIAEoCzIoLmFwZXJpby52MS5Hb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZyLuAQodR29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWcSDwoHZW5hYmxlZBgBIAEoCBISCgpwcm9qZWN0X2lkGAIgASgJEhYKDnJhd19kYXRhc2V0X2lkGAMgASgJEhIKCmRhdGFzZXRfaWQYBCABKAkSEAoIbG9jYXRpb24YBSABKAkSHQoVc2VydmljZV9hY2NvdW50X2VtYWlsGAYgASgJEiIKGndvcmtsb2FkX2lkZW50aXR5X3Byb3ZpZGVyGAcgASgJEhMKC2FjY2Vzc19tb2RlGAggASgJEhIKCnVwZGF0ZWRfYXQYCSABKAkiRgosVmFsaWRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkiawotVmFsaWRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1Jlc3BvbnNlEjoKBGRhdGEYASABKAsyLC5hcGVyaW8udjEuR29vZ2xlV29ya3NwYWNlQmlnUXVlcnlWYWxpZGF0aW9uIvoBCiFHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeVZhbGlkYXRpb24SFgoOaW50ZWdyYXRpb25faWQYASABKAkSCgoCb2sYAiABKAgSDwoHbWVzc2FnZRgDIAEoCRISCgpwcm9qZWN0X2lkGAQgASgJEhIKCmRhdGFzZXRfaWQYBSABKAkSFgoOYWN0aXZpdHlfdGFibGUYBiABKAkSEwoLdGFibGVfZm91bmQYByABKAgSEwoLc2FtcGxlX3Jvd3MYCCABKAUSFwoPZXN0aW1hdGVkX2J5dGVzGAkgASgDEh0KFXJ1bnRpbWVfdG9rZW5fcHJlc2VudBgKIAEoCCIwCiBTdGFydEdvb2dsZVdvcmtzcGFjZU9BdXRoUmVxdWVzdBIMCgRtb2RlGAEgASgJIkgKIVN0YXJ0R29vZ2xlV29ya3NwYWNlT0F1dGhSZXNwb25zZRIjCgRkYXRhGAEgASgLMhUuYXBlcmlvLnYxLk9BdXRoU3RhcnQiqQEKFkludGVncmF0aW9uT0F1dGhDbGllbnQSEAoIcHJvdmlkZXIYASABKAkSEQoJY2xpZW50X2lkGAIgASgJEhQKDHJlZGlyZWN0X3VyaRgDIAEoCRISCgpjb25maWd1cmVkGAQgASgIEhwKFGRlZmF1bHRfcmVkaXJlY3RfdXJpGAUgASgJEhIKCnVwZGF0ZWRfYXQYBiABKAkSDgoGc291cmNlGAcgASgJIjQKIEdldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXF1ZXN0EhAKCHByb3ZpZGVyGAEgASgJIlQKIUdldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRIvCgRkYXRhGAEgASgLMiEuYXBlcmlvLnYxLkludGVncmF0aW9uT0F1dGhDbGllbnQidAogU2V0SW50ZWdyYXRpb25PQXV0aENsaWVudFJlcXVlc3QSEAoIcHJvdmlkZXIYASABKAkSEQoJY2xpZW50X2lkGAIgASgJEhUKDWNsaWVudF9zZWNyZXQYAyABKAkSFAoMcmVkaXJlY3RfdXJpGAQgASgJIlQKIVNldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRIvCgRkYXRhGAEgASgLMiEuYXBlcmlvLnYxLkludGVncmF0aW9uT0F1dGhDbGllbnQiNgoiQ2xlYXJJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50UmVxdWVzdBIQCghwcm92aWRlchgBIAEoCSJWCiNDbGVhckludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRIvCgRkYXRhGAEgASgLMiEuYXBlcmlvLnYxLkludGVncmF0aW9uT0F1dGhDbGllbnQiGQoKT0F1dGhTdGFydBILCgN1cmwYASABKAkiNQobRm9yY2VTeW5jSW50ZWdyYXRpb25SZXF1ZXN0EhYKDmludGVncmF0aW9uX2lkGAEgASgJInQKHEZvcmNlU3luY0ludGVncmF0aW9uUmVzcG9uc2USLgoEZGF0YRgBIAEoCzIgLmFwZXJpby52MS5JbnRlZ3JhdGlvbkNvbm5lY3Rpb24SJAoEc3luYxgCIAEoCzIWLmFwZXJpby52MS5TeW5jU3VtbWFyeSJmCgtTeW5jU3VtbWFyeRIUCgxzYW1wbGVfY291bnQYASABKAUSFwoPZXZlbnRzX2luZ2VzdGVkGAIgASgFEhcKD2ZpbmRpbmdzX29wZW5lZBgDIAEoBRIPCgdzb3VyY2VzGAQgAygJIjkKH0dldEludGVncmF0aW9uU3luY1N0YXR1c1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkiUgogR2V0SW50ZWdyYXRpb25TeW5jU3RhdHVzUmVzcG9uc2USLgoEZGF0YRgBIAEoCzIgLmFwZXJpby52MS5JbnRlZ3JhdGlvblN5bmNTdGF0dXMiYwofUnVuSW50ZWdyYXRpb25Tb3VyY2VTeW5jUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRITCgtzb3VyY2Vfa2luZBgCIAEoCRITCgtzdHJlYW1fbmFtZRgDIAEoCSJYCiBSdW5JbnRlZ3JhdGlvblNvdXJjZVN5bmNSZXNwb25zZRI0CgRkYXRhGAEgASgLMiYuYXBlcmlvLnYxLkludGVncmF0aW9uU291cmNlU3luY0FjdGlvbiJ3CiBCYWNrZmlsbEludGVncmF0aW9uU291cmNlUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRITCgtzb3VyY2Vfa2luZBgCIAEoCRITCgtzdHJlYW1fbmFtZRgDIAEoCRIRCglmcm9tX3RpbWUYBCABKAkiWQohQmFja2ZpbGxJbnRlZ3JhdGlvblNvdXJjZVJlc3BvbnNlEjQKBGRhdGEYASABKAsyJi5hcGVyaW8udjEuSW50ZWdyYXRpb25Tb3VyY2VTeW5jQWN0aW9uIo8BChVJbnRlZ3JhdGlvblN5bmNTdGF0dXMSFgoOaW50ZWdyYXRpb25faWQYASABKAkSEAoIcHJvdmlkZXIYAiABKAkSFAoMZ2VuZXJhdGVkX2F0GAMgASgJEjYKB3NvdXJjZXMYBCADKAsyJS5hcGVyaW8udjEuSW50ZWdyYXRpb25Tb3VyY2VTeW5jU3RhdGUiywMKGkludGVncmF0aW9uU291cmNlU3luY1N0YXRlEhMKC3NvdXJjZV9raW5kGAEgASgJEhMKC3N0cmVhbV9uYW1lGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCRIOCgZzdGF0dXMYBCABKAkSEwoLY3Vyc29yX3RpbWUYBSABKAkSFwoPbGFzdF9hdHRlbXB0X2F0GAYgASgJEhcKD2xhc3Rfc3VjY2Vzc19hdBgHIAEoCRISCgpsYXN0X2Vycm9yGAggASgJEhMKC2xhZ19zZWNvbmRzGAkgASgDEhEKCXJvd3Nfc2VlbhgKIAEoAxIVCg1yb3dzX2VucXVldWVkGAsgASgDEhQKDHF1ZXVlX3F1ZXVlZBgMIAEoAxIVCg1xdWV1ZV9ydW5uaW5nGA0gASgDEhQKDHF1ZXVlX2ZhaWxlZBgOIAEoAxIZChFxdWV1ZV9kZWFkX2xldHRlchgPIAEoAxIXCg9xdWV1ZV9zdWNjZWVkZWQYECABKAMSGgoSc3luY19ub3dfc3VwcG9ydGVkGBEgASgIEhoKEmJhY2tmaWxsX3N1cHBvcnRlZBgSIAEoCBIUCgxxdWV1ZV9zb3VyY2UYEyABKAkilgEKG0ludGVncmF0aW9uU291cmNlU3luY0FjdGlvbhIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRITCgtzb3VyY2Vfa2luZBgCIAEoCRITCgtzdHJlYW1fbmFtZRgDIAEoCRIOCgZxdWV1ZWQYBCABKAgSDwoHbWVzc2FnZRgFIAEoCRIUCgxyZXF1ZXN0ZWRfYXQYBiABKAkiGAoWTGlzdFNpZW1DYXRhbG9nUmVxdWVzdCJNChdMaXN0U2llbUNhdGFsb2dSZXNwb25zZRIyCgRkYXRhGAEgAygLMiQuYXBlcmlvLnYxLlNpZW1EZXN0aW5hdGlvbkRlZmluaXRpb24ivwEKGVNpZW1EZXN0aW5hdGlvbkRlZmluaXRpb24SDAoEa2luZBgBIAEoCRIMCgRuYW1lGAIgASgJEg4KBnZlbmRvchgDIAEoCRITCgtkZXNjcmlwdGlvbhgEIAEoCRIQCghjYXRlZ29yeRgFIAEoCRIQCghkb2NzX3VybBgGIAEoCRIXCg9kZWZhdWx0X3N0cmVhbXMYByADKAkSJAoGZmllbGRzGAggAygLMhQuYXBlcmlvLnYxLlNpZW1GaWVsZCJ8CglTaWVtRmllbGQSCwoDa2V5GAEgASgJEg0KBWxhYmVsGAIgASgJEhMKC3BsYWNlaG9sZGVyGAMgASgJEg4KBmhlbHBlchgEIAEoCRIMCgR0eXBlGAUgASgJEhAKCHJlcXVpcmVkGAYgASgIEg4KBnNlY3JldBgHIAEoCCIdChtMaXN0U2llbURlc3RpbmF0aW9uc1JlcXVlc3QiSAocTGlzdFNpZW1EZXN0aW5hdGlvbnNSZXNwb25zZRIoCgRkYXRhGAEgAygLMhouYXBlcmlvLnYxLlNpZW1EZXN0aW5hdGlvbiKEAgoPU2llbURlc3RpbmF0aW9uEgoKAmlkGAEgASgJEgwKBGtpbmQYAiABKAkSDAoEbmFtZRgDIAEoCRIUCgxlbmRwb2ludF91cmwYBCABKAkSEQoJZmlsZV9wYXRoGAUgASgJEg0KBWluZGV4GAYgASgJEg8KB3N0cmVhbXMYByADKAkSDgoGc3RhdHVzGAggASgJEhgKEGxhc3RfZGVsaXZlcnlfYXQYCSABKAkSEgoKbGFzdF9lcnJvchgKIAEoCRIVCg1kZWxpdmVyaWVzX29rGAsgASgFEhcKD2RlbGl2ZXJpZXNfZmFpbBgMIAEoBRISCgpjcmVhdGVkX2F0GA0gASgJIpIBChxDcmVhdGVTaWVtRGVzdGluYXRpb25SZXF1ZXN0EgwKBGtpbmQYASABKAkSDAoEbmFtZRgCIAEoCRIUCgxlbmRwb2ludF91cmwYAyABKAkSEQoJZmlsZV9wYXRoGAQgASgJEg0KBWluZGV4GAUgASgJEg0KBXRva2VuGAYgASgJEg8KB3N0cmVhbXMYByADKAkiSQodQ3JlYXRlU2llbURlc3RpbmF0aW9uUmVzcG9uc2USKAoEZGF0YRgBIAEoCzIaLmFwZXJpby52MS5TaWVtRGVzdGluYXRpb24iKgocRGVsZXRlU2llbURlc3RpbmF0aW9uUmVxdWVzdBIKCgJpZBgBIAEoCSJGCh1EZWxldGVTaWVtRGVzdGluYXRpb25SZXNwb25zZRIlCgRkYXRhGAEgASgLMhcuYXBlcmlvLnYxLkRlbGV0ZVJlc3VsdCIoChpUZXN0U2llbURlc3RpbmF0aW9uUmVxdWVzdBIKCgJpZBgBIAEoCSJGChtUZXN0U2llbURlc3RpbmF0aW9uUmVzcG9uc2USJwoEZGF0YRgBIAEoCzIZLmFwZXJpby52MS5TaWVtVGVzdFJlc3VsdCJFCg5TaWVtVGVzdFJlc3VsdBIWCg5kZXN0aW5hdGlvbl9pZBgBIAEoCRIKCgJvaxgCIAEoCBIPCgdtZXNzYWdlGAMgASgJIh4KHExpc3RTaGFkb3dJdE9hdXRoQXBwc1JlcXVlc3QiSgodTGlzdFNoYWRvd0l0T2F1dGhBcHBzUmVzcG9uc2USKQoEZGF0YRgBIAMoCzIbLmFwZXJpby52MS5TaGFkb3dJdE9hdXRoQXBwIrACChBTaGFkb3dJdE9hdXRoQXBwEgoKAmlkGAEgASgJEhAKCHByb3ZpZGVyGAIgASgJEgwKBG5hbWUYAyABKAkSDwoHc3VtbWFyeRgEIAEoCRITCgtleHRlcm5hbF9pZBgFIAEoCRIOCgZsYWJlbHMYBiADKAkSEwoLY3JpdGljYWxpdHkYByABKAkSHwoXY29udGFpbnNfc2Vuc2l0aXZlX2RhdGEYCCABKAgSEgoKcmlza19zY29yZRgJIAEoBRIYChBsYXN0X29ic2VydmVkX2F0GAogASgJEhIKCnVzZXJfY291bnQYCyABKAUSDgoGc2NvcGVzGAwgAygJEjIKC2ludGVncmF0aW9uGA0gASgLMh0uYXBlcmlvLnYxLkZpbmRpbmdJbnRlZ3JhdGlvbiI1CiFMaXN0U2hhZG93SXRPYXV0aEFwcEdyYW50c1JlcXVlc3QSEAoIYXNzZXRfaWQYASABKAkiVQoiTGlzdFNoYWRvd0l0T2F1dGhBcHBHcmFudHNSZXNwb25zZRIvCgRkYXRhGAEgASgLMiEuYXBlcmlvLnYxLlNoYWRvd0l0T2F1dGhBcHBEZXRhaWwidwoWU2hhZG93SXRPYXV0aEFwcERldGFpbBIrCgNhcHAYASABKAsyHi5hcGVyaW8udjEuU2hhZG93SXRPYXV0aEFwcFJlZhIwCgZncmFudHMYAiADKAsyIC5hcGVyaW8udjEuU2hhZG93SXRPYXV0aEFwcEdyYW50IlYKE1NoYWRvd0l0T2F1dGhBcHBSZWYSCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRITCgtleHRlcm5hbF9pZBgDIAEoCRIQCghwcm92aWRlchgEIAEoCSK9AQoVU2hhZG93SXRPYXV0aEFwcEdyYW50EgoKAmlkGAEgASgJEhIKCnVzZXJfZW1haWwYAiABKAkSGAoQdXNlcl9leHRlcm5hbF9pZBgDIAEoCRIZChF1c2VyX2Rpc3BsYXlfbmFtZRgEIAEoCRIOCgZzY29wZXMYBSADKAkSEQoJYW5vbnltb3VzGAYgASgIEhIKCm5hdGl2ZV9hcHAYByABKAgSGAoQbGFzdF9vYnNlcnZlZF9hdBgIIAEoCSIaChhHZXRUZW5hbnRTZXR0aW5nc1JlcXVlc3QiRAoZR2V0VGVuYW50U2V0dGluZ3NSZXNwb25zZRInCgRkYXRhGAEgASgLMhkuYXBlcmlvLnYxLlRlbmFudFNldHRpbmdzItMDChtVcGRhdGVUZW5hbnRTZXR0aW5nc1JlcXVlc3QSEQoEbmFtZRgBIAEoCUgAiAEBEh8KEm5vdGlmaWNhdGlvbl9lbWFpbBgCIAEoCUgBiAEBEiAKE2RhdGFfcmV0ZW50aW9uX2RheXMYAyABKAVIAogBARIkChdjcml0aWNhbF9yaXNrX3RocmVzaG9sZBgEIAEoBUgDiAEBEh4KEWRlZmF1bHRfc2xhX2hvdXJzGAUgASgFSASIAQESJgoZYXV0b19yZXNvbHZlX2xvd19zZXZlcml0eRgGIAEoCEgFiAEBEh0KEGVuZm9yY2Vfc3NvX29ubHkYByABKAhIBogBARIeChF3ZWJob29rX2FsZXJ0X3VybBgIIAEoCUgHiAEBQgcKBV9uYW1lQhUKE19ub3RpZmljYXRpb25fZW1haWxCFgoUX2RhdGFfcmV0ZW50aW9uX2RheXNCGgoYX2NyaXRpY2FsX3Jpc2tfdGhyZXNob2xkQhQKEl9kZWZhdWx0X3NsYV9ob3Vyc0IcChpfYXV0b19yZXNvbHZlX2xvd19zZXZlcml0eUITChFfZW5mb3JjZV9zc29fb25seUIUChJfd2ViaG9va19hbGVydF91cmwiRwocVXBkYXRlVGVuYW50U2V0dGluZ3NSZXNwb25zZRInCgRkYXRhGAEgASgLMhkuYXBlcmlvLnYxLlRlbmFudFNldHRpbmdzIq0CCg5UZW5hbnRTZXR0aW5ncxIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEgwKBHNsdWcYAyABKAkSGgoSbm90aWZpY2F0aW9uX2VtYWlsGAQgASgJEhsKE2RhdGFfcmV0ZW50aW9uX2RheXMYBSABKAUSHwoXY3JpdGljYWxfcmlza190aHJlc2hvbGQYBiABKAUSGQoRZGVmYXVsdF9zbGFfaG91cnMYByABKAUSIQoZYXV0b19yZXNvbHZlX2xvd19zZXZlcml0eRgIIAEoCBIYChBlbmZvcmNlX3Nzb19vbmx5GAkgASgIEhkKEXdlYmhvb2tfYWxlcnRfdXJsGAogASgJEhIKCmNyZWF0ZWRfYXQYCyABKAkSEgoKdXBkYXRlZF9hdBgMIAEoCSIaChhMaXN0VGVuYW50TWVtYmVyc1JlcXVlc3QiQgoZTGlzdFRlbmFudE1lbWJlcnNSZXNwb25zZRIlCgRkYXRhGAEgAygLMhcuYXBlcmlvLnYxLlRlbmFudE1lbWJlciJTChlDcmVhdGVUZW5hbnRNZW1iZXJSZXF1ZXN0Eg0KBWVtYWlsGAEgASgJEhQKDGRpc3BsYXlfbmFtZRgCIAEoCRIRCglyb2xlX25hbWUYAyABKAkidAoaQ3JlYXRlVGVuYW50TWVtYmVyUmVzcG9uc2USJQoEZGF0YRgBIAEoCzIXLmFwZXJpby52MS5UZW5hbnRNZW1iZXISLwoKaW52aXRhdGlvbhgCIAEoCzIbLmFwZXJpby52MS5JbnZpdGF0aW9uUmVzdWx0IioKHENyZWF0ZU1lbWJlclJlc2V0TGlua1JlcXVlc3QSCgoCaWQYASABKAkicgodQ3JlYXRlTWVtYmVyUmVzZXRMaW5rUmVzcG9uc2USJQoEZGF0YRgBIAEoCzIXLmFwZXJpby52MS5UZW5hbnRNZW1iZXISKgoFcmVzZXQYAiABKAsyGy5hcGVyaW8udjEuSW52aXRhdGlvblJlc3VsdCI4ChdVcGRhdGVNZW1iZXJSb2xlUmVxdWVzdBIKCgJpZBgBIAEoCRIRCglyb2xlX25hbWUYAiABKAkiQQoYVXBkYXRlTWVtYmVyUm9sZVJlc3BvbnNlEiUKBGRhdGEYASABKAsyFy5hcGVyaW8udjEuVGVuYW50TWVtYmVyIu8BCgxUZW5hbnRNZW1iZXISCgoCaWQYASABKAkSDQoFZW1haWwYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJEhEKCWlzX2FjdGl2ZRgEIAEoCBITCgttZmFfZW5hYmxlZBgFIAEoCBIVCg1sYXN0X2xvZ2luX2F0GAYgASgJEhYKDmlzX2JyZWFrX2dsYXNzGAcgASgIEgwKBHJvbGUYCCABKAkSEgoKYXV0aF9zdGF0ZRgJIAEoCRIhChlwZW5kaW5nX2FjdGlvbl9leHBpcmVzX2F0GAogASgJEhIKCmNyZWF0ZWRfYXQYCyABKAkiRQoQSW52aXRhdGlvblJlc3VsdBIQCghkZWxpdmVyeRgBIAEoCRILCgN1cmwYAiABKAkSEgoKZXhwaXJlc19hdBgDIAEoCSIWChRMaXN0QXVkaXRMb2dzUmVxdWVzdCI/ChVMaXN0QXVkaXRMb2dzUmVzcG9uc2USJgoEZGF0YRgBIAMoCzIYLmFwZXJpby52MS5BdWRpdExvZ0VudHJ5Io0BCg1BdWRpdExvZ0VudHJ5EgoKAmlkGAEgASgJEg4KBmFjdGlvbhgCIAEoCRITCgt0YXJnZXRfdHlwZRgDIAEoCRIRCgl0YXJnZXRfaWQYBCABKAkSDQoFYWN0b3IYBSABKAkSEgoKY3JlYXRlZF9hdBgGIAEoCRIVCg1tZXRhZGF0YV9qc29uGAcgASgJIhwKGkdldFNlY3VyaXR5T3ZlcnZpZXdSZXF1ZXN0IkgKG0dldFNlY3VyaXR5T3ZlcnZpZXdSZXNwb25zZRIpCgRkYXRhGAEgASgLMhsuYXBlcmlvLnYxLlNlY3VyaXR5T3ZlcnZpZXciiQQKEFNlY3VyaXR5T3ZlcnZpZXcSMwoHc3VtbWFyeRgBIAEoCzIiLmFwZXJpby52MS5TZWN1cml0eU92ZXJ2aWV3U3VtbWFyeRIvCgppZGVudGl0aWVzGAIgAygLMhsuYXBlcmlvLnYxLlNlY3VyaXR5SWRlbnRpdHkSJwoFZ3JhcGgYAyABKAsyGC5hcGVyaW8udjEuU2VjdXJpdHlHcmFwaBIsCgpvYXV0aF9hcHBzGAQgAygLMhguYXBlcmlvLnYxLlNlY3VyaXR5QXNzZXQSLQoLZGF0YV9hc3NldHMYBSADKAsyGC5hcGVyaW8udjEuU2VjdXJpdHlBc3NldBIrCgxhdHRhY2tfcGF0aHMYBiADKAsyFS5hcGVyaW8udjEuQXR0YWNrUGF0aBIwCg5vd25lcnNoaXBfZ2FwcxgHIAMoCzIYLmFwZXJpby52MS5TZWN1cml0eUFzc2V0EiwKCmV4Y2VwdGlvbnMYCCADKAsyGC5hcGVyaW8udjEuUmlza0V4Y2VwdGlvbhJAChdkb21haW5fd2lkZV9kZWxlZ2F0aW9ucxgJIAMoCzIfLmFwZXJpby52MS5Eb21haW5XaWRlRGVsZWdhdGlvbhI6Cg9jZXJlYnJvX2NvbnRleHQYCiABKAsyIS5hcGVyaW8udjEuU2VjdXJpdHlDZXJlYnJvQ29udGV4dCLoAQoXU2VjdXJpdHlPdmVydmlld1N1bW1hcnkSHQoVcHJpdmlsZWdlZF9pZGVudGl0aWVzGAEgASgFEiQKHGFkbWluX2lkZW50aXRpZXNfd2l0aG91dF9tZmEYAiABKAUSGAoQcmlza3lfb2F1dGhfYXBwcxgDIAEoBRIbChNleHBvc2VkX2RhdGFfYXNzZXRzGAQgASgFEhYKDnVub3duZWRfYXNzZXRzGAUgASgFEhkKEWFjdGl2ZV9leGNlcHRpb25zGAYgASgFEh4KFnRvcF9ibGFzdF9yYWRpdXNfc2NvcmUYByABKAUilwIKFlNlY3VyaXR5Q2VyZWJyb0NvbnRleHQSDgoGc291cmNlGAEgASgJEgwKBG1vZGUYAiABKAkSGQoRc291cmNlX3J1bnRpbWVfaWQYAyABKAkSGAoQZmluZGluZ19jb250cmFjdBgEIAEoCRITCgtjbGFpbV9jb3VudBgFIAEoBRIaChJncmFwaF9zaWduYWxfY291bnQYBiABKAUSFAoMZW50aXR5X2NvdW50GAcgASgFEhgKEGdyYXBoX3BhdGhfY291bnQYCCABKAUSMQoDbWNwGAkgASgLMiQuYXBlcmlvLnYxLlNlY3VyaXR5Q2VyZWJyb01DUENvbnRleHQSFgoOcmVzcG9uc2VfaGludHMYCiADKAkipQEKGVNlY3VyaXR5Q2VyZWJyb01DUENvbnRleHQSDgoGc2VydmVyGAEgASgJEhQKDHJlc291cmNlX3VyaRgCIAEoCRIQCghyZXNvdXJjZRgDIAEoCRINCgV0b29scxgEIAMoCRJBChJyZXNvdXJjZV90ZW1wbGF0ZXMYBSADKAsyJS5hcGVyaW8udjEuQ2VyZWJyb01DUFJlc291cmNlVGVtcGxhdGUi/gIKEFNlY3VyaXR5SWRlbnRpdHkSCgoCaWQYASABKAkSEQoJZW50aXR5X2lkGAIgASgJEgwKBGtpbmQYAyABKAkSDAoEbmFtZRgEIAEoCRINCgVlbWFpbBgFIAEoCRIQCghwcm92aWRlchgGIAEoCRIyCgtpbnRlZ3JhdGlvbhgHIAEoCzIdLmFwZXJpby52MS5GaW5kaW5nSW50ZWdyYXRpb24SDAoEcm9sZRgIIAEoCRISCgpwcml2aWxlZ2VkGAkgASgIEhMKC21mYV9lbmFibGVkGAogASgIEg4KBnN0YXR1cxgLIAEoCRITCgtpc19leHRlcm5hbBgMIAEoCBIYChBsYXN0X29ic2VydmVkX2F0GA0gASgJEhoKEmxpbmtlZF9hc3NldF9jb3VudBgOIAEoBRISCgpyaXNrX3Njb3JlGA8gASgFEh4KEW1mYV9lbmFibGVkX3N0YXRlGBAgASgISACIAQFCFAoSX21mYV9lbmFibGVkX3N0YXRlImkKDVNlY3VyaXR5R3JhcGgSKwoFbm9kZXMYASADKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlHcmFwaE5vZGUSKwoFZWRnZXMYAiADKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlHcmFwaEVkZ2UikQEKEVNlY3VyaXR5R3JhcGhOb2RlEgoKAmlkGAEgASgJEg0KBWxhYmVsGAIgASgJEgwKBGtpbmQYAyABKAkSEgoKcmlza19zY29yZRgEIAEoBRISCgpwcml2aWxlZ2VkGAUgASgIEhYKDmV4cG9zdXJlX2xldmVsGAYgASgJEhMKC2NyaXRpY2FsaXR5GAcgASgJImAKEVNlY3VyaXR5R3JhcGhFZGdlEgoKAmlkGAEgASgJEhEKCXNvdXJjZV9pZBgCIAEoCRIRCgl0YXJnZXRfaWQYAyABKAkSGQoRcmVsYXRpb25zaGlwX3R5cGUYBCABKAkizAEKCkF0dGFja1BhdGgSCgoCaWQYASABKAkSDQoFdGl0bGUYAiABKAkSDQoFc2NvcmUYAyABKAUSFQoNZmluZGluZ190aXRsZRgEIAEoCRITCgtlbnRyeV9wb2ludBgFIAEoCRIOCgZ0YXJnZXQYBiABKAkSDQoFb3duZXIYByABKAkSFgoOZXhwb3N1cmVfbGV2ZWwYCCABKAkSEwoLY3JpdGljYWxpdHkYCSABKAkSDgoGcmVhc29uGAogASgJEgwKBHBhdGgYCyADKAkirAIKFERvbWFpbldpZGVEZWxlZ2F0aW9uEhYKDmludGVncmF0aW9uX2lkGAEgASgJEhAKCHByb3ZpZGVyGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCRIYChB3b3Jrc3BhY2VfZG9tYWluGAQgASgJEiQKHHNlcnZpY2VfYWNjb3VudF9jbGllbnRfZW1haWwYBSABKAkSDgoGc2NvcGVzGAYgAygJEg4KBnN0YXR1cxgHIAEoCRIaChJpbnRlZ3JhdGlvbl9zdGF0dXMYCCABKAkSDAoEbW9kZRgJIAEoCRIdChVvcGVuX21haWxib3hfZmluZGluZ3MYCiABKAUSFAoMbGFzdF9zeW5jX2F0GAsgASgJEhUKDWNvbmZpZ3VyZWRfYXQYDCABKAkiOAocTGlzdEVtYWlsRG9tYWluSGVhbHRoUmVxdWVzdBIYChByZWZyZXNoX2lmX3N0YWxlGAEgASgIIksKHUxpc3RFbWFpbERvbWFpbkhlYWx0aFJlc3BvbnNlEioKBGRhdGEYASADKAsyHC5hcGVyaW8udjEuRW1haWxEb21haW5IZWFsdGgiLQobR2V0RW1haWxEb21haW5IZWFsdGhSZXF1ZXN0Eg4KBmRvbWFpbhgBIAEoCSJQChxHZXRFbWFpbERvbWFpbkhlYWx0aFJlc3BvbnNlEjAKBGRhdGEYASABKAsyIi5hcGVyaW8udjEuRW1haWxEb21haW5IZWFsdGhEZXRhaWwiMQofUmVmcmVzaEVtYWlsRG9tYWluSGVhbHRoUmVxdWVzdBIOCgZkb21haW4YASABKAkiTgogUmVmcmVzaEVtYWlsRG9tYWluSGVhbHRoUmVzcG9uc2USKgoEZGF0YRgBIAMoCzIcLmFwZXJpby52MS5FbWFpbERvbWFpbkhlYWx0aCLmAQoRRW1haWxEb21haW5IZWFsdGgSDgoGZG9tYWluGAEgASgJEhgKEHByb3ZpZGVyX3NvdXJjZXMYAiADKAkSDgoGc3RhdHVzGAMgASgJEg0KBXNjb3JlGAQgASgFEhIKCnNwZl9zdGF0dXMYBSABKAkSEwoLZGtpbV9zdGF0dXMYBiABKAkSFAoMZG1hcmNfc3RhdHVzGAcgASgJEhcKD2xhc3RfY2hlY2tlZF9hdBgIIAEoCRITCgtpc3N1ZV9jb3VudBgJIAEoBRIbChNmYWlsaW5nX2lzc3VlX2NvdW50GAogASgFIo0BChZFbWFpbERvbWFpbkhlYWx0aElzc3VlEgoKAmlkGAEgASgJEhAKCHByb3RvY29sGAIgASgJEhAKCHNldmVyaXR5GAMgASgJEgwKBGNvZGUYBCABKAkSDQoFdGl0bGUYBSABKAkSDgoGZGV0YWlsGAYgASgJEhYKDnJlY29tbWVuZGF0aW9uGAcgASgJIl0KF0VtYWlsRG9tYWluRGtpbVNlbGVjdG9yEhAKCHNlbGVjdG9yGAEgASgJEg4KBnN0YXR1cxgCIAEoCRIQCghrZXlfYml0cxgDIAEoBRIOCgZyZWNvcmQYBCABKAkiZwodRW1haWxEb21haW5IZWFsdGhIaXN0b3J5UG9pbnQSEgoKY2hlY2tlZF9hdBgBIAEoCRIOCgZzdGF0dXMYAiABKAkSDQoFc2NvcmUYAyABKAUSEwoLaXNzdWVfY291bnQYBCABKAUitAMKF0VtYWlsRG9tYWluSGVhbHRoRGV0YWlsEiwKBmRvbWFpbhgBIAEoCzIcLmFwZXJpby52MS5FbWFpbERvbWFpbkhlYWx0aBITCgtzcGZfcmVjb3JkcxgCIAMoCRISCgpzcGZfcG9saWN5GAMgASgJEhgKEHNwZl9sb29rdXBfY291bnQYBCABKAUSFQoNZG1hcmNfcmVjb3JkcxgFIAMoCRIUCgxkbWFyY19wb2xpY3kYBiABKAkSEQoJZG1hcmNfcGN0GAcgASgFEhEKCWRtYXJjX3J1YRgIIAMoCRISCgpteF9yZWNvcmRzGAkgAygJEjoKDmRraW1fc2VsZWN0b3JzGAogAygLMiIuYXBlcmlvLnYxLkVtYWlsRG9tYWluRGtpbVNlbGVjdG9yEhcKD3JlbGF0ZWRfcmVjb3JkcxgLIAMoCRIxCgZpc3N1ZXMYDCADKAsyIS5hcGVyaW8udjEuRW1haWxEb21haW5IZWFsdGhJc3N1ZRI5CgdoaXN0b3J5GA0gAygLMiguYXBlcmlvLnYxLkVtYWlsRG9tYWluSGVhbHRoSGlzdG9yeVBvaW50IlsKGUxpc3RTZWN1cml0eUFzc2V0c1JlcXVlc3QSDAoEdHlwZRgBIAEoCRIYChBvd25lcnNoaXBfc3RhdHVzGAIgASgJEhYKDmludGVncmF0aW9uX2lkGAMgASgJIkQKGkxpc3RTZWN1cml0eUFzc2V0c1Jlc3BvbnNlEiYKBGRhdGEYASADKAsyGC5hcGVyaW8udjEuU2VjdXJpdHlBc3NldCKnBAoNU2VjdXJpdHlBc3NldBIKCgJpZBgBIAEoCRIMCgR0eXBlGAIgASgJEhAKCHByb3ZpZGVyGAMgASgJEgwKBG5hbWUYBCABKAkSDwoHc3VtbWFyeRgFIAEoCRITCgtleHRlcm5hbF9pZBgGIAEoCRIOCgZsYWJlbHMYByADKAkSEwoLY3JpdGljYWxpdHkYCCABKAkSFgoOZXhwb3N1cmVfbGV2ZWwYCSABKAkSGAoQb3duZXJzaGlwX3N0YXR1cxgKIAEoCRIfChdjb250YWluc19zZW5zaXRpdmVfZGF0YRgLIAEoCBIVCg1pc19wcml2aWxlZ2VkGAwgASgIEhIKCnJpc2tfc2NvcmUYDSABKAUSGAoQbGFzdF9vYnNlcnZlZF9hdBgOIAEoCRISCgpjcmVhdGVkX2F0GA8gASgJEhIKCnVwZGF0ZWRfYXQYECABKAkSMgoLaW50ZWdyYXRpb24YESABKAsyHS5hcGVyaW8udjEuRmluZGluZ0ludGVncmF0aW9uEisKBW93bmVyGBIgASgLMhwuYXBlcmlvLnYxLlNlY3VyaXR5UHJpbmNpcGFsEjQKDmJ1c2luZXNzX293bmVyGBMgASgLMhwuYXBlcmlvLnYxLlNlY3VyaXR5UHJpbmNpcGFsEhoKEm9wZW5fZmluZGluZ19jb3VudBgUIAEoBRIeChZhY3RpdmVfZXhjZXB0aW9uX2NvdW50GBUgASgFIkQKEVNlY3VyaXR5UHJpbmNpcGFsEgoKAmlkGAEgASgJEg0KBWVtYWlsGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCSL8AgoaQ3JlYXRlU2VjdXJpdHlBc3NldFJlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkSFQoNb3duZXJfdXNlcl9pZBgCIAEoCRIeChZidXNpbmVzc19vd25lcl91c2VyX2lkGAMgASgJEgwKBHR5cGUYBCABKAkSEAoIcHJvdmlkZXIYBSABKAkSDAoEbmFtZRgGIAEoCRIPCgdzdW1tYXJ5GAcgASgJEhMKC2V4dGVybmFsX2lkGAggASgJEg4KBmxhYmVscxgJIAMoCRITCgtjcml0aWNhbGl0eRgKIAEoCRIWCg5leHBvc3VyZV9sZXZlbBgLIAEoCRIYChBvd25lcnNoaXBfc3RhdHVzGAwgASgJEh8KF2NvbnRhaW5zX3NlbnNpdGl2ZV9kYXRhGA0gASgIEhUKDWlzX3ByaXZpbGVnZWQYDiABKAgSEgoKcmlza19zY29yZRgPIAEoBRIYChBsYXN0X29ic2VydmVkX2F0GBAgASgJIkUKG0NyZWF0ZVNlY3VyaXR5QXNzZXRSZXNwb25zZRImCgRkYXRhGAEgASgLMhguYXBlcmlvLnYxLlNlY3VyaXR5QXNzZXQi8AUKGlVwZGF0ZVNlY3VyaXR5QXNzZXRSZXF1ZXN0EgoKAmlkGAEgASgJEhsKDmludGVncmF0aW9uX2lkGAIgASgJSACIAQESGgoNb3duZXJfdXNlcl9pZBgDIAEoCUgBiAEBEiMKFmJ1c2luZXNzX293bmVyX3VzZXJfaWQYBCABKAlIAogBARIRCgR0eXBlGAUgASgJSAOIAQESFQoIcHJvdmlkZXIYBiABKAlIBIgBARIRCgRuYW1lGAcgASgJSAWIAQESFAoHc3VtbWFyeRgIIAEoCUgGiAEBEhgKC2V4dGVybmFsX2lkGAkgASgJSAeIAQESDgoGbGFiZWxzGAogAygJEhYKDmxhYmVsc19wcmVzZW50GAsgASgIEhgKC2NyaXRpY2FsaXR5GAwgASgJSAiIAQESGwoOZXhwb3N1cmVfbGV2ZWwYDSABKAlICYgBARIdChBvd25lcnNoaXBfc3RhdHVzGA4gASgJSAqIAQESJAoXY29udGFpbnNfc2Vuc2l0aXZlX2RhdGEYDyABKAhIC4gBARIaCg1pc19wcml2aWxlZ2VkGBAgASgISAyIAQESFwoKcmlza19zY29yZRgRIAEoBUgNiAEBEh0KEGxhc3Rfb2JzZXJ2ZWRfYXQYEiABKAlIDogBAUIRCg9faW50ZWdyYXRpb25faWRCEAoOX293bmVyX3VzZXJfaWRCGQoXX2J1c2luZXNzX293bmVyX3VzZXJfaWRCBwoFX3R5cGVCCwoJX3Byb3ZpZGVyQgcKBV9uYW1lQgoKCF9zdW1tYXJ5Qg4KDF9leHRlcm5hbF9pZEIOCgxfY3JpdGljYWxpdHlCEQoPX2V4cG9zdXJlX2xldmVsQhMKEV9vd25lcnNoaXBfc3RhdHVzQhoKGF9jb250YWluc19zZW5zaXRpdmVfZGF0YUIQCg5faXNfcHJpdmlsZWdlZEINCgtfcmlza19zY29yZUITChFfbGFzdF9vYnNlcnZlZF9hdCJFChtVcGRhdGVTZWN1cml0eUFzc2V0UmVzcG9uc2USJgoEZGF0YRgBIAEoCzIYLmFwZXJpby52MS5TZWN1cml0eUFzc2V0IhsKGUxpc3RSaXNrRXhjZXB0aW9uc1JlcXVlc3QiRAoaTGlzdFJpc2tFeGNlcHRpb25zUmVzcG9uc2USJgoEZGF0YRgBIAMoCzIYLmFwZXJpby52MS5SaXNrRXhjZXB0aW9uIoIDCg1SaXNrRXhjZXB0aW9uEgoKAmlkGAEgASgJEg0KBXRpdGxlGAIgASgJEhEKCXJhdGlvbmFsZRgDIAEoCRIdChVjb21wZW5zYXRpbmdfY29udHJvbHMYBCADKAkSDgoGc3RhdHVzGAUgASgJEhIKCmV4cGlyZXNfYXQYBiABKAkSEwoLYXBwcm92ZWRfYXQYByABKAkSEgoKY3JlYXRlZF9hdBgIIAEoCRISCgp1cGRhdGVkX2F0GAkgASgJEiwKBWFzc2V0GAogASgLMh0uYXBlcmlvLnYxLlJpc2tFeGNlcHRpb25Bc3NldBIwCgdmaW5kaW5nGAsgASgLMh8uYXBlcmlvLnYxLlJpc2tFeGNlcHRpb25GaW5kaW5nEjAKCmNyZWF0ZWRfYnkYDCABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwSMQoLYXBwcm92ZWRfYnkYDSABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwiPAoSUmlza0V4Y2VwdGlvbkFzc2V0EgoKAmlkGAEgASgJEgwKBG5hbWUYAiABKAkSDAoEdHlwZRgDIAEoCSJTChRSaXNrRXhjZXB0aW9uRmluZGluZxIKCgJpZBgBIAEoCRINCgV0aXRsZRgCIAEoCRIQCghzZXZlcml0eRgDIAEoCRIOCgZzdGF0dXMYBCABKAkilwEKGkNyZWF0ZVJpc2tFeGNlcHRpb25SZXF1ZXN0EhAKCGFzc2V0X2lkGAEgASgJEhIKCmZpbmRpbmdfaWQYAiABKAkSDQoFdGl0bGUYAyABKAkSEQoJcmF0aW9uYWxlGAQgASgJEh0KFWNvbXBlbnNhdGluZ19jb250cm9scxgFIAMoCRISCgpleHBpcmVzX2F0GAYgASgJIkUKG0NyZWF0ZVJpc2tFeGNlcHRpb25SZXNwb25zZRImCgRkYXRhGAEgASgLMhguYXBlcmlvLnYxLlJpc2tFeGNlcHRpb24i+gEKGlVwZGF0ZVJpc2tFeGNlcHRpb25SZXF1ZXN0EgoKAmlkGAEgASgJEhIKBXRpdGxlGAIgASgJSACIAQESFgoJcmF0aW9uYWxlGAMgASgJSAGIAQESHQoVY29tcGVuc2F0aW5nX2NvbnRyb2xzGAQgAygJEiUKHWNvbXBlbnNhdGluZ19jb250cm9sc19wcmVzZW50GAUgASgIEhMKBnN0YXR1cxgGIAEoCUgCiAEBEhcKCmV4cGlyZXNfYXQYByABKAlIA4gBAUIICgZfdGl0bGVCDAoKX3JhdGlvbmFsZUIJCgdfc3RhdHVzQg0KC19leHBpcmVzX2F0IkUKG1VwZGF0ZVJpc2tFeGNlcHRpb25SZXNwb25zZRImCgRkYXRhGAEgASgLMhguYXBlcmlvLnYxLlJpc2tFeGNlcHRpb24i7QIKD0V4ZWN1dGl2ZVJlcG9ydBIKCgJpZBgBIAEoCRIOCgZwZXJpb2QYAiABKAkSFAoMcGVyaW9kX3N0YXJ0GAMgASgJEhIKCnBlcmlvZF9lbmQYBCABKAkSDQoFdGl0bGUYBSABKAkSDwoHc3VtbWFyeRgGIAEoCRIOCgZzdGF0dXMYByABKAkSGQoRa3BpX3NuYXBzaG90X2pzb24YCCABKAkSEAoIaGFzX2h0bWwYCSABKAgSDwoHaGFzX3BkZhgKIAEoCBIQCghodG1sX3VybBgLIAEoCRIPCgdwZGZfdXJsGAwgASgJEhIKCmNyZWF0ZWRfYXQYDSABKAkSEgoKdXBkYXRlZF9hdBgOIAEoCRIUCgxnZW5lcmF0ZWRfYXQYDyABKAkSFQoNZXJyb3JfbWVzc2FnZRgQIAEoCRIcChRyZXF1ZXN0ZWRfYnlfdXNlcl9pZBgRIAEoCRIQCgh0ZW1wbGF0ZRgSIAEoCSIdChtMaXN0RXhlY3V0aXZlUmVwb3J0c1JlcXVlc3QiSAocTGlzdEV4ZWN1dGl2ZVJlcG9ydHNSZXNwb25zZRIoCgRkYXRhGAEgAygLMhouYXBlcmlvLnYxLkV4ZWN1dGl2ZVJlcG9ydCInChlHZXRFeGVjdXRpdmVSZXBvcnRSZXF1ZXN0EgoKAmlkGAEgASgJIkYKGkdldEV4ZWN1dGl2ZVJlcG9ydFJlc3BvbnNlEigKBGRhdGEYASABKAsyGi5hcGVyaW8udjEuRXhlY3V0aXZlUmVwb3J0InkKHENyZWF0ZUV4ZWN1dGl2ZVJlcG9ydFJlcXVlc3QSDgoGcGVyaW9kGAEgASgJEg0KBXRpdGxlGAIgASgJEhQKDHBlcmlvZF9zdGFydBgDIAEoCRISCgpwZXJpb2RfZW5kGAQgASgJEhAKCHRlbXBsYXRlGAUgASgJIkkKHUNyZWF0ZUV4ZWN1dGl2ZVJlcG9ydFJlc3BvbnNlEigKBGRhdGEYASABKAsyGi5hcGVyaW8udjEuRXhlY3V0aXZlUmVwb3J0IioKHERlbGV0ZUV4ZWN1dGl2ZVJlcG9ydFJlcXVlc3QSCgoCaWQYASABKAkiMAodRGVsZXRlRXhlY3V0aXZlUmVwb3J0UmVzcG9uc2USDwoHZGVsZXRlZBgBIAEoCCKQAQoUQ29ubmVjdG9yQnVpbHRJblJ1bGUSCgoCaWQYASABKAkSEAoIcHJvdmlkZXIYAiABKAkSDQoFdGl0bGUYAyABKAkSEwoLZGVzY3JpcHRpb24YBCABKAkSEAoIc2V2ZXJpdHkYBSABKAkSEwoLZXZlbnRfdHlwZXMYBiADKAkSDwoHZW5hYmxlZBgHIAEoCCKpAQoTQ29ubmVjdG9yQ3VzdG9tUnVsZRIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEhAKCHNldmVyaXR5GAMgASgJEhIKCmV2ZW50X3R5cGUYBCABKAkSFgoOcHJlZGljYXRlX2pzb24YBSABKAkSDwoHZW5hYmxlZBgGIAEoCBISCgp1cGRhdGVkX2F0GAcgASgJEhUKDXN1YmplY3RfZmllbGQYCCABKAkiMwoZTGlzdENvbm5lY3RvclJ1bGVzUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCSKpAQoaTGlzdENvbm5lY3RvclJ1bGVzUmVzcG9uc2USFgoOaW50ZWdyYXRpb25faWQYASABKAkSEAoIcHJvdmlkZXIYAiABKAkSMQoIYnVpbHRfaW4YAyADKAsyHy5hcGVyaW8udjEuQ29ubmVjdG9yQnVpbHRJblJ1bGUSLgoGY3VzdG9tGAQgAygLMh4uYXBlcmlvLnYxLkNvbm5lY3RvckN1c3RvbVJ1bGUipQEKF0NyZWF0ZUN1c3RvbVJ1bGVSZXF1ZXN0EhYKDmludGVncmF0aW9uX2lkGAEgASgJEgwKBG5hbWUYAiABKAkSEAoIc2V2ZXJpdHkYAyABKAkSEgoKZXZlbnRfdHlwZRgEIAEoCRIWCg5wcmVkaWNhdGVfanNvbhgFIAEoCRIPCgdlbmFibGVkGAYgASgIEhUKDXN1YmplY3RfZmllbGQYByABKAkiJgoYQ3JlYXRlQ3VzdG9tUnVsZVJlc3BvbnNlEgoKAmlkGAEgASgJIrYBChdVcGRhdGVDdXN0b21SdWxlUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRIPCgdydWxlX2lkGAIgASgJEgwKBG5hbWUYAyABKAkSEAoIc2V2ZXJpdHkYBCABKAkSEgoKZXZlbnRfdHlwZRgFIAEoCRIWCg5wcmVkaWNhdGVfanNvbhgGIAEoCRIPCgdlbmFibGVkGAcgASgIEhUKDXN1YmplY3RfZmllbGQYCCABKAkiJgoYVXBkYXRlQ3VzdG9tUnVsZVJlc3BvbnNlEgoKAmlkGAEgASgJIkIKF0RlbGV0ZUN1c3RvbVJ1bGVSZXF1ZXN0EhYKDmludGVncmF0aW9uX2lkGAEgASgJEg8KB3J1bGVfaWQYAiABKAkiJgoYRGVsZXRlQ3VzdG9tUnVsZVJlc3BvbnNlEgoKAmlkGAEgASgJMug9Cg1BcGVyaW9TZXJ2aWNlEkAKB0NhbGxBcGkSGS5hcGVyaW8udjEuQ2FsbEFwaVJlcXVlc3QaGi5hcGVyaW8udjEuQ2FsbEFwaVJlc3BvbnNlEj0KBlNpZ251cBIYLmFwZXJpby52MS5TaWdudXBSZXF1ZXN0GhkuYXBlcmlvLnYxLlNpZ251cFJlc3BvbnNlEjoKBUxvZ2luEhcuYXBlcmlvLnYxLkxvZ2luUmVxdWVzdBoYLmFwZXJpby52MS5Mb2dpblJlc3BvbnNlEl4KEUdldEN1cnJlbnRTZXNzaW9uEiMuYXBlcmlvLnYxLkdldEN1cnJlbnRTZXNzaW9uUmVxdWVzdBokLmFwZXJpby52MS5HZXRDdXJyZW50U2Vzc2lvblJlc3BvbnNlEmcKFExvZ291dEN1cnJlbnRTZXNzaW9uEiYuYXBlcmlvLnYxLkxvZ291dEN1cnJlbnRTZXNzaW9uUmVxdWVzdBonLmFwZXJpby52MS5Mb2dvdXRDdXJyZW50U2Vzc2lvblJlc3BvbnNlElUKDkxpc3RXb3Jrc3BhY2VzEiAuYXBlcmlvLnYxLkxpc3RXb3Jrc3BhY2VzUmVxdWVzdBohLmFwZXJpby52MS5MaXN0V29ya3NwYWNlc1Jlc3BvbnNlElgKD1N3aXRjaFdvcmtzcGFjZRIhLmFwZXJpby52MS5Td2l0Y2hXb3Jrc3BhY2VSZXF1ZXN0GiIuYXBlcmlvLnYxLlN3aXRjaFdvcmtzcGFjZVJlc3BvbnNlEmcKFFJlcXVlc3RQYXNzd29yZFJlc2V0EiYuYXBlcmlvLnYxLlJlcXVlc3RQYXNzd29yZFJlc2V0UmVxdWVzdBonLmFwZXJpby52MS5SZXF1ZXN0UGFzc3dvcmRSZXNldFJlc3BvbnNlElIKDVJlc2V0UGFzc3dvcmQSHy5hcGVyaW8udjEuUmVzZXRQYXNzd29yZFJlcXVlc3QaIC5hcGVyaW8udjEuUmVzZXRQYXNzd29yZFJlc3BvbnNlEk8KDEFjY2VwdEludml0ZRIeLmFwZXJpby52MS5BY2NlcHRJbnZpdGVSZXF1ZXN0Gh8uYXBlcmlvLnYxLkFjY2VwdEludml0ZVJlc3BvbnNlEmEKEkJlZ2luTWZhRW5yb2xsbWVudBIkLmFwZXJpby52MS5CZWdpbk1mYUVucm9sbG1lbnRSZXF1ZXN0GiUuYXBlcmlvLnYxLkJlZ2luTWZhRW5yb2xsbWVudFJlc3BvbnNlEkYKCUVuYWJsZU1mYRIbLmFwZXJpby52MS5FbmFibGVNZmFSZXF1ZXN0GhwuYXBlcmlvLnYxLkVuYWJsZU1mYVJlc3BvbnNlEkkKCkRpc2FibGVNZmESHC5hcGVyaW8udjEuRGlzYWJsZU1mYVJlcXVlc3QaHS5hcGVyaW8udjEuRGlzYWJsZU1mYVJlc3BvbnNlEkwKC0NoZWNrSGVhbHRoEh0uYXBlcmlvLnYxLkNoZWNrSGVhbHRoUmVxdWVzdBoeLmFwZXJpby52MS5DaGVja0hlYWx0aFJlc3BvbnNlEmQKE0dldERhc2hib2FyZE1ldHJpY3MSJS5hcGVyaW8udjEuR2V0RGFzaGJvYXJkTWV0cmljc1JlcXVlc3QaJi5hcGVyaW8udjEuR2V0RGFzaGJvYXJkTWV0cmljc1Jlc3BvbnNlEk8KDExpc3RGaW5kaW5ncxIeLmFwZXJpby52MS5MaXN0RmluZGluZ3NSZXF1ZXN0Gh8uYXBlcmlvLnYxLkxpc3RGaW5kaW5nc1Jlc3BvbnNlEkkKCkdldEZpbmRpbmcSHC5hcGVyaW8udjEuR2V0RmluZGluZ1JlcXVlc3QaHS5hcGVyaW8udjEuR2V0RmluZGluZ1Jlc3BvbnNlEmQKE1VwZGF0ZUZpbmRpbmdTdGF0dXMSJS5hcGVyaW8udjEuVXBkYXRlRmluZGluZ1N0YXR1c1JlcXVlc3QaJi5hcGVyaW8udjEuVXBkYXRlRmluZGluZ1N0YXR1c1Jlc3BvbnNlElsKEFJlbWVkaWF0ZUZpbmRpbmcSIi5hcGVyaW8udjEuUmVtZWRpYXRlRmluZGluZ1JlcXVlc3QaIy5hcGVyaW8udjEuUmVtZWRpYXRlRmluZGluZ1Jlc3BvbnNlEl4KEUxpc3RTYWFzSW5jaWRlbnRzEiMuYXBlcmlvLnYxLkxpc3RTYWFzSW5jaWRlbnRzUmVxdWVzdBokLmFwZXJpby52MS5MaXN0U2Fhc0luY2lkZW50c1Jlc3BvbnNlElgKD0dldFNhYXNJbmNpZGVudBIhLmFwZXJpby52MS5HZXRTYWFzSW5jaWRlbnRSZXF1ZXN0GiIuYXBlcmlvLnYxLkdldFNhYXNJbmNpZGVudFJlc3BvbnNlEmEKEkNyZWF0ZVNhYXNJbmNpZGVudBIkLmFwZXJpby52MS5DcmVhdGVTYWFzSW5jaWRlbnRSZXF1ZXN0GiUuYXBlcmlvLnYxLkNyZWF0ZVNhYXNJbmNpZGVudFJlc3BvbnNlEnMKGFVwZGF0ZVNhYXNJbmNpZGVudFN0YXR1cxIqLmFwZXJpby52MS5VcGRhdGVTYWFzSW5jaWRlbnRTdGF0dXNSZXF1ZXN0GisuYXBlcmlvLnYxLlVwZGF0ZVNhYXNJbmNpZGVudFN0YXR1c1Jlc3BvbnNlEnYKGVByb3Bvc2VTYWFzUmVzcG9uc2VBY3Rpb24SKy5hcGVyaW8udjEuUHJvcG9zZVNhYXNSZXNwb25zZUFjdGlvblJlcXVlc3QaLC5hcGVyaW8udjEuUHJvcG9zZVNhYXNSZXNwb25zZUFjdGlvblJlc3BvbnNlEnYKGUFwcHJvdmVTYWFzUmVzcG9uc2VBY3Rpb24SKy5hcGVyaW8udjEuQXBwcm92ZVNhYXNSZXNwb25zZUFjdGlvblJlcXVlc3QaLC5hcGVyaW8udjEuQXBwcm92ZVNhYXNSZXNwb25zZUFjdGlvblJlc3BvbnNlEnYKGUV4ZWN1dGVTYWFzUmVzcG9uc2VBY3Rpb24SKy5hcGVyaW8udjEuRXhlY3V0ZVNhYXNSZXNwb25zZUFjdGlvblJlcXVlc3QaLC5hcGVyaW8udjEuRXhlY3V0ZVNhYXNSZXNwb25zZUFjdGlvblJlc3BvbnNlEmcKFExpc3RDb25uZWN0b3JDYXRhbG9nEiYuYXBlcmlvLnYxLkxpc3RDb25uZWN0b3JDYXRhbG9nUmVxdWVzdBonLmFwZXJpby52MS5MaXN0Q29ubmVjdG9yQ2F0YWxvZ1Jlc3BvbnNlElsKEExpc3RJbnRlZ3JhdGlvbnMSIi5hcGVyaW8udjEuTGlzdEludGVncmF0aW9uc1JlcXVlc3QaIy5hcGVyaW8udjEuTGlzdEludGVncmF0aW9uc1Jlc3BvbnNlEl4KEUNyZWF0ZUludGVncmF0aW9uEiMuYXBlcmlvLnYxLkNyZWF0ZUludGVncmF0aW9uUmVxdWVzdBokLmFwZXJpby52MS5DcmVhdGVJbnRlZ3JhdGlvblJlc3BvbnNlEl4KEURlbGV0ZUludGVncmF0aW9uEiMuYXBlcmlvLnYxLkRlbGV0ZUludGVncmF0aW9uUmVxdWVzdBokLmFwZXJpby52MS5EZWxldGVJbnRlZ3JhdGlvblJlc3BvbnNlEmcKFEdldEludGVncmF0aW9uQ2hlY2tzEiYuYXBlcmlvLnYxLkdldEludGVncmF0aW9uQ2hlY2tzUmVxdWVzdBonLmFwZXJpby52MS5HZXRJbnRlZ3JhdGlvbkNoZWNrc1Jlc3BvbnNlEnAKF1VwZGF0ZUludGVncmF0aW9uQ2hlY2tzEikuYXBlcmlvLnYxLlVwZGF0ZUludGVncmF0aW9uQ2hlY2tzUmVxdWVzdBoqLmFwZXJpby52MS5VcGRhdGVJbnRlZ3JhdGlvbkNoZWNrc1Jlc3BvbnNlEmEKEkxpc3RDb25uZWN0b3JSdWxlcxIkLmFwZXJpby52MS5MaXN0Q29ubmVjdG9yUnVsZXNSZXF1ZXN0GiUuYXBlcmlvLnYxLkxpc3RDb25uZWN0b3JSdWxlc1Jlc3BvbnNlElsKEENyZWF0ZUN1c3RvbVJ1bGUSIi5hcGVyaW8udjEuQ3JlYXRlQ3VzdG9tUnVsZVJlcXVlc3QaIy5hcGVyaW8udjEuQ3JlYXRlQ3VzdG9tUnVsZVJlc3BvbnNlElsKEFVwZGF0ZUN1c3RvbVJ1bGUSIi5hcGVyaW8udjEuVXBkYXRlQ3VzdG9tUnVsZVJlcXVlc3QaIy5hcGVyaW8udjEuVXBkYXRlQ3VzdG9tUnVsZVJlc3BvbnNlElsKEERlbGV0ZUN1c3RvbVJ1bGUSIi5hcGVyaW8udjEuRGVsZXRlQ3VzdG9tUnVsZVJlcXVlc3QaIy5hcGVyaW8udjEuRGVsZXRlQ3VzdG9tUnVsZVJlc3BvbnNlEnkKGkdldEdvb2dsZU1haWxib3hTY2FuQ29uZmlnEiwuYXBlcmlvLnYxLkdldEdvb2dsZU1haWxib3hTY2FuQ29uZmlnUmVxdWVzdBotLmFwZXJpby52MS5HZXRHb29nbGVNYWlsYm94U2NhbkNvbmZpZ1Jlc3BvbnNlEoIBCh1VcGRhdGVHb29nbGVNYWlsYm94U2NhbkNvbmZpZxIvLmFwZXJpby52MS5VcGRhdGVHb29nbGVNYWlsYm94U2NhbkNvbmZpZ1JlcXVlc3QaMC5hcGVyaW8udjEuVXBkYXRlR29vZ2xlTWFpbGJveFNjYW5Db25maWdSZXNwb25zZRKLAQogR2V0R29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWcSMi5hcGVyaW8udjEuR2V0R29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWdSZXF1ZXN0GjMuYXBlcmlvLnYxLkdldEdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnUmVzcG9uc2USlAEKI1VwZGF0ZUdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnEjUuYXBlcmlvLnYxLlVwZGF0ZUdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnUmVxdWVzdBo2LmFwZXJpby52MS5VcGRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1Jlc3BvbnNlEpoBCiVWYWxpZGF0ZUdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnEjcuYXBlcmlvLnYxLlZhbGlkYXRlR29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWdSZXF1ZXN0GjguYXBlcmlvLnYxLlZhbGlkYXRlR29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWdSZXNwb25zZRJ2ChlTdGFydEdvb2dsZVdvcmtzcGFjZU9BdXRoEisuYXBlcmlvLnYxLlN0YXJ0R29vZ2xlV29ya3NwYWNlT0F1dGhSZXF1ZXN0GiwuYXBlcmlvLnYxLlN0YXJ0R29vZ2xlV29ya3NwYWNlT0F1dGhSZXNwb25zZRJ2ChlHZXRJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50EisuYXBlcmlvLnYxLkdldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXF1ZXN0GiwuYXBlcmlvLnYxLkdldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRJ2ChlTZXRJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50EisuYXBlcmlvLnYxLlNldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXF1ZXN0GiwuYXBlcmlvLnYxLlNldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRJ8ChtDbGVhckludGVncmF0aW9uT0F1dGhDbGllbnQSLS5hcGVyaW8udjEuQ2xlYXJJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50UmVxdWVzdBouLmFwZXJpby52MS5DbGVhckludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRJnChRGb3JjZVN5bmNJbnRlZ3JhdGlvbhImLmFwZXJpby52MS5Gb3JjZVN5bmNJbnRlZ3JhdGlvblJlcXVlc3QaJy5hcGVyaW8udjEuRm9yY2VTeW5jSW50ZWdyYXRpb25SZXNwb25zZRJzChhHZXRJbnRlZ3JhdGlvblN5bmNTdGF0dXMSKi5hcGVyaW8udjEuR2V0SW50ZWdyYXRpb25TeW5jU3RhdHVzUmVxdWVzdBorLmFwZXJpby52MS5HZXRJbnRlZ3JhdGlvblN5bmNTdGF0dXNSZXNwb25zZRJzChhSdW5JbnRlZ3JhdGlvblNvdXJjZVN5bmMSKi5hcGVyaW8udjEuUnVuSW50ZWdyYXRpb25Tb3VyY2VTeW5jUmVxdWVzdBorLmFwZXJpby52MS5SdW5JbnRlZ3JhdGlvblNvdXJjZVN5bmNSZXNwb25zZRJ2ChlCYWNrZmlsbEludGVncmF0aW9uU291cmNlEisuYXBlcmlvLnYxLkJhY2tmaWxsSW50ZWdyYXRpb25Tb3VyY2VSZXF1ZXN0GiwuYXBlcmlvLnYxLkJhY2tmaWxsSW50ZWdyYXRpb25Tb3VyY2VSZXNwb25zZRJYCg9MaXN0U2llbUNhdGFsb2cSIS5hcGVyaW8udjEuTGlzdFNpZW1DYXRhbG9nUmVxdWVzdBoiLmFwZXJpby52MS5MaXN0U2llbUNhdGFsb2dSZXNwb25zZRJnChRMaXN0U2llbURlc3RpbmF0aW9ucxImLmFwZXJpby52MS5MaXN0U2llbURlc3RpbmF0aW9uc1JlcXVlc3QaJy5hcGVyaW8udjEuTGlzdFNpZW1EZXN0aW5hdGlvbnNSZXNwb25zZRJqChVDcmVhdGVTaWVtRGVzdGluYXRpb24SJy5hcGVyaW8udjEuQ3JlYXRlU2llbURlc3RpbmF0aW9uUmVxdWVzdBooLmFwZXJpby52MS5DcmVhdGVTaWVtRGVzdGluYXRpb25SZXNwb25zZRJqChVEZWxldGVTaWVtRGVzdGluYXRpb24SJy5hcGVyaW8udjEuRGVsZXRlU2llbURlc3RpbmF0aW9uUmVxdWVzdBooLmFwZXJpby52MS5EZWxldGVTaWVtRGVzdGluYXRpb25SZXNwb25zZRJkChNUZXN0U2llbURlc3RpbmF0aW9uEiUuYXBlcmlvLnYxLlRlc3RTaWVtRGVzdGluYXRpb25SZXF1ZXN0GiYuYXBlcmlvLnYxLlRlc3RTaWVtRGVzdGluYXRpb25SZXNwb25zZRJqChVMaXN0U2hhZG93SXRPYXV0aEFwcHMSJy5hcGVyaW8udjEuTGlzdFNoYWRvd0l0T2F1dGhBcHBzUmVxdWVzdBooLmFwZXJpby52MS5MaXN0U2hhZG93SXRPYXV0aEFwcHNSZXNwb25zZRJ5ChpMaXN0U2hhZG93SXRPYXV0aEFwcEdyYW50cxIsLmFwZXJpby52MS5MaXN0U2hhZG93SXRPYXV0aEFwcEdyYW50c1JlcXVlc3QaLS5hcGVyaW8udjEuTGlzdFNoYWRvd0l0T2F1dGhBcHBHcmFudHNSZXNwb25zZRJeChFHZXRUZW5hbnRTZXR0aW5ncxIjLmFwZXJpby52MS5HZXRUZW5hbnRTZXR0aW5nc1JlcXVlc3QaJC5hcGVyaW8udjEuR2V0VGVuYW50U2V0dGluZ3NSZXNwb25zZRJnChRVcGRhdGVUZW5hbnRTZXR0aW5ncxImLmFwZXJpby52MS5VcGRhdGVUZW5hbnRTZXR0aW5nc1JlcXVlc3QaJy5hcGVyaW8udjEuVXBkYXRlVGVuYW50U2V0dGluZ3NSZXNwb25zZRJeChFMaXN0VGVuYW50TWVtYmVycxIjLmFwZXJpby52MS5MaXN0VGVuYW50TWVtYmVyc1JlcXVlc3QaJC5hcGVyaW8udjEuTGlzdFRlbmFudE1lbWJlcnNSZXNwb25zZRJhChJDcmVhdGVUZW5hbnRNZW1iZXISJC5hcGVyaW8udjEuQ3JlYXRlVGVuYW50TWVtYmVyUmVxdWVzdBolLmFwZXJpby52MS5DcmVhdGVUZW5hbnRNZW1iZXJSZXNwb25zZRJqChVDcmVhdGVNZW1iZXJSZXNldExpbmsSJy5hcGVyaW8udjEuQ3JlYXRlTWVtYmVyUmVzZXRMaW5rUmVxdWVzdBooLmFwZXJpby52MS5DcmVhdGVNZW1iZXJSZXNldExpbmtSZXNwb25zZRJbChBVcGRhdGVNZW1iZXJSb2xlEiIuYXBlcmlvLnYxLlVwZGF0ZU1lbWJlclJvbGVSZXF1ZXN0GiMuYXBlcmlvLnYxLlVwZGF0ZU1lbWJlclJvbGVSZXNwb25zZRJSCg1MaXN0QXVkaXRMb2dzEh8uYXBlcmlvLnYxLkxpc3RBdWRpdExvZ3NSZXF1ZXN0GiAuYXBlcmlvLnYxLkxpc3RBdWRpdExvZ3NSZXNwb25zZRJkChNHZXRTZWN1cml0eU92ZXJ2aWV3EiUuYXBlcmlvLnYxLkdldFNlY3VyaXR5T3ZlcnZpZXdSZXF1ZXN0GiYuYXBlcmlvLnYxLkdldFNlY3VyaXR5T3ZlcnZpZXdSZXNwb25zZRJqChVMaXN0RW1haWxEb21haW5IZWFsdGgSJy5hcGVyaW8udjEuTGlzdEVtYWlsRG9tYWluSGVhbHRoUmVxdWVzdBooLmFwZXJpby52MS5MaXN0RW1haWxEb21haW5IZWFsdGhSZXNwb25zZRJnChRHZXRFbWFpbERvbWFpbkhlYWx0aBImLmFwZXJpby52MS5HZXRFbWFpbERvbWFpbkhlYWx0aFJlcXVlc3QaJy5hcGVyaW8udjEuR2V0RW1haWxEb21haW5IZWFsdGhSZXNwb25zZRJzChhSZWZyZXNoRW1haWxEb21haW5IZWFsdGgSKi5hcGVyaW8udjEuUmVmcmVzaEVtYWlsRG9tYWluSGVhbHRoUmVxdWVzdBorLmFwZXJpby52MS5SZWZyZXNoRW1haWxEb21haW5IZWFsdGhSZXNwb25zZRJhChJMaXN0U2VjdXJpdHlBc3NldHMSJC5hcGVyaW8udjEuTGlzdFNlY3VyaXR5QXNzZXRzUmVxdWVzdBolLmFwZXJpby52MS5MaXN0U2VjdXJpdHlBc3NldHNSZXNwb25zZRJkChNDcmVhdGVTZWN1cml0eUFzc2V0EiUuYXBlcmlvLnYxLkNyZWF0ZVNlY3VyaXR5QXNzZXRSZXF1ZXN0GiYuYXBlcmlvLnYxLkNyZWF0ZVNlY3VyaXR5QXNzZXRSZXNwb25zZRJkChNVcGRhdGVTZWN1cml0eUFzc2V0EiUuYXBlcmlvLnYxLlVwZGF0ZVNlY3VyaXR5QXNzZXRSZXF1ZXN0GiYuYXBlcmlvLnYxLlVwZGF0ZVNlY3VyaXR5QXNzZXRSZXNwb25zZRJhChJMaXN0Umlza0V4Y2VwdGlvbnMSJC5hcGVyaW8udjEuTGlzdFJpc2tFeGNlcHRpb25zUmVxdWVzdBolLmFwZXJpby52MS5MaXN0Umlza0V4Y2VwdGlvbnNSZXNwb25zZRJkChNDcmVhdGVSaXNrRXhjZXB0aW9uEiUuYXBlcmlvLnYxLkNyZWF0ZVJpc2tFeGNlcHRpb25SZXF1ZXN0GiYuYXBlcmlvLnYxLkNyZWF0ZVJpc2tFeGNlcHRpb25SZXNwb25zZRJkChNVcGRhdGVSaXNrRXhjZXB0aW9uEiUuYXBlcmlvLnYxLlVwZGF0ZVJpc2tFeGNlcHRpb25SZXF1ZXN0GiYuYXBlcmlvLnYxLlVwZGF0ZVJpc2tFeGNlcHRpb25SZXNwb25zZRJnChRMaXN0RXhlY3V0aXZlUmVwb3J0cxImLmFwZXJpby52MS5MaXN0RXhlY3V0aXZlUmVwb3J0c1JlcXVlc3QaJy5hcGVyaW8udjEuTGlzdEV4ZWN1dGl2ZVJlcG9ydHNSZXNwb25zZRJhChJHZXRFeGVjdXRpdmVSZXBvcnQSJC5hcGVyaW8udjEuR2V0RXhlY3V0aXZlUmVwb3J0UmVxdWVzdBolLmFwZXJpby52MS5HZXRFeGVjdXRpdmVSZXBvcnRSZXNwb25zZRJqChVDcmVhdGVFeGVjdXRpdmVSZXBvcnQSJy5hcGVyaW8udjEuQ3JlYXRlRXhlY3V0aXZlUmVwb3J0UmVxdWVzdBooLmFwZXJpby52MS5DcmVhdGVFeGVjdXRpdmVSZXBvcnRSZXNwb25zZRJqChVEZWxldGVFeGVjdXRpdmVSZXBvcnQSJy5hcGVyaW8udjEuRGVsZXRlRXhlY3V0aXZlUmVwb3J0UmVxdWVzdBooLmFwZXJpby52MS5EZWxldGVFeGVjdXRpdmVSZXBvcnRSZXNwb25zZUIxWi9naXRodWIuY29tL3dyaXRlci9hcGVyaW8vZ2VuL2FwZXJpby92MTthcGVyaW92MWIGcHJvdG8z", [file_google_protobuf_timestamp]); + fileDesc("ChNhcGVyaW8vdjEvYXBpLnByb3RvEglhcGVyaW8udjEiQQoOQ2FsbEFwaVJlcXVlc3QSDgoGbWV0aG9kGAEgASgJEgwKBHBhdGgYAiABKAkSEQoJYm9keV9qc29uGAMgASgJIiQKD0NhbGxBcGlSZXNwb25zZRIRCglib2R5X2pzb24YASABKAkipAEKDVNpZ251cFJlcXVlc3QSGQoRb3JnYW5pemF0aW9uX25hbWUYASABKAkSGQoRb3JnYW5pemF0aW9uX3NsdWcYAiABKAkSGgoSbm90aWZpY2F0aW9uX2VtYWlsGAMgASgJEhMKC293bmVyX2VtYWlsGAQgASgJEhoKEm93bmVyX2Rpc3BsYXlfbmFtZRgFIAEoCRIQCghwYXNzd29yZBgGIAEoCSI2Cg5TaWdudXBSZXNwb25zZRIkCgRkYXRhGAEgASgLMhYuYXBlcmlvLnYxLkF1dGhTZXNzaW9uIl0KDExvZ2luUmVxdWVzdBIZChFvcmdhbml6YXRpb25fc2x1ZxgBIAEoCRINCgVlbWFpbBgCIAEoCRIQCghwYXNzd29yZBgDIAEoCRIRCgl0b3RwX2NvZGUYBCABKAkiNQoNTG9naW5SZXNwb25zZRIkCgRkYXRhGAEgASgLMhYuYXBlcmlvLnYxLkF1dGhTZXNzaW9uIhoKGEdldEN1cnJlbnRTZXNzaW9uUmVxdWVzdCJBChlHZXRDdXJyZW50U2Vzc2lvblJlc3BvbnNlEiQKBGRhdGEYASABKAsyFi5hcGVyaW8udjEuQXV0aFNlc3Npb24iHQobTG9nb3V0Q3VycmVudFNlc3Npb25SZXF1ZXN0IkUKHExvZ291dEN1cnJlbnRTZXNzaW9uUmVzcG9uc2USJQoEZGF0YRgBIAEoCzIXLmFwZXJpby52MS5EZWxldGVSZXN1bHQiFwoVTGlzdFdvcmtzcGFjZXNSZXF1ZXN0IkYKFkxpc3RXb3Jrc3BhY2VzUmVzcG9uc2USLAoEZGF0YRgBIAMoCzIeLmFwZXJpby52MS5Xb3Jrc3BhY2VNZW1iZXJzaGlwIlgKFlN3aXRjaFdvcmtzcGFjZVJlcXVlc3QSGQoRb3JnYW5pemF0aW9uX3NsdWcYASABKAkSEQoJdG90cF9jb2RlGAIgASgJEhAKCHBhc3N3b3JkGAMgASgJIj8KF1N3aXRjaFdvcmtzcGFjZVJlc3BvbnNlEiQKBGRhdGEYASABKAsyFi5hcGVyaW8udjEuQXV0aFNlc3Npb24iRwobUmVxdWVzdFBhc3N3b3JkUmVzZXRSZXF1ZXN0EhkKEW9yZ2FuaXphdGlvbl9zbHVnGAEgASgJEg0KBWVtYWlsGAIgASgJIkwKHFJlcXVlc3RQYXNzd29yZFJlc2V0UmVzcG9uc2USLAoEZGF0YRgBIAEoCzIeLmFwZXJpby52MS5QYXNzd29yZFJlc2V0UmVzdWx0IjcKFFJlc2V0UGFzc3dvcmRSZXF1ZXN0Eg0KBXRva2VuGAEgASgJEhAKCHBhc3N3b3JkGAIgASgJIj0KFVJlc2V0UGFzc3dvcmRSZXNwb25zZRIkCgRkYXRhGAEgASgLMhYuYXBlcmlvLnYxLkF1dGhTZXNzaW9uIkwKE0FjY2VwdEludml0ZVJlcXVlc3QSDQoFdG9rZW4YASABKAkSFAoMZGlzcGxheV9uYW1lGAIgASgJEhAKCHBhc3N3b3JkGAMgASgJIjwKFEFjY2VwdEludml0ZVJlc3BvbnNlEiQKBGRhdGEYASABKAsyFi5hcGVyaW8udjEuQXV0aFNlc3Npb24iGwoZQmVnaW5NZmFFbnJvbGxtZW50UmVxdWVzdCJEChpCZWdpbk1mYUVucm9sbG1lbnRSZXNwb25zZRImCgRkYXRhGAEgASgLMhguYXBlcmlvLnYxLk1mYUVucm9sbG1lbnQiIAoQRW5hYmxlTWZhUmVxdWVzdBIMCgRjb2RlGAEgASgJIjkKEUVuYWJsZU1mYVJlc3BvbnNlEiQKBGRhdGEYASABKAsyFi5hcGVyaW8udjEuQXV0aFNlc3Npb24iMwoRRGlzYWJsZU1mYVJlcXVlc3QSEAoIcGFzc3dvcmQYASABKAkSDAoEY29kZRgCIAEoCSI6ChJEaXNhYmxlTWZhUmVzcG9uc2USJAoEZGF0YRgBIAEoCzIWLmFwZXJpby52MS5BdXRoU2Vzc2lvbiKgAQoLQXV0aFNlc3Npb24SDQoFdG9rZW4YASABKAkSIQoEdXNlchgCIAEoCzITLmFwZXJpby52MS5BdXRoVXNlchIxCgxvcmdhbml6YXRpb24YAyABKAsyGy5hcGVyaW8udjEuQXV0aE9yZ2FuaXphdGlvbhIsCgxhdXRoX2NvbnRleHQYBCABKAsyFi5hcGVyaW8udjEuQXV0aENvbnRleHQiXgoIQXV0aFVzZXISCgoCaWQYASABKAkSDQoFZW1haWwYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJEhMKC21mYV9lbmFibGVkGAQgASgIEgwKBHJvbGUYBSABKAkiOgoQQXV0aE9yZ2FuaXphdGlvbhIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEgwKBHNsdWcYAyABKAkisQMKC0F1dGhDb250ZXh0EhEKCXByaW5jaXBhbBgBIAEoCRIRCgl0ZW5hbnRfaWQYAiABKAkSEwoLdGVuYW50X3NsdWcYAyABKAkSFwoPY3JlZGVudGlhbF9raW5kGAQgASgJEhEKCWF1dGhfbW9kZRgFIAEoCRIXCg90b2tlbl90cmFuc3BvcnQYBiABKAkSGAoQY2VyZWJyb19yZXNvdXJjZRgHIAEoCRIXCg9hbGxvd2VkX3RlbmFudHMYCCADKAkSFgoOY2VyZWJyb19zY29wZXMYCSADKAkSDgoGZ3JvdXBzGAogAygJEhwKFGNlcmVicm9fbWNwX3Jlc291cmNlGAsgASgJEioKImNlcmVicm9fbWNwX3Jlc291cmNlX21ldGFkYXRhX3BhdGgYDCABKAkSOAowY2VyZWJyb19vYXV0aF9hdXRob3JpemF0aW9uX3NlcnZlcl9tZXRhZGF0YV9wYXRoGA0gASgJEh8KF2NlcmVicm9fbWNwX2dyYW50X3R5cGVzGA4gAygJEiIKGmNlcmVicm9fbWNwX2JlYXJlcl9tZXRob2RzGA8gAygJIlwKE1dvcmtzcGFjZU1lbWJlcnNoaXASCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRIMCgRzbHVnGAMgASgJEgwKBHJvbGUYBCABKAkSDwoHY3VycmVudBgFIAEoCCJ7ChNQYXNzd29yZFJlc2V0UmVzdWx0EhAKCGFjY2VwdGVkGAEgASgIEhAKCGRlbGl2ZXJ5GAIgASgJEhEKCXJlc2V0X3VybBgDIAEoCRISCgpleHBpcmVzX2F0GAQgASgJEhkKEW9yZ2FuaXphdGlvbl9uYW1lGAUgASgJIjQKDU1mYUVucm9sbG1lbnQSDgoGc2VjcmV0GAEgASgJEhMKC290cGF1dGhfdXJsGAIgASgJIhQKEkNoZWNrSGVhbHRoUmVxdWVzdCKWAQoTQ2hlY2tIZWFsdGhSZXNwb25zZRIOCgZzdGF0dXMYASABKAkSDwoHc2VydmljZRgCIAEoCRIuCgpjaGVja2VkX2F0GAMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIuCgpjb21wb25lbnRzGAQgAygLMhouYXBlcmlvLnYxLkhlYWx0aENvbXBvbmVudCI/Cg9IZWFsdGhDb21wb25lbnQSDAoEbmFtZRgBIAEoCRIOCgZzdGF0dXMYAiABKAkSDgoGZGV0YWlsGAMgASgJIhwKGkdldERhc2hib2FyZE1ldHJpY3NSZXF1ZXN0IkgKG0dldERhc2hib2FyZE1ldHJpY3NSZXNwb25zZRIpCgRkYXRhGAEgASgLMhsuYXBlcmlvLnYxLkRhc2hib2FyZE1ldHJpY3MiggEKEERhc2hib2FyZE1ldHJpY3MSGAoQdG90YWxfcmlza19zY29yZRgBIAEoBRIeChZvcGVuX2NyaXRpY2FsX2ZpbmRpbmdzGAIgASgFEhYKDmNvbm5lY3RlZF9hcHBzGAMgASgFEhwKFGV2ZW50X2luZ2VzdGlvbl9yYXRlGAQgASgFIoABChNMaXN0RmluZGluZ3NSZXF1ZXN0EhAKCHNldmVyaXR5GAEgASgJEg4KBnN0YXR1cxgCIAEoCRIQCghwcm92aWRlchgDIAEoCRIWCg5pbnRlZ3JhdGlvbl9pZBgEIAEoCRINCgVsaW1pdBgFIAEoBRIOCgZjdXJzb3IYBiABKAkiYAoUTGlzdEZpbmRpbmdzUmVzcG9uc2USIAoEZGF0YRgBIAMoCzISLmFwZXJpby52MS5GaW5kaW5nEiYKCXBhZ2VfaW5mbxgCIAEoCzITLmFwZXJpby52MS5QYWdlSW5mbyIfChFHZXRGaW5kaW5nUmVxdWVzdBIKCgJpZBgBIAEoCSI2ChJHZXRGaW5kaW5nUmVzcG9uc2USIAoEZGF0YRgBIAEoCzISLmFwZXJpby52MS5GaW5kaW5nIlEKGlVwZGF0ZUZpbmRpbmdTdGF0dXNSZXF1ZXN0EgoKAmlkGAEgASgJEg4KBnN0YXR1cxgCIAEoCRIXCg9yZXNvbHV0aW9uX25vdGUYAyABKAkiSwobVXBkYXRlRmluZGluZ1N0YXR1c1Jlc3BvbnNlEiwKBGRhdGEYASABKAsyHi5hcGVyaW8udjEuRmluZGluZ1N0YXR1c1VwZGF0ZSIxChNGaW5kaW5nU3RhdHVzVXBkYXRlEgoKAmlkGAEgASgJEg4KBnN0YXR1cxgCIAEoCSJmChdSZW1lZGlhdGVGaW5kaW5nUmVxdWVzdBISCgpmaW5kaW5nX2lkGAEgASgJEg4KBmFjdGlvbhgCIAEoCRIZChF0YXJnZXRfaWRlbnRpZmllchgDIAEoCRIMCgRub3RlGAQgASgJIkYKGFJlbWVkaWF0ZUZpbmRpbmdSZXNwb25zZRIqCgRkYXRhGAEgASgLMhwuYXBlcmlvLnYxLlJlbWVkaWF0aW9uUmVzdWx0IocBChFSZW1lZGlhdGlvblJlc3VsdBISCgpmaW5kaW5nX2lkGAEgASgJEg4KBmFjdGlvbhgCIAEoCRIPCgdzdWNjZXNzGAMgASgIEg8KB21lc3NhZ2UYBCABKAkSGwoTcHJvdmlkZXJfcmVxdWVzdF9pZBgFIAEoCRIPCgdlZmZlY3RzGAYgAygJItoCCgdGaW5kaW5nEgoKAmlkGAEgASgJEhAKCGFzc2V0X2lkGAIgASgJEg0KBXRpdGxlGAMgASgJEhMKC2Rlc2NyaXB0aW9uGAQgASgJEhAKCHNldmVyaXR5GAUgASgJEg4KBnN0YXR1cxgGIAEoCRISCgpyaXNrX3Njb3JlGAcgASgFEhkKEXJlbWVkaWF0aW9uX3N0ZXBzGAggAygJEhUKDWV2aWRlbmNlX2pzb24YCSABKAkSEwoLZGV0ZWN0ZWRfYXQYCiABKAkSEwoLcmVzb2x2ZWRfYXQYCyABKAkSMgoLaW50ZWdyYXRpb24YDCABKAsyHS5hcGVyaW8udjEuRmluZGluZ0ludGVncmF0aW9uEgwKBHRhZ3MYDSADKAkSOQoPY2VyZWJyb19jb250ZXh0GA4gASgLMiAuYXBlcmlvLnYxLkZpbmRpbmdDZXJlYnJvQ29udGV4dCJIChJGaW5kaW5nSW50ZWdyYXRpb24SCgoCaWQYASABKAkSEAoIcHJvdmlkZXIYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJIqsDChVGaW5kaW5nQ2VyZWJyb0NvbnRleHQSDgoGc291cmNlGAEgASgJEgwKBG1vZGUYAiABKAkSGQoRc291cmNlX3J1bnRpbWVfaWQYAyABKAkSGAoQZmluZGluZ19jb250cmFjdBgEIAEoCRIXCg9zb3VyY2VfZXZlbnRfaWQYBSABKAkSEwoLY2xhaW1fY291bnQYBiABKAUSNwoPY2xhaW1fc3VtbWFyaWVzGAcgAygLMh4uYXBlcmlvLnYxLkNlcmVicm9DbGFpbVN1bW1hcnkSNAoNZ3JhcGhfc2lnbmFscxgIIAMoCzIdLmFwZXJpby52MS5DZXJlYnJvR3JhcGhTaWduYWwSLQoIZW50aXRpZXMYCSADKAsyGy5hcGVyaW8udjEuQ2VyZWJyb0VudGl0eVJlZhIwCgtncmFwaF9wYXRocxgKIAMoCzIbLmFwZXJpby52MS5DZXJlYnJvR3JhcGhQYXRoEikKA21jcBgLIAEoCzIcLmFwZXJpby52MS5DZXJlYnJvTUNQQ29udGV4dBIWCg5yZXNwb25zZV9oaW50cxgMIAMoCSJ7ChNDZXJlYnJvQ2xhaW1TdW1tYXJ5EhIKCmNsYWltX3R5cGUYASABKAkSEQoJcHJlZGljYXRlGAIgASgJEhMKC3N1YmplY3RfdXJuGAMgASgJEhIKCm9iamVjdF91cm4YBCABKAkSFAoMc291cmNlX2V2ZW50GAUgASgJInAKEkNlcmVicm9HcmFwaFNpZ25hbBINCgVsYWJlbBgBIAEoCRIRCglwcmVkaWNhdGUYAiABKAkSEgoKY29uZmlkZW5jZRgDIAEoBRISCgplbnRpdHlfdXJuGAQgASgJEhAKCGV2aWRlbmNlGAUgASgJIk4KEENlcmVicm9FbnRpdHlSZWYSCwoDdXJuGAEgASgJEgwKBHR5cGUYAiABKAkSDQoFbGFiZWwYAyABKAkSEAoIcHJvdmlkZXIYBCABKAkiZwoQQ2VyZWJyb0dyYXBoUGF0aBIKCgJpZBgBIAEoCRINCgV0aXRsZRgCIAEoCRIMCgRyaXNrGAMgASgJEioKBW5vZGVzGAQgAygLMhsuYXBlcmlvLnYxLkNlcmVicm9FbnRpdHlSZWYingEKEUNlcmVicm9NQ1BDb250ZXh0Eg4KBnNlcnZlchgBIAEoCRIUCgxyZXNvdXJjZV91cmkYAiABKAkSEQoJbWltZV90eXBlGAMgASgJEg0KBXRvb2xzGAQgAygJEkEKEnJlc291cmNlX3RlbXBsYXRlcxgFIAMoCzIlLmFwZXJpby52MS5DZXJlYnJvTUNQUmVzb3VyY2VUZW1wbGF0ZSJoChpDZXJlYnJvTUNQUmVzb3VyY2VUZW1wbGF0ZRIUCgx1cmlfdGVtcGxhdGUYASABKAkSDAoEbmFtZRgCIAEoCRITCgtkZXNjcmlwdGlvbhgDIAEoCRIRCgltaW1lX3R5cGUYBCABKAkidQoYTGlzdFNhYXNJbmNpZGVudHNSZXF1ZXN0Eg4KBnN0YXR1cxgBIAEoCRIQCghzZXZlcml0eRgCIAEoCRIYChBhc3NpZ25lZV91c2VyX2lkGAMgASgJEg0KBWxpbWl0GAQgASgFEg4KBmN1cnNvchgFIAEoCSKbAQoZTGlzdFNhYXNJbmNpZGVudHNSZXNwb25zZRIlCgRkYXRhGAEgAygLMhcuYXBlcmlvLnYxLlNhYXNJbmNpZGVudBImCglwYWdlX2luZm8YAiABKAsyEy5hcGVyaW8udjEuUGFnZUluZm8SLwoHbWV0cmljcxgDIAEoCzIeLmFwZXJpby52MS5TYWFzSW5jaWRlbnRNZXRyaWNzIiQKFkdldFNhYXNJbmNpZGVudFJlcXVlc3QSCgoCaWQYASABKAkiRgoXR2V0U2Fhc0luY2lkZW50UmVzcG9uc2USKwoEZGF0YRgBIAEoCzIdLmFwZXJpby52MS5TYWFzSW5jaWRlbnREZXRhaWwikAEKGUNyZWF0ZVNhYXNJbmNpZGVudFJlcXVlc3QSDQoFdGl0bGUYASABKAkSDwoHc3VtbWFyeRgCIAEoCRIQCghzZXZlcml0eRgDIAEoCRITCgtmaW5kaW5nX2lkcxgEIAMoCRISCgpvd25lcl90ZWFtGAUgASgJEhgKEGFzc2lnbmVlX3VzZXJfaWQYBiABKAkiSQoaQ3JlYXRlU2Fhc0luY2lkZW50UmVzcG9uc2USKwoEZGF0YRgBIAEoCzIdLmFwZXJpby52MS5TYWFzSW5jaWRlbnREZXRhaWwiSwofVXBkYXRlU2Fhc0luY2lkZW50U3RhdHVzUmVxdWVzdBIKCgJpZBgBIAEoCRIOCgZzdGF0dXMYAiABKAkSDAoEbm90ZRgDIAEoCSJJCiBVcGRhdGVTYWFzSW5jaWRlbnRTdGF0dXNSZXNwb25zZRIlCgRkYXRhGAEgASgLMhcuYXBlcmlvLnYxLlNhYXNJbmNpZGVudCLmAQogUHJvcG9zZVNhYXNSZXNwb25zZUFjdGlvblJlcXVlc3QSEwoLaW5jaWRlbnRfaWQYASABKAkSEgoKZmluZGluZ19pZBgCIAEoCRIOCgZhY3Rpb24YAyABKAkSEAoIcHJvdmlkZXIYBCABKAkSEwoLdGFyZ2V0X3R5cGUYBSABKAkSGQoRdGFyZ2V0X2lkZW50aWZpZXIYBiABKAkSEQoJcmF0aW9uYWxlGAcgASgJEh4KEWFwcHJvdmFsX3JlcXVpcmVkGAggASgISACIAQFCFAoSX2FwcHJvdmFsX3JlcXVpcmVkIlAKIVByb3Bvc2VTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRIrCgRkYXRhGAEgASgLMh0uYXBlcmlvLnYxLlNhYXNSZXNwb25zZUFjdGlvbiI8CiBBcHByb3ZlU2Fhc1Jlc3BvbnNlQWN0aW9uUmVxdWVzdBIKCgJpZBgBIAEoCRIMCgRub3RlGAIgASgJIlAKIUFwcHJvdmVTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRIrCgRkYXRhGAEgASgLMh0uYXBlcmlvLnYxLlNhYXNSZXNwb25zZUFjdGlvbiI8CiBFeGVjdXRlU2Fhc1Jlc3BvbnNlQWN0aW9uUmVxdWVzdBIKCgJpZBgBIAEoCRIMCgRub3RlGAIgASgJIlAKIUV4ZWN1dGVTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRIrCgRkYXRhGAEgASgLMh0uYXBlcmlvLnYxLlNhYXNSZXNwb25zZUFjdGlvbiKYAQoTU2Fhc0luY2lkZW50TWV0cmljcxIMCgRvcGVuGAEgASgFEhUKDWludmVzdGlnYXRpbmcYAiABKAUSEQoJY29udGFpbmVkGAMgASgFEhAKCHJlc29sdmVkGAQgASgFEhUKDWNyaXRpY2FsX29wZW4YBSABKAUSIAoYcmVzcG9uc2VfYWN0aW9uc19wZW5kaW5nGAYgASgFItkDCgxTYWFzSW5jaWRlbnQSCgoCaWQYASABKAkSDQoFdGl0bGUYAiABKAkSDwoHc3VtbWFyeRgDIAEoCRIQCghzZXZlcml0eRgEIAEoCRIOCgZzdGF0dXMYBSABKAkSGAoQY29uZmlkZW5jZV9zY29yZRgGIAEoBRISCgpvd25lcl90ZWFtGAcgASgJEi4KCGFzc2lnbmVlGAggASgLMhwuYXBlcmlvLnYxLlNlY3VyaXR5UHJpbmNpcGFsEhkKEWZpcnN0X2RldGVjdGVkX2F0GAkgASgJEhgKEGxhc3RfYWN0aXZpdHlfYXQYCiABKAkSEgoKc2xhX2R1ZV9hdBgLIAEoCRITCgtyZXNvbHZlZF9hdBgMIAEoCRIcChRjZXJlYnJvX2NvbnRleHRfanNvbhgNIAEoCRISCgpjcmVhdGVkX2F0GA4gASgJEhIKCnVwZGF0ZWRfYXQYDyABKAkSFQoNZmluZGluZ19jb3VudBgQIAEoBRIaChJvcGVuX2ZpbmRpbmdfY291bnQYESABKAUSHQoVcmVzcG9uc2VfYWN0aW9uX2NvdW50GBIgASgFEicKH2NvbXBsZXRlZF9yZXNwb25zZV9hY3Rpb25fY291bnQYEyABKAUi1gEKElNhYXNJbmNpZGVudERldGFpbBIpCghpbmNpZGVudBgBIAEoCzIXLmFwZXJpby52MS5TYWFzSW5jaWRlbnQSJAoIZmluZGluZ3MYAiADKAsyEi5hcGVyaW8udjEuRmluZGluZxI2Cgh0aW1lbGluZRgDIAMoCzIkLmFwZXJpby52MS5TYWFzSW5jaWRlbnRUaW1lbGluZUV2ZW50EjcKEHJlc3BvbnNlX2FjdGlvbnMYBCADKAsyHS5hcGVyaW8udjEuU2Fhc1Jlc3BvbnNlQWN0aW9uIv0BChlTYWFzSW5jaWRlbnRUaW1lbGluZUV2ZW50EgoKAmlkGAEgASgJEhMKC2luY2lkZW50X2lkGAIgASgJEhIKCmZpbmRpbmdfaWQYAyABKAkSGgoScmVzcG9uc2VfYWN0aW9uX2lkGAQgASgJEgwKBGtpbmQYBSABKAkSDQoFdGl0bGUYBiABKAkSEwoLZGVzY3JpcHRpb24YByABKAkSDQoFYWN0b3IYCCABKAkSDgoGc291cmNlGAkgASgJEhUKDWV2aWRlbmNlX2pzb24YCiABKAkSEwoLb2NjdXJyZWRfYXQYCyABKAkSEgoKY3JlYXRlZF9hdBgMIAEoCSLwAwoSU2Fhc1Jlc3BvbnNlQWN0aW9uEgoKAmlkGAEgASgJEhMKC2luY2lkZW50X2lkGAIgASgJEhIKCmZpbmRpbmdfaWQYAyABKAkSDgoGYWN0aW9uGAQgASgJEhAKCHByb3ZpZGVyGAUgASgJEhMKC3RhcmdldF90eXBlGAYgASgJEhkKEXRhcmdldF9pZGVudGlmaWVyGAcgASgJEg4KBnN0YXR1cxgIIAEoCRIZChFhcHByb3ZhbF9yZXF1aXJlZBgJIAEoCBIRCglyYXRpb25hbGUYCiABKAkSMQoLYXBwcm92ZWRfYnkYCyABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwSEwoLYXBwcm92ZWRfYXQYDCABKAkSEwoLZXhlY3V0ZWRfYXQYDSABKAkSFQoNZXJyb3JfbWVzc2FnZRgOIAEoCRITCgtyZXN1bHRfanNvbhgPIAEoCRISCgpjcmVhdGVkX2F0GBAgASgJEhIKCnVwZGF0ZWRfYXQYESABKAkSMQoLcHJvcG9zZWRfYnkYEiABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwSMQoLZXhlY3V0ZWRfYnkYEyABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwiLgoIUGFnZUluZm8SDQoFdG90YWwYASABKAUSEwoLbmV4dF9jdXJzb3IYAiABKAkiHQobTGlzdENvbm5lY3RvckNhdGFsb2dSZXF1ZXN0IkwKHExpc3RDb25uZWN0b3JDYXRhbG9nUmVzcG9uc2USLAoEZGF0YRgBIAMoCzIeLmFwZXJpby52MS5Db25uZWN0b3JEZWZpbml0aW9uIuQCChNDb25uZWN0b3JEZWZpbml0aW9uEhAKCHByb3ZpZGVyGAEgASgJEgwKBG5hbWUYAiABKAkSEAoIY2F0ZWdvcnkYAyABKAkSFAoMYXZhaWxhYmlsaXR5GAQgASgJEhYKDnJlYWRpbmVzc19ub3RlGAUgASgJEhMKC2Rlc2NyaXB0aW9uGAYgASgJEhMKC3JlYWRfc2NvcGVzGAcgAygJEhoKEnJlbWVkaWF0aW9uX3Njb3BlcxgIIAMoCRI5ChNyZW1lZGlhdGlvbl9hY3Rpb25zGAkgAygLMhwuYXBlcmlvLnYxLlJlbWVkaWF0aW9uQWN0aW9uEi8KDmZpbmRpbmdfY2hlY2tzGAogAygLMhcuYXBlcmlvLnYxLkZpbmRpbmdDaGVjaxIQCghkb2NzX3VybBgLIAEoCRIpCgZmaWVsZHMYDCADKAsyGS5hcGVyaW8udjEuQ29ubmVjdG9yRmllbGQigQEKDkNvbm5lY3RvckZpZWxkEgsKA2tleRgBIAEoCRINCgVsYWJlbBgCIAEoCRITCgtwbGFjZWhvbGRlchgDIAEoCRIOCgZoZWxwZXIYBCABKAkSDAoEdHlwZRgFIAEoCRIQCghyZXF1aXJlZBgGIAEoCBIOCgZzZWNyZXQYByABKAgiWwoRUmVtZWRpYXRpb25BY3Rpb24SCwoDa2V5GAEgASgJEg0KBWxhYmVsGAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJEhUKDXNldmVyaXR5X2hpbnQYBCABKAkibwoMRmluZGluZ0NoZWNrEgsKA2tleRgBIAEoCRINCgV0aXRsZRgCIAEoCRITCgtkZXNjcmlwdGlvbhgDIAEoCRIVCg1zZXZlcml0eV9oaW50GAQgASgJEhcKD2RlZmF1bHRfZW5hYmxlZBgFIAEoCCIZChdMaXN0SW50ZWdyYXRpb25zUmVxdWVzdCJKChhMaXN0SW50ZWdyYXRpb25zUmVzcG9uc2USLgoEZGF0YRgBIAMoCzIgLmFwZXJpby52MS5JbnRlZ3JhdGlvbkNvbm5lY3Rpb24iqAIKFUludGVncmF0aW9uQ29ubmVjdGlvbhIKCgJpZBgBIAEoCRIQCghwcm92aWRlchgCIAEoCRIUCgxkaXNwbGF5X25hbWUYAyABKAkSGwoTZXh0ZXJuYWxfYWNjb3VudF9pZBgEIAEoCRIOCgZzdGF0dXMYBSABKAkSDAoEbW9kZRgGIAEoCRIOCgZzY29wZXMYByADKAkSFwoPZGlzYWJsZWRfY2hlY2tzGAggAygJEiMKG2dvb2dsZV9tYWlsYm94X3NjYW5fZW5hYmxlZBgJIAEoCBIoCiBnb29nbGVfbWFpbGJveF9zY2FuX2NsaWVudF9lbWFpbBgKIAEoCRIUCgxsYXN0X3N5bmNfYXQYCyABKAkSEgoKY3JlYXRlZF9hdBgMIAEoCSKlAQoYQ3JlYXRlSW50ZWdyYXRpb25SZXF1ZXN0EhAKCHByb3ZpZGVyGAEgASgJEhQKDGRpc3BsYXlfbmFtZRgCIAEoCRIbChNleHRlcm5hbF9hY2NvdW50X2lkGAMgASgJEgwKBG1vZGUYBCABKAkSNgoLY3JlZGVudGlhbHMYBSABKAsyIS5hcGVyaW8udjEuSW50ZWdyYXRpb25DcmVkZW50aWFscyJdChZJbnRlZ3JhdGlvbkNyZWRlbnRpYWxzEhQKDGFjY2Vzc190b2tlbhgBIAEoCRIVCg1yZWZyZXNoX3Rva2VuGAIgASgJEhYKDndlYmhvb2tfc2VjcmV0GAMgASgJIksKGUNyZWF0ZUludGVncmF0aW9uUmVzcG9uc2USLgoEZGF0YRgBIAEoCzIgLmFwZXJpby52MS5JbnRlZ3JhdGlvbkNvbm5lY3Rpb24iJgoYRGVsZXRlSW50ZWdyYXRpb25SZXF1ZXN0EgoKAmlkGAEgASgJIkIKGURlbGV0ZUludGVncmF0aW9uUmVzcG9uc2USJQoEZGF0YRgBIAEoCzIXLmFwZXJpby52MS5EZWxldGVSZXN1bHQiGgoMRGVsZXRlUmVzdWx0EgoKAm9rGAEgASgIIjUKG0dldEludGVncmF0aW9uQ2hlY2tzUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCSJOChxHZXRJbnRlZ3JhdGlvbkNoZWNrc1Jlc3BvbnNlEi4KBGRhdGEYASABKAsyIC5hcGVyaW8udjEuSW50ZWdyYXRpb25DaGVja1N0YXRlIoUBCh5VcGRhdGVJbnRlZ3JhdGlvbkNoZWNrc1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkSFwoPZGlzYWJsZWRfY2hlY2tzGAIgAygJEhYKDmRpc2FibGVfcmVhc29uGAMgASgJEhoKEmRpc2FibGVfZXhwaXJlc19hdBgEIAEoCSJRCh9VcGRhdGVJbnRlZ3JhdGlvbkNoZWNrc1Jlc3BvbnNlEi4KBGRhdGEYASABKAsyIC5hcGVyaW8udjEuSW50ZWdyYXRpb25DaGVja1N0YXRlIncKFUludGVncmF0aW9uQ2hlY2tTdGF0ZRIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRIXCg9kaXNhYmxlZF9jaGVja3MYAiADKAkSLQoGY2hlY2tzGAMgAygLMh0uYXBlcmlvLnYxLkZpbmRpbmdDaGVja1N0YXR1cyKGAQoSRmluZGluZ0NoZWNrU3RhdHVzEgsKA2tleRgBIAEoCRINCgV0aXRsZRgCIAEoCRITCgtkZXNjcmlwdGlvbhgDIAEoCRIVCg1zZXZlcml0eV9oaW50GAQgASgJEhcKD2RlZmF1bHRfZW5hYmxlZBgFIAEoCBIPCgdlbmFibGVkGAYgASgIIjsKIUdldEdvb2dsZU1haWxib3hTY2FuQ29uZmlnUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCSJWCiJHZXRHb29nbGVNYWlsYm94U2NhbkNvbmZpZ1Jlc3BvbnNlEjAKBGRhdGEYASABKAsyIi5hcGVyaW8udjEuR29vZ2xlTWFpbGJveFNjYW5Db25maWciigEKJFVwZGF0ZUdvb2dsZU1haWxib3hTY2FuQ29uZmlnUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRIPCgdlbmFibGVkGAIgASgIEiQKHHNlcnZpY2VfYWNjb3VudF9jbGllbnRfZW1haWwYAyABKAkSEwoLcHJpdmF0ZV9rZXkYBCABKAkiWQolVXBkYXRlR29vZ2xlTWFpbGJveFNjYW5Db25maWdSZXNwb25zZRIwCgRkYXRhGAEgASgLMiIuYXBlcmlvLnYxLkdvb2dsZU1haWxib3hTY2FuQ29uZmlnIlAKF0dvb2dsZU1haWxib3hTY2FuQ29uZmlnEg8KB2VuYWJsZWQYASABKAgSJAocc2VydmljZV9hY2NvdW50X2NsaWVudF9lbWFpbBgCIAEoCSJBCidHZXRHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkiYgooR2V0R29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWdSZXNwb25zZRI2CgRkYXRhGAEgASgLMiguYXBlcmlvLnYxLkdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnIv8BCipVcGRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkSDwoHZW5hYmxlZBgCIAEoCBISCgpwcm9qZWN0X2lkGAMgASgJEhYKDnJhd19kYXRhc2V0X2lkGAQgASgJEhIKCmRhdGFzZXRfaWQYBSABKAkSEAoIbG9jYXRpb24YBiABKAkSHQoVc2VydmljZV9hY2NvdW50X2VtYWlsGAcgASgJEiIKGndvcmtsb2FkX2lkZW50aXR5X3Byb3ZpZGVyGAggASgJEhMKC2FjY2Vzc19tb2RlGAkgASgJImUKK1VwZGF0ZUdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnUmVzcG9uc2USNgoEZGF0YRgBIAEoCzIoLmFwZXJpby52MS5Hb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZyLuAQodR29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWcSDwoHZW5hYmxlZBgBIAEoCBISCgpwcm9qZWN0X2lkGAIgASgJEhYKDnJhd19kYXRhc2V0X2lkGAMgASgJEhIKCmRhdGFzZXRfaWQYBCABKAkSEAoIbG9jYXRpb24YBSABKAkSHQoVc2VydmljZV9hY2NvdW50X2VtYWlsGAYgASgJEiIKGndvcmtsb2FkX2lkZW50aXR5X3Byb3ZpZGVyGAcgASgJEhMKC2FjY2Vzc19tb2RlGAggASgJEhIKCnVwZGF0ZWRfYXQYCSABKAkiRgosVmFsaWRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkiawotVmFsaWRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1Jlc3BvbnNlEjoKBGRhdGEYASABKAsyLC5hcGVyaW8udjEuR29vZ2xlV29ya3NwYWNlQmlnUXVlcnlWYWxpZGF0aW9uIvoBCiFHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeVZhbGlkYXRpb24SFgoOaW50ZWdyYXRpb25faWQYASABKAkSCgoCb2sYAiABKAgSDwoHbWVzc2FnZRgDIAEoCRISCgpwcm9qZWN0X2lkGAQgASgJEhIKCmRhdGFzZXRfaWQYBSABKAkSFgoOYWN0aXZpdHlfdGFibGUYBiABKAkSEwoLdGFibGVfZm91bmQYByABKAgSEwoLc2FtcGxlX3Jvd3MYCCABKAUSFwoPZXN0aW1hdGVkX2J5dGVzGAkgASgDEh0KFXJ1bnRpbWVfdG9rZW5fcHJlc2VudBgKIAEoCCIwCiBTdGFydEdvb2dsZVdvcmtzcGFjZU9BdXRoUmVxdWVzdBIMCgRtb2RlGAEgASgJIkgKIVN0YXJ0R29vZ2xlV29ya3NwYWNlT0F1dGhSZXNwb25zZRIjCgRkYXRhGAEgASgLMhUuYXBlcmlvLnYxLk9BdXRoU3RhcnQiqQEKFkludGVncmF0aW9uT0F1dGhDbGllbnQSEAoIcHJvdmlkZXIYASABKAkSEQoJY2xpZW50X2lkGAIgASgJEhQKDHJlZGlyZWN0X3VyaRgDIAEoCRISCgpjb25maWd1cmVkGAQgASgIEhwKFGRlZmF1bHRfcmVkaXJlY3RfdXJpGAUgASgJEhIKCnVwZGF0ZWRfYXQYBiABKAkSDgoGc291cmNlGAcgASgJIjQKIEdldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXF1ZXN0EhAKCHByb3ZpZGVyGAEgASgJIlQKIUdldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRIvCgRkYXRhGAEgASgLMiEuYXBlcmlvLnYxLkludGVncmF0aW9uT0F1dGhDbGllbnQidAogU2V0SW50ZWdyYXRpb25PQXV0aENsaWVudFJlcXVlc3QSEAoIcHJvdmlkZXIYASABKAkSEQoJY2xpZW50X2lkGAIgASgJEhUKDWNsaWVudF9zZWNyZXQYAyABKAkSFAoMcmVkaXJlY3RfdXJpGAQgASgJIlQKIVNldEludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRIvCgRkYXRhGAEgASgLMiEuYXBlcmlvLnYxLkludGVncmF0aW9uT0F1dGhDbGllbnQiNgoiQ2xlYXJJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50UmVxdWVzdBIQCghwcm92aWRlchgBIAEoCSJWCiNDbGVhckludGVncmF0aW9uT0F1dGhDbGllbnRSZXNwb25zZRIvCgRkYXRhGAEgASgLMiEuYXBlcmlvLnYxLkludGVncmF0aW9uT0F1dGhDbGllbnQiGQoKT0F1dGhTdGFydBILCgN1cmwYASABKAkiNQobRm9yY2VTeW5jSW50ZWdyYXRpb25SZXF1ZXN0EhYKDmludGVncmF0aW9uX2lkGAEgASgJInQKHEZvcmNlU3luY0ludGVncmF0aW9uUmVzcG9uc2USLgoEZGF0YRgBIAEoCzIgLmFwZXJpby52MS5JbnRlZ3JhdGlvbkNvbm5lY3Rpb24SJAoEc3luYxgCIAEoCzIWLmFwZXJpby52MS5TeW5jU3VtbWFyeSJmCgtTeW5jU3VtbWFyeRIUCgxzYW1wbGVfY291bnQYASABKAUSFwoPZXZlbnRzX2luZ2VzdGVkGAIgASgFEhcKD2ZpbmRpbmdzX29wZW5lZBgDIAEoBRIPCgdzb3VyY2VzGAQgAygJIjkKH0dldEludGVncmF0aW9uU3luY1N0YXR1c1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkiUgogR2V0SW50ZWdyYXRpb25TeW5jU3RhdHVzUmVzcG9uc2USLgoEZGF0YRgBIAEoCzIgLmFwZXJpby52MS5JbnRlZ3JhdGlvblN5bmNTdGF0dXMiYwofUnVuSW50ZWdyYXRpb25Tb3VyY2VTeW5jUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRITCgtzb3VyY2Vfa2luZBgCIAEoCRITCgtzdHJlYW1fbmFtZRgDIAEoCSJYCiBSdW5JbnRlZ3JhdGlvblNvdXJjZVN5bmNSZXNwb25zZRI0CgRkYXRhGAEgASgLMiYuYXBlcmlvLnYxLkludGVncmF0aW9uU291cmNlU3luY0FjdGlvbiJ3CiBCYWNrZmlsbEludGVncmF0aW9uU291cmNlUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRITCgtzb3VyY2Vfa2luZBgCIAEoCRITCgtzdHJlYW1fbmFtZRgDIAEoCRIRCglmcm9tX3RpbWUYBCABKAkiWQohQmFja2ZpbGxJbnRlZ3JhdGlvblNvdXJjZVJlc3BvbnNlEjQKBGRhdGEYASABKAsyJi5hcGVyaW8udjEuSW50ZWdyYXRpb25Tb3VyY2VTeW5jQWN0aW9uIo8BChVJbnRlZ3JhdGlvblN5bmNTdGF0dXMSFgoOaW50ZWdyYXRpb25faWQYASABKAkSEAoIcHJvdmlkZXIYAiABKAkSFAoMZ2VuZXJhdGVkX2F0GAMgASgJEjYKB3NvdXJjZXMYBCADKAsyJS5hcGVyaW8udjEuSW50ZWdyYXRpb25Tb3VyY2VTeW5jU3RhdGUiywMKGkludGVncmF0aW9uU291cmNlU3luY1N0YXRlEhMKC3NvdXJjZV9raW5kGAEgASgJEhMKC3N0cmVhbV9uYW1lGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCRIOCgZzdGF0dXMYBCABKAkSEwoLY3Vyc29yX3RpbWUYBSABKAkSFwoPbGFzdF9hdHRlbXB0X2F0GAYgASgJEhcKD2xhc3Rfc3VjY2Vzc19hdBgHIAEoCRISCgpsYXN0X2Vycm9yGAggASgJEhMKC2xhZ19zZWNvbmRzGAkgASgDEhEKCXJvd3Nfc2VlbhgKIAEoAxIVCg1yb3dzX2VucXVldWVkGAsgASgDEhQKDHF1ZXVlX3F1ZXVlZBgMIAEoAxIVCg1xdWV1ZV9ydW5uaW5nGA0gASgDEhQKDHF1ZXVlX2ZhaWxlZBgOIAEoAxIZChFxdWV1ZV9kZWFkX2xldHRlchgPIAEoAxIXCg9xdWV1ZV9zdWNjZWVkZWQYECABKAMSGgoSc3luY19ub3dfc3VwcG9ydGVkGBEgASgIEhoKEmJhY2tmaWxsX3N1cHBvcnRlZBgSIAEoCBIUCgxxdWV1ZV9zb3VyY2UYEyABKAkilgEKG0ludGVncmF0aW9uU291cmNlU3luY0FjdGlvbhIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRITCgtzb3VyY2Vfa2luZBgCIAEoCRITCgtzdHJlYW1fbmFtZRgDIAEoCRIOCgZxdWV1ZWQYBCABKAgSDwoHbWVzc2FnZRgFIAEoCRIUCgxyZXF1ZXN0ZWRfYXQYBiABKAkiGAoWTGlzdFNpZW1DYXRhbG9nUmVxdWVzdCJNChdMaXN0U2llbUNhdGFsb2dSZXNwb25zZRIyCgRkYXRhGAEgAygLMiQuYXBlcmlvLnYxLlNpZW1EZXN0aW5hdGlvbkRlZmluaXRpb24ivwEKGVNpZW1EZXN0aW5hdGlvbkRlZmluaXRpb24SDAoEa2luZBgBIAEoCRIMCgRuYW1lGAIgASgJEg4KBnZlbmRvchgDIAEoCRITCgtkZXNjcmlwdGlvbhgEIAEoCRIQCghjYXRlZ29yeRgFIAEoCRIQCghkb2NzX3VybBgGIAEoCRIXCg9kZWZhdWx0X3N0cmVhbXMYByADKAkSJAoGZmllbGRzGAggAygLMhQuYXBlcmlvLnYxLlNpZW1GaWVsZCJ8CglTaWVtRmllbGQSCwoDa2V5GAEgASgJEg0KBWxhYmVsGAIgASgJEhMKC3BsYWNlaG9sZGVyGAMgASgJEg4KBmhlbHBlchgEIAEoCRIMCgR0eXBlGAUgASgJEhAKCHJlcXVpcmVkGAYgASgIEg4KBnNlY3JldBgHIAEoCCIdChtMaXN0U2llbURlc3RpbmF0aW9uc1JlcXVlc3QiSAocTGlzdFNpZW1EZXN0aW5hdGlvbnNSZXNwb25zZRIoCgRkYXRhGAEgAygLMhouYXBlcmlvLnYxLlNpZW1EZXN0aW5hdGlvbiKEAgoPU2llbURlc3RpbmF0aW9uEgoKAmlkGAEgASgJEgwKBGtpbmQYAiABKAkSDAoEbmFtZRgDIAEoCRIUCgxlbmRwb2ludF91cmwYBCABKAkSEQoJZmlsZV9wYXRoGAUgASgJEg0KBWluZGV4GAYgASgJEg8KB3N0cmVhbXMYByADKAkSDgoGc3RhdHVzGAggASgJEhgKEGxhc3RfZGVsaXZlcnlfYXQYCSABKAkSEgoKbGFzdF9lcnJvchgKIAEoCRIVCg1kZWxpdmVyaWVzX29rGAsgASgFEhcKD2RlbGl2ZXJpZXNfZmFpbBgMIAEoBRISCgpjcmVhdGVkX2F0GA0gASgJIpIBChxDcmVhdGVTaWVtRGVzdGluYXRpb25SZXF1ZXN0EgwKBGtpbmQYASABKAkSDAoEbmFtZRgCIAEoCRIUCgxlbmRwb2ludF91cmwYAyABKAkSEQoJZmlsZV9wYXRoGAQgASgJEg0KBWluZGV4GAUgASgJEg0KBXRva2VuGAYgASgJEg8KB3N0cmVhbXMYByADKAkiSQodQ3JlYXRlU2llbURlc3RpbmF0aW9uUmVzcG9uc2USKAoEZGF0YRgBIAEoCzIaLmFwZXJpby52MS5TaWVtRGVzdGluYXRpb24iKgocRGVsZXRlU2llbURlc3RpbmF0aW9uUmVxdWVzdBIKCgJpZBgBIAEoCSJGCh1EZWxldGVTaWVtRGVzdGluYXRpb25SZXNwb25zZRIlCgRkYXRhGAEgASgLMhcuYXBlcmlvLnYxLkRlbGV0ZVJlc3VsdCIoChpUZXN0U2llbURlc3RpbmF0aW9uUmVxdWVzdBIKCgJpZBgBIAEoCSJGChtUZXN0U2llbURlc3RpbmF0aW9uUmVzcG9uc2USJwoEZGF0YRgBIAEoCzIZLmFwZXJpby52MS5TaWVtVGVzdFJlc3VsdCJFCg5TaWVtVGVzdFJlc3VsdBIWCg5kZXN0aW5hdGlvbl9pZBgBIAEoCRIKCgJvaxgCIAEoCBIPCgdtZXNzYWdlGAMgASgJIh4KHExpc3RTaGFkb3dJdE9hdXRoQXBwc1JlcXVlc3QiSgodTGlzdFNoYWRvd0l0T2F1dGhBcHBzUmVzcG9uc2USKQoEZGF0YRgBIAMoCzIbLmFwZXJpby52MS5TaGFkb3dJdE9hdXRoQXBwIrACChBTaGFkb3dJdE9hdXRoQXBwEgoKAmlkGAEgASgJEhAKCHByb3ZpZGVyGAIgASgJEgwKBG5hbWUYAyABKAkSDwoHc3VtbWFyeRgEIAEoCRITCgtleHRlcm5hbF9pZBgFIAEoCRIOCgZsYWJlbHMYBiADKAkSEwoLY3JpdGljYWxpdHkYByABKAkSHwoXY29udGFpbnNfc2Vuc2l0aXZlX2RhdGEYCCABKAgSEgoKcmlza19zY29yZRgJIAEoBRIYChBsYXN0X29ic2VydmVkX2F0GAogASgJEhIKCnVzZXJfY291bnQYCyABKAUSDgoGc2NvcGVzGAwgAygJEjIKC2ludGVncmF0aW9uGA0gASgLMh0uYXBlcmlvLnYxLkZpbmRpbmdJbnRlZ3JhdGlvbiI1CiFMaXN0U2hhZG93SXRPYXV0aEFwcEdyYW50c1JlcXVlc3QSEAoIYXNzZXRfaWQYASABKAkiVQoiTGlzdFNoYWRvd0l0T2F1dGhBcHBHcmFudHNSZXNwb25zZRIvCgRkYXRhGAEgASgLMiEuYXBlcmlvLnYxLlNoYWRvd0l0T2F1dGhBcHBEZXRhaWwidwoWU2hhZG93SXRPYXV0aEFwcERldGFpbBIrCgNhcHAYASABKAsyHi5hcGVyaW8udjEuU2hhZG93SXRPYXV0aEFwcFJlZhIwCgZncmFudHMYAiADKAsyIC5hcGVyaW8udjEuU2hhZG93SXRPYXV0aEFwcEdyYW50IlYKE1NoYWRvd0l0T2F1dGhBcHBSZWYSCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRITCgtleHRlcm5hbF9pZBgDIAEoCRIQCghwcm92aWRlchgEIAEoCSK9AQoVU2hhZG93SXRPYXV0aEFwcEdyYW50EgoKAmlkGAEgASgJEhIKCnVzZXJfZW1haWwYAiABKAkSGAoQdXNlcl9leHRlcm5hbF9pZBgDIAEoCRIZChF1c2VyX2Rpc3BsYXlfbmFtZRgEIAEoCRIOCgZzY29wZXMYBSADKAkSEQoJYW5vbnltb3VzGAYgASgIEhIKCm5hdGl2ZV9hcHAYByABKAgSGAoQbGFzdF9vYnNlcnZlZF9hdBgIIAEoCSIaChhHZXRUZW5hbnRTZXR0aW5nc1JlcXVlc3QiRAoZR2V0VGVuYW50U2V0dGluZ3NSZXNwb25zZRInCgRkYXRhGAEgASgLMhkuYXBlcmlvLnYxLlRlbmFudFNldHRpbmdzItMDChtVcGRhdGVUZW5hbnRTZXR0aW5nc1JlcXVlc3QSEQoEbmFtZRgBIAEoCUgAiAEBEh8KEm5vdGlmaWNhdGlvbl9lbWFpbBgCIAEoCUgBiAEBEiAKE2RhdGFfcmV0ZW50aW9uX2RheXMYAyABKAVIAogBARIkChdjcml0aWNhbF9yaXNrX3RocmVzaG9sZBgEIAEoBUgDiAEBEh4KEWRlZmF1bHRfc2xhX2hvdXJzGAUgASgFSASIAQESJgoZYXV0b19yZXNvbHZlX2xvd19zZXZlcml0eRgGIAEoCEgFiAEBEh0KEGVuZm9yY2Vfc3NvX29ubHkYByABKAhIBogBARIeChF3ZWJob29rX2FsZXJ0X3VybBgIIAEoCUgHiAEBQgcKBV9uYW1lQhUKE19ub3RpZmljYXRpb25fZW1haWxCFgoUX2RhdGFfcmV0ZW50aW9uX2RheXNCGgoYX2NyaXRpY2FsX3Jpc2tfdGhyZXNob2xkQhQKEl9kZWZhdWx0X3NsYV9ob3Vyc0IcChpfYXV0b19yZXNvbHZlX2xvd19zZXZlcml0eUITChFfZW5mb3JjZV9zc29fb25seUIUChJfd2ViaG9va19hbGVydF91cmwiRwocVXBkYXRlVGVuYW50U2V0dGluZ3NSZXNwb25zZRInCgRkYXRhGAEgASgLMhkuYXBlcmlvLnYxLlRlbmFudFNldHRpbmdzIq0CCg5UZW5hbnRTZXR0aW5ncxIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEgwKBHNsdWcYAyABKAkSGgoSbm90aWZpY2F0aW9uX2VtYWlsGAQgASgJEhsKE2RhdGFfcmV0ZW50aW9uX2RheXMYBSABKAUSHwoXY3JpdGljYWxfcmlza190aHJlc2hvbGQYBiABKAUSGQoRZGVmYXVsdF9zbGFfaG91cnMYByABKAUSIQoZYXV0b19yZXNvbHZlX2xvd19zZXZlcml0eRgIIAEoCBIYChBlbmZvcmNlX3Nzb19vbmx5GAkgASgIEhkKEXdlYmhvb2tfYWxlcnRfdXJsGAogASgJEhIKCmNyZWF0ZWRfYXQYCyABKAkSEgoKdXBkYXRlZF9hdBgMIAEoCSIaChhMaXN0VGVuYW50TWVtYmVyc1JlcXVlc3QiQgoZTGlzdFRlbmFudE1lbWJlcnNSZXNwb25zZRIlCgRkYXRhGAEgAygLMhcuYXBlcmlvLnYxLlRlbmFudE1lbWJlciJTChlDcmVhdGVUZW5hbnRNZW1iZXJSZXF1ZXN0Eg0KBWVtYWlsGAEgASgJEhQKDGRpc3BsYXlfbmFtZRgCIAEoCRIRCglyb2xlX25hbWUYAyABKAkidAoaQ3JlYXRlVGVuYW50TWVtYmVyUmVzcG9uc2USJQoEZGF0YRgBIAEoCzIXLmFwZXJpby52MS5UZW5hbnRNZW1iZXISLwoKaW52aXRhdGlvbhgCIAEoCzIbLmFwZXJpby52MS5JbnZpdGF0aW9uUmVzdWx0IioKHENyZWF0ZU1lbWJlclJlc2V0TGlua1JlcXVlc3QSCgoCaWQYASABKAkicgodQ3JlYXRlTWVtYmVyUmVzZXRMaW5rUmVzcG9uc2USJQoEZGF0YRgBIAEoCzIXLmFwZXJpby52MS5UZW5hbnRNZW1iZXISKgoFcmVzZXQYAiABKAsyGy5hcGVyaW8udjEuSW52aXRhdGlvblJlc3VsdCI4ChdVcGRhdGVNZW1iZXJSb2xlUmVxdWVzdBIKCgJpZBgBIAEoCRIRCglyb2xlX25hbWUYAiABKAkiQQoYVXBkYXRlTWVtYmVyUm9sZVJlc3BvbnNlEiUKBGRhdGEYASABKAsyFy5hcGVyaW8udjEuVGVuYW50TWVtYmVyIu8BCgxUZW5hbnRNZW1iZXISCgoCaWQYASABKAkSDQoFZW1haWwYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJEhEKCWlzX2FjdGl2ZRgEIAEoCBITCgttZmFfZW5hYmxlZBgFIAEoCBIVCg1sYXN0X2xvZ2luX2F0GAYgASgJEhYKDmlzX2JyZWFrX2dsYXNzGAcgASgIEgwKBHJvbGUYCCABKAkSEgoKYXV0aF9zdGF0ZRgJIAEoCRIhChlwZW5kaW5nX2FjdGlvbl9leHBpcmVzX2F0GAogASgJEhIKCmNyZWF0ZWRfYXQYCyABKAkiRQoQSW52aXRhdGlvblJlc3VsdBIQCghkZWxpdmVyeRgBIAEoCRILCgN1cmwYAiABKAkSEgoKZXhwaXJlc19hdBgDIAEoCSIWChRMaXN0QXVkaXRMb2dzUmVxdWVzdCI/ChVMaXN0QXVkaXRMb2dzUmVzcG9uc2USJgoEZGF0YRgBIAMoCzIYLmFwZXJpby52MS5BdWRpdExvZ0VudHJ5Io0BCg1BdWRpdExvZ0VudHJ5EgoKAmlkGAEgASgJEg4KBmFjdGlvbhgCIAEoCRITCgt0YXJnZXRfdHlwZRgDIAEoCRIRCgl0YXJnZXRfaWQYBCABKAkSDQoFYWN0b3IYBSABKAkSEgoKY3JlYXRlZF9hdBgGIAEoCRIVCg1tZXRhZGF0YV9qc29uGAcgASgJIhwKGkdldFNlY3VyaXR5T3ZlcnZpZXdSZXF1ZXN0IkgKG0dldFNlY3VyaXR5T3ZlcnZpZXdSZXNwb25zZRIpCgRkYXRhGAEgASgLMhsuYXBlcmlvLnYxLlNlY3VyaXR5T3ZlcnZpZXciiQQKEFNlY3VyaXR5T3ZlcnZpZXcSMwoHc3VtbWFyeRgBIAEoCzIiLmFwZXJpby52MS5TZWN1cml0eU92ZXJ2aWV3U3VtbWFyeRIvCgppZGVudGl0aWVzGAIgAygLMhsuYXBlcmlvLnYxLlNlY3VyaXR5SWRlbnRpdHkSJwoFZ3JhcGgYAyABKAsyGC5hcGVyaW8udjEuU2VjdXJpdHlHcmFwaBIsCgpvYXV0aF9hcHBzGAQgAygLMhguYXBlcmlvLnYxLlNlY3VyaXR5QXNzZXQSLQoLZGF0YV9hc3NldHMYBSADKAsyGC5hcGVyaW8udjEuU2VjdXJpdHlBc3NldBIrCgxhdHRhY2tfcGF0aHMYBiADKAsyFS5hcGVyaW8udjEuQXR0YWNrUGF0aBIwCg5vd25lcnNoaXBfZ2FwcxgHIAMoCzIYLmFwZXJpby52MS5TZWN1cml0eUFzc2V0EiwKCmV4Y2VwdGlvbnMYCCADKAsyGC5hcGVyaW8udjEuUmlza0V4Y2VwdGlvbhJAChdkb21haW5fd2lkZV9kZWxlZ2F0aW9ucxgJIAMoCzIfLmFwZXJpby52MS5Eb21haW5XaWRlRGVsZWdhdGlvbhI6Cg9jZXJlYnJvX2NvbnRleHQYCiABKAsyIS5hcGVyaW8udjEuU2VjdXJpdHlDZXJlYnJvQ29udGV4dCLoAQoXU2VjdXJpdHlPdmVydmlld1N1bW1hcnkSHQoVcHJpdmlsZWdlZF9pZGVudGl0aWVzGAEgASgFEiQKHGFkbWluX2lkZW50aXRpZXNfd2l0aG91dF9tZmEYAiABKAUSGAoQcmlza3lfb2F1dGhfYXBwcxgDIAEoBRIbChNleHBvc2VkX2RhdGFfYXNzZXRzGAQgASgFEhYKDnVub3duZWRfYXNzZXRzGAUgASgFEhkKEWFjdGl2ZV9leGNlcHRpb25zGAYgASgFEh4KFnRvcF9ibGFzdF9yYWRpdXNfc2NvcmUYByABKAUilwIKFlNlY3VyaXR5Q2VyZWJyb0NvbnRleHQSDgoGc291cmNlGAEgASgJEgwKBG1vZGUYAiABKAkSGQoRc291cmNlX3J1bnRpbWVfaWQYAyABKAkSGAoQZmluZGluZ19jb250cmFjdBgEIAEoCRITCgtjbGFpbV9jb3VudBgFIAEoBRIaChJncmFwaF9zaWduYWxfY291bnQYBiABKAUSFAoMZW50aXR5X2NvdW50GAcgASgFEhgKEGdyYXBoX3BhdGhfY291bnQYCCABKAUSMQoDbWNwGAkgASgLMiQuYXBlcmlvLnYxLlNlY3VyaXR5Q2VyZWJyb01DUENvbnRleHQSFgoOcmVzcG9uc2VfaGludHMYCiADKAkipQEKGVNlY3VyaXR5Q2VyZWJyb01DUENvbnRleHQSDgoGc2VydmVyGAEgASgJEhQKDHJlc291cmNlX3VyaRgCIAEoCRIQCghyZXNvdXJjZRgDIAEoCRINCgV0b29scxgEIAMoCRJBChJyZXNvdXJjZV90ZW1wbGF0ZXMYBSADKAsyJS5hcGVyaW8udjEuQ2VyZWJyb01DUFJlc291cmNlVGVtcGxhdGUi/gIKEFNlY3VyaXR5SWRlbnRpdHkSCgoCaWQYASABKAkSEQoJZW50aXR5X2lkGAIgASgJEgwKBGtpbmQYAyABKAkSDAoEbmFtZRgEIAEoCRINCgVlbWFpbBgFIAEoCRIQCghwcm92aWRlchgGIAEoCRIyCgtpbnRlZ3JhdGlvbhgHIAEoCzIdLmFwZXJpby52MS5GaW5kaW5nSW50ZWdyYXRpb24SDAoEcm9sZRgIIAEoCRISCgpwcml2aWxlZ2VkGAkgASgIEhMKC21mYV9lbmFibGVkGAogASgIEg4KBnN0YXR1cxgLIAEoCRITCgtpc19leHRlcm5hbBgMIAEoCBIYChBsYXN0X29ic2VydmVkX2F0GA0gASgJEhoKEmxpbmtlZF9hc3NldF9jb3VudBgOIAEoBRISCgpyaXNrX3Njb3JlGA8gASgFEh4KEW1mYV9lbmFibGVkX3N0YXRlGBAgASgISACIAQFCFAoSX21mYV9lbmFibGVkX3N0YXRlImkKDVNlY3VyaXR5R3JhcGgSKwoFbm9kZXMYASADKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlHcmFwaE5vZGUSKwoFZWRnZXMYAiADKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlHcmFwaEVkZ2UikQEKEVNlY3VyaXR5R3JhcGhOb2RlEgoKAmlkGAEgASgJEg0KBWxhYmVsGAIgASgJEgwKBGtpbmQYAyABKAkSEgoKcmlza19zY29yZRgEIAEoBRISCgpwcml2aWxlZ2VkGAUgASgIEhYKDmV4cG9zdXJlX2xldmVsGAYgASgJEhMKC2NyaXRpY2FsaXR5GAcgASgJImAKEVNlY3VyaXR5R3JhcGhFZGdlEgoKAmlkGAEgASgJEhEKCXNvdXJjZV9pZBgCIAEoCRIRCgl0YXJnZXRfaWQYAyABKAkSGQoRcmVsYXRpb25zaGlwX3R5cGUYBCABKAkizAEKCkF0dGFja1BhdGgSCgoCaWQYASABKAkSDQoFdGl0bGUYAiABKAkSDQoFc2NvcmUYAyABKAUSFQoNZmluZGluZ190aXRsZRgEIAEoCRITCgtlbnRyeV9wb2ludBgFIAEoCRIOCgZ0YXJnZXQYBiABKAkSDQoFb3duZXIYByABKAkSFgoOZXhwb3N1cmVfbGV2ZWwYCCABKAkSEwoLY3JpdGljYWxpdHkYCSABKAkSDgoGcmVhc29uGAogASgJEgwKBHBhdGgYCyADKAkirAIKFERvbWFpbldpZGVEZWxlZ2F0aW9uEhYKDmludGVncmF0aW9uX2lkGAEgASgJEhAKCHByb3ZpZGVyGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCRIYChB3b3Jrc3BhY2VfZG9tYWluGAQgASgJEiQKHHNlcnZpY2VfYWNjb3VudF9jbGllbnRfZW1haWwYBSABKAkSDgoGc2NvcGVzGAYgAygJEg4KBnN0YXR1cxgHIAEoCRIaChJpbnRlZ3JhdGlvbl9zdGF0dXMYCCABKAkSDAoEbW9kZRgJIAEoCRIdChVvcGVuX21haWxib3hfZmluZGluZ3MYCiABKAUSFAoMbGFzdF9zeW5jX2F0GAsgASgJEhUKDWNvbmZpZ3VyZWRfYXQYDCABKAkiOAocTGlzdEVtYWlsRG9tYWluSGVhbHRoUmVxdWVzdBIYChByZWZyZXNoX2lmX3N0YWxlGAEgASgIIksKHUxpc3RFbWFpbERvbWFpbkhlYWx0aFJlc3BvbnNlEioKBGRhdGEYASADKAsyHC5hcGVyaW8udjEuRW1haWxEb21haW5IZWFsdGgiLQobR2V0RW1haWxEb21haW5IZWFsdGhSZXF1ZXN0Eg4KBmRvbWFpbhgBIAEoCSJQChxHZXRFbWFpbERvbWFpbkhlYWx0aFJlc3BvbnNlEjAKBGRhdGEYASABKAsyIi5hcGVyaW8udjEuRW1haWxEb21haW5IZWFsdGhEZXRhaWwiMQofUmVmcmVzaEVtYWlsRG9tYWluSGVhbHRoUmVxdWVzdBIOCgZkb21haW4YASABKAkiTgogUmVmcmVzaEVtYWlsRG9tYWluSGVhbHRoUmVzcG9uc2USKgoEZGF0YRgBIAMoCzIcLmFwZXJpby52MS5FbWFpbERvbWFpbkhlYWx0aCLmAQoRRW1haWxEb21haW5IZWFsdGgSDgoGZG9tYWluGAEgASgJEhgKEHByb3ZpZGVyX3NvdXJjZXMYAiADKAkSDgoGc3RhdHVzGAMgASgJEg0KBXNjb3JlGAQgASgFEhIKCnNwZl9zdGF0dXMYBSABKAkSEwoLZGtpbV9zdGF0dXMYBiABKAkSFAoMZG1hcmNfc3RhdHVzGAcgASgJEhcKD2xhc3RfY2hlY2tlZF9hdBgIIAEoCRITCgtpc3N1ZV9jb3VudBgJIAEoBRIbChNmYWlsaW5nX2lzc3VlX2NvdW50GAogASgFIo0BChZFbWFpbERvbWFpbkhlYWx0aElzc3VlEgoKAmlkGAEgASgJEhAKCHByb3RvY29sGAIgASgJEhAKCHNldmVyaXR5GAMgASgJEgwKBGNvZGUYBCABKAkSDQoFdGl0bGUYBSABKAkSDgoGZGV0YWlsGAYgASgJEhYKDnJlY29tbWVuZGF0aW9uGAcgASgJIl0KF0VtYWlsRG9tYWluRGtpbVNlbGVjdG9yEhAKCHNlbGVjdG9yGAEgASgJEg4KBnN0YXR1cxgCIAEoCRIQCghrZXlfYml0cxgDIAEoBRIOCgZyZWNvcmQYBCABKAkiZwodRW1haWxEb21haW5IZWFsdGhIaXN0b3J5UG9pbnQSEgoKY2hlY2tlZF9hdBgBIAEoCRIOCgZzdGF0dXMYAiABKAkSDQoFc2NvcmUYAyABKAUSEwoLaXNzdWVfY291bnQYBCABKAUitAMKF0VtYWlsRG9tYWluSGVhbHRoRGV0YWlsEiwKBmRvbWFpbhgBIAEoCzIcLmFwZXJpby52MS5FbWFpbERvbWFpbkhlYWx0aBITCgtzcGZfcmVjb3JkcxgCIAMoCRISCgpzcGZfcG9saWN5GAMgASgJEhgKEHNwZl9sb29rdXBfY291bnQYBCABKAUSFQoNZG1hcmNfcmVjb3JkcxgFIAMoCRIUCgxkbWFyY19wb2xpY3kYBiABKAkSEQoJZG1hcmNfcGN0GAcgASgFEhEKCWRtYXJjX3J1YRgIIAMoCRISCgpteF9yZWNvcmRzGAkgAygJEjoKDmRraW1fc2VsZWN0b3JzGAogAygLMiIuYXBlcmlvLnYxLkVtYWlsRG9tYWluRGtpbVNlbGVjdG9yEhcKD3JlbGF0ZWRfcmVjb3JkcxgLIAMoCRIxCgZpc3N1ZXMYDCADKAsyIS5hcGVyaW8udjEuRW1haWxEb21haW5IZWFsdGhJc3N1ZRI5CgdoaXN0b3J5GA0gAygLMiguYXBlcmlvLnYxLkVtYWlsRG9tYWluSGVhbHRoSGlzdG9yeVBvaW50IlsKGUxpc3RTZWN1cml0eUFzc2V0c1JlcXVlc3QSDAoEdHlwZRgBIAEoCRIYChBvd25lcnNoaXBfc3RhdHVzGAIgASgJEhYKDmludGVncmF0aW9uX2lkGAMgASgJIkQKGkxpc3RTZWN1cml0eUFzc2V0c1Jlc3BvbnNlEiYKBGRhdGEYASADKAsyGC5hcGVyaW8udjEuU2VjdXJpdHlBc3NldCKnBAoNU2VjdXJpdHlBc3NldBIKCgJpZBgBIAEoCRIMCgR0eXBlGAIgASgJEhAKCHByb3ZpZGVyGAMgASgJEgwKBG5hbWUYBCABKAkSDwoHc3VtbWFyeRgFIAEoCRITCgtleHRlcm5hbF9pZBgGIAEoCRIOCgZsYWJlbHMYByADKAkSEwoLY3JpdGljYWxpdHkYCCABKAkSFgoOZXhwb3N1cmVfbGV2ZWwYCSABKAkSGAoQb3duZXJzaGlwX3N0YXR1cxgKIAEoCRIfChdjb250YWluc19zZW5zaXRpdmVfZGF0YRgLIAEoCBIVCg1pc19wcml2aWxlZ2VkGAwgASgIEhIKCnJpc2tfc2NvcmUYDSABKAUSGAoQbGFzdF9vYnNlcnZlZF9hdBgOIAEoCRISCgpjcmVhdGVkX2F0GA8gASgJEhIKCnVwZGF0ZWRfYXQYECABKAkSMgoLaW50ZWdyYXRpb24YESABKAsyHS5hcGVyaW8udjEuRmluZGluZ0ludGVncmF0aW9uEisKBW93bmVyGBIgASgLMhwuYXBlcmlvLnYxLlNlY3VyaXR5UHJpbmNpcGFsEjQKDmJ1c2luZXNzX293bmVyGBMgASgLMhwuYXBlcmlvLnYxLlNlY3VyaXR5UHJpbmNpcGFsEhoKEm9wZW5fZmluZGluZ19jb3VudBgUIAEoBRIeChZhY3RpdmVfZXhjZXB0aW9uX2NvdW50GBUgASgFIkQKEVNlY3VyaXR5UHJpbmNpcGFsEgoKAmlkGAEgASgJEg0KBWVtYWlsGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCSL8AgoaQ3JlYXRlU2VjdXJpdHlBc3NldFJlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkSFQoNb3duZXJfdXNlcl9pZBgCIAEoCRIeChZidXNpbmVzc19vd25lcl91c2VyX2lkGAMgASgJEgwKBHR5cGUYBCABKAkSEAoIcHJvdmlkZXIYBSABKAkSDAoEbmFtZRgGIAEoCRIPCgdzdW1tYXJ5GAcgASgJEhMKC2V4dGVybmFsX2lkGAggASgJEg4KBmxhYmVscxgJIAMoCRITCgtjcml0aWNhbGl0eRgKIAEoCRIWCg5leHBvc3VyZV9sZXZlbBgLIAEoCRIYChBvd25lcnNoaXBfc3RhdHVzGAwgASgJEh8KF2NvbnRhaW5zX3NlbnNpdGl2ZV9kYXRhGA0gASgIEhUKDWlzX3ByaXZpbGVnZWQYDiABKAgSEgoKcmlza19zY29yZRgPIAEoBRIYChBsYXN0X29ic2VydmVkX2F0GBAgASgJIkUKG0NyZWF0ZVNlY3VyaXR5QXNzZXRSZXNwb25zZRImCgRkYXRhGAEgASgLMhguYXBlcmlvLnYxLlNlY3VyaXR5QXNzZXQi8AUKGlVwZGF0ZVNlY3VyaXR5QXNzZXRSZXF1ZXN0EgoKAmlkGAEgASgJEhsKDmludGVncmF0aW9uX2lkGAIgASgJSACIAQESGgoNb3duZXJfdXNlcl9pZBgDIAEoCUgBiAEBEiMKFmJ1c2luZXNzX293bmVyX3VzZXJfaWQYBCABKAlIAogBARIRCgR0eXBlGAUgASgJSAOIAQESFQoIcHJvdmlkZXIYBiABKAlIBIgBARIRCgRuYW1lGAcgASgJSAWIAQESFAoHc3VtbWFyeRgIIAEoCUgGiAEBEhgKC2V4dGVybmFsX2lkGAkgASgJSAeIAQESDgoGbGFiZWxzGAogAygJEhYKDmxhYmVsc19wcmVzZW50GAsgASgIEhgKC2NyaXRpY2FsaXR5GAwgASgJSAiIAQESGwoOZXhwb3N1cmVfbGV2ZWwYDSABKAlICYgBARIdChBvd25lcnNoaXBfc3RhdHVzGA4gASgJSAqIAQESJAoXY29udGFpbnNfc2Vuc2l0aXZlX2RhdGEYDyABKAhIC4gBARIaCg1pc19wcml2aWxlZ2VkGBAgASgISAyIAQESFwoKcmlza19zY29yZRgRIAEoBUgNiAEBEh0KEGxhc3Rfb2JzZXJ2ZWRfYXQYEiABKAlIDogBAUIRCg9faW50ZWdyYXRpb25faWRCEAoOX293bmVyX3VzZXJfaWRCGQoXX2J1c2luZXNzX293bmVyX3VzZXJfaWRCBwoFX3R5cGVCCwoJX3Byb3ZpZGVyQgcKBV9uYW1lQgoKCF9zdW1tYXJ5Qg4KDF9leHRlcm5hbF9pZEIOCgxfY3JpdGljYWxpdHlCEQoPX2V4cG9zdXJlX2xldmVsQhMKEV9vd25lcnNoaXBfc3RhdHVzQhoKGF9jb250YWluc19zZW5zaXRpdmVfZGF0YUIQCg5faXNfcHJpdmlsZWdlZEINCgtfcmlza19zY29yZUITChFfbGFzdF9vYnNlcnZlZF9hdCJFChtVcGRhdGVTZWN1cml0eUFzc2V0UmVzcG9uc2USJgoEZGF0YRgBIAEoCzIYLmFwZXJpby52MS5TZWN1cml0eUFzc2V0IhsKGUxpc3RSaXNrRXhjZXB0aW9uc1JlcXVlc3QiRAoaTGlzdFJpc2tFeGNlcHRpb25zUmVzcG9uc2USJgoEZGF0YRgBIAMoCzIYLmFwZXJpby52MS5SaXNrRXhjZXB0aW9uIoIDCg1SaXNrRXhjZXB0aW9uEgoKAmlkGAEgASgJEg0KBXRpdGxlGAIgASgJEhEKCXJhdGlvbmFsZRgDIAEoCRIdChVjb21wZW5zYXRpbmdfY29udHJvbHMYBCADKAkSDgoGc3RhdHVzGAUgASgJEhIKCmV4cGlyZXNfYXQYBiABKAkSEwoLYXBwcm92ZWRfYXQYByABKAkSEgoKY3JlYXRlZF9hdBgIIAEoCRISCgp1cGRhdGVkX2F0GAkgASgJEiwKBWFzc2V0GAogASgLMh0uYXBlcmlvLnYxLlJpc2tFeGNlcHRpb25Bc3NldBIwCgdmaW5kaW5nGAsgASgLMh8uYXBlcmlvLnYxLlJpc2tFeGNlcHRpb25GaW5kaW5nEjAKCmNyZWF0ZWRfYnkYDCABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwSMQoLYXBwcm92ZWRfYnkYDSABKAsyHC5hcGVyaW8udjEuU2VjdXJpdHlQcmluY2lwYWwiPAoSUmlza0V4Y2VwdGlvbkFzc2V0EgoKAmlkGAEgASgJEgwKBG5hbWUYAiABKAkSDAoEdHlwZRgDIAEoCSJTChRSaXNrRXhjZXB0aW9uRmluZGluZxIKCgJpZBgBIAEoCRINCgV0aXRsZRgCIAEoCRIQCghzZXZlcml0eRgDIAEoCRIOCgZzdGF0dXMYBCABKAkilwEKGkNyZWF0ZVJpc2tFeGNlcHRpb25SZXF1ZXN0EhAKCGFzc2V0X2lkGAEgASgJEhIKCmZpbmRpbmdfaWQYAiABKAkSDQoFdGl0bGUYAyABKAkSEQoJcmF0aW9uYWxlGAQgASgJEh0KFWNvbXBlbnNhdGluZ19jb250cm9scxgFIAMoCRISCgpleHBpcmVzX2F0GAYgASgJIkUKG0NyZWF0ZVJpc2tFeGNlcHRpb25SZXNwb25zZRImCgRkYXRhGAEgASgLMhguYXBlcmlvLnYxLlJpc2tFeGNlcHRpb24i+gEKGlVwZGF0ZVJpc2tFeGNlcHRpb25SZXF1ZXN0EgoKAmlkGAEgASgJEhIKBXRpdGxlGAIgASgJSACIAQESFgoJcmF0aW9uYWxlGAMgASgJSAGIAQESHQoVY29tcGVuc2F0aW5nX2NvbnRyb2xzGAQgAygJEiUKHWNvbXBlbnNhdGluZ19jb250cm9sc19wcmVzZW50GAUgASgIEhMKBnN0YXR1cxgGIAEoCUgCiAEBEhcKCmV4cGlyZXNfYXQYByABKAlIA4gBAUIICgZfdGl0bGVCDAoKX3JhdGlvbmFsZUIJCgdfc3RhdHVzQg0KC19leHBpcmVzX2F0IkUKG1VwZGF0ZVJpc2tFeGNlcHRpb25SZXNwb25zZRImCgRkYXRhGAEgASgLMhguYXBlcmlvLnYxLlJpc2tFeGNlcHRpb24i7QIKD0V4ZWN1dGl2ZVJlcG9ydBIKCgJpZBgBIAEoCRIOCgZwZXJpb2QYAiABKAkSFAoMcGVyaW9kX3N0YXJ0GAMgASgJEhIKCnBlcmlvZF9lbmQYBCABKAkSDQoFdGl0bGUYBSABKAkSDwoHc3VtbWFyeRgGIAEoCRIOCgZzdGF0dXMYByABKAkSGQoRa3BpX3NuYXBzaG90X2pzb24YCCABKAkSEAoIaGFzX2h0bWwYCSABKAgSDwoHaGFzX3BkZhgKIAEoCBIQCghodG1sX3VybBgLIAEoCRIPCgdwZGZfdXJsGAwgASgJEhIKCmNyZWF0ZWRfYXQYDSABKAkSEgoKdXBkYXRlZF9hdBgOIAEoCRIUCgxnZW5lcmF0ZWRfYXQYDyABKAkSFQoNZXJyb3JfbWVzc2FnZRgQIAEoCRIcChRyZXF1ZXN0ZWRfYnlfdXNlcl9pZBgRIAEoCRIQCgh0ZW1wbGF0ZRgSIAEoCSIdChtMaXN0RXhlY3V0aXZlUmVwb3J0c1JlcXVlc3QiSAocTGlzdEV4ZWN1dGl2ZVJlcG9ydHNSZXNwb25zZRIoCgRkYXRhGAEgAygLMhouYXBlcmlvLnYxLkV4ZWN1dGl2ZVJlcG9ydCInChlHZXRFeGVjdXRpdmVSZXBvcnRSZXF1ZXN0EgoKAmlkGAEgASgJIkYKGkdldEV4ZWN1dGl2ZVJlcG9ydFJlc3BvbnNlEigKBGRhdGEYASABKAsyGi5hcGVyaW8udjEuRXhlY3V0aXZlUmVwb3J0InkKHENyZWF0ZUV4ZWN1dGl2ZVJlcG9ydFJlcXVlc3QSDgoGcGVyaW9kGAEgASgJEg0KBXRpdGxlGAIgASgJEhQKDHBlcmlvZF9zdGFydBgDIAEoCRISCgpwZXJpb2RfZW5kGAQgASgJEhAKCHRlbXBsYXRlGAUgASgJIkkKHUNyZWF0ZUV4ZWN1dGl2ZVJlcG9ydFJlc3BvbnNlEigKBGRhdGEYASABKAsyGi5hcGVyaW8udjEuRXhlY3V0aXZlUmVwb3J0IioKHERlbGV0ZUV4ZWN1dGl2ZVJlcG9ydFJlcXVlc3QSCgoCaWQYASABKAkiMAodRGVsZXRlRXhlY3V0aXZlUmVwb3J0UmVzcG9uc2USDwoHZGVsZXRlZBgBIAEoCCKQAQoUQ29ubmVjdG9yQnVpbHRJblJ1bGUSCgoCaWQYASABKAkSEAoIcHJvdmlkZXIYAiABKAkSDQoFdGl0bGUYAyABKAkSEwoLZGVzY3JpcHRpb24YBCABKAkSEAoIc2V2ZXJpdHkYBSABKAkSEwoLZXZlbnRfdHlwZXMYBiADKAkSDwoHZW5hYmxlZBgHIAEoCCItChlMaXN0RGV0ZWN0aW9uUGFja3NSZXF1ZXN0EhAKCHByb3ZpZGVyGAEgASgJIkQKGkxpc3REZXRlY3Rpb25QYWNrc1Jlc3BvbnNlEiYKBGRhdGEYASADKAsyGC5hcGVyaW8udjEuRGV0ZWN0aW9uUGFjayKOAQoNRGV0ZWN0aW9uUGFjaxIKCgJpZBgBIAEoCRIQCghwcm92aWRlchgCIAEoCRIMCgRuYW1lGAMgASgJEhMKC2Rlc2NyaXB0aW9uGAQgASgJEg8KB3ZlcnNpb24YBSABKAkSKwoFcnVsZXMYBiADKAsyHC5hcGVyaW8udjEuRGV0ZWN0aW9uUGFja1J1bGUiogEKEURldGVjdGlvblBhY2tSdWxlEgoKAmlkGAEgASgJEg0KBXRpdGxlGAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJEhAKCHNldmVyaXR5GAQgASgJEhMKC2V2ZW50X3R5cGVzGAUgAygJEhgKEG1pdHJlX3RlY2huaXF1ZXMYBiADKAkSDgoGaW50ZW50GAcgASgJEgwKBHRhZ3MYCCADKAkiqQEKE0Nvbm5lY3RvckN1c3RvbVJ1bGUSCgoCaWQYASABKAkSDAoEbmFtZRgCIAEoCRIQCghzZXZlcml0eRgDIAEoCRISCgpldmVudF90eXBlGAQgASgJEhYKDnByZWRpY2F0ZV9qc29uGAUgASgJEg8KB2VuYWJsZWQYBiABKAgSEgoKdXBkYXRlZF9hdBgHIAEoCRIVCg1zdWJqZWN0X2ZpZWxkGAggASgJIjMKGUxpc3RDb25uZWN0b3JSdWxlc1JlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkiqQEKGkxpc3RDb25uZWN0b3JSdWxlc1Jlc3BvbnNlEhYKDmludGVncmF0aW9uX2lkGAEgASgJEhAKCHByb3ZpZGVyGAIgASgJEjEKCGJ1aWx0X2luGAMgAygLMh8uYXBlcmlvLnYxLkNvbm5lY3RvckJ1aWx0SW5SdWxlEi4KBmN1c3RvbRgEIAMoCzIeLmFwZXJpby52MS5Db25uZWN0b3JDdXN0b21SdWxlIqUBChdDcmVhdGVDdXN0b21SdWxlUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRIMCgRuYW1lGAIgASgJEhAKCHNldmVyaXR5GAMgASgJEhIKCmV2ZW50X3R5cGUYBCABKAkSFgoOcHJlZGljYXRlX2pzb24YBSABKAkSDwoHZW5hYmxlZBgGIAEoCBIVCg1zdWJqZWN0X2ZpZWxkGAcgASgJIiYKGENyZWF0ZUN1c3RvbVJ1bGVSZXNwb25zZRIKCgJpZBgBIAEoCSK2AQoXVXBkYXRlQ3VzdG9tUnVsZVJlcXVlc3QSFgoOaW50ZWdyYXRpb25faWQYASABKAkSDwoHcnVsZV9pZBgCIAEoCRIMCgRuYW1lGAMgASgJEhAKCHNldmVyaXR5GAQgASgJEhIKCmV2ZW50X3R5cGUYBSABKAkSFgoOcHJlZGljYXRlX2pzb24YBiABKAkSDwoHZW5hYmxlZBgHIAEoCBIVCg1zdWJqZWN0X2ZpZWxkGAggASgJIiYKGFVwZGF0ZUN1c3RvbVJ1bGVSZXNwb25zZRIKCgJpZBgBIAEoCSJCChdEZWxldGVDdXN0b21SdWxlUmVxdWVzdBIWCg5pbnRlZ3JhdGlvbl9pZBgBIAEoCRIPCgdydWxlX2lkGAIgASgJIiYKGERlbGV0ZUN1c3RvbVJ1bGVSZXNwb25zZRIKCgJpZBgBIAEoCTLLPgoNQXBlcmlvU2VydmljZRJACgdDYWxsQXBpEhkuYXBlcmlvLnYxLkNhbGxBcGlSZXF1ZXN0GhouYXBlcmlvLnYxLkNhbGxBcGlSZXNwb25zZRI9CgZTaWdudXASGC5hcGVyaW8udjEuU2lnbnVwUmVxdWVzdBoZLmFwZXJpby52MS5TaWdudXBSZXNwb25zZRI6CgVMb2dpbhIXLmFwZXJpby52MS5Mb2dpblJlcXVlc3QaGC5hcGVyaW8udjEuTG9naW5SZXNwb25zZRJeChFHZXRDdXJyZW50U2Vzc2lvbhIjLmFwZXJpby52MS5HZXRDdXJyZW50U2Vzc2lvblJlcXVlc3QaJC5hcGVyaW8udjEuR2V0Q3VycmVudFNlc3Npb25SZXNwb25zZRJnChRMb2dvdXRDdXJyZW50U2Vzc2lvbhImLmFwZXJpby52MS5Mb2dvdXRDdXJyZW50U2Vzc2lvblJlcXVlc3QaJy5hcGVyaW8udjEuTG9nb3V0Q3VycmVudFNlc3Npb25SZXNwb25zZRJVCg5MaXN0V29ya3NwYWNlcxIgLmFwZXJpby52MS5MaXN0V29ya3NwYWNlc1JlcXVlc3QaIS5hcGVyaW8udjEuTGlzdFdvcmtzcGFjZXNSZXNwb25zZRJYCg9Td2l0Y2hXb3Jrc3BhY2USIS5hcGVyaW8udjEuU3dpdGNoV29ya3NwYWNlUmVxdWVzdBoiLmFwZXJpby52MS5Td2l0Y2hXb3Jrc3BhY2VSZXNwb25zZRJnChRSZXF1ZXN0UGFzc3dvcmRSZXNldBImLmFwZXJpby52MS5SZXF1ZXN0UGFzc3dvcmRSZXNldFJlcXVlc3QaJy5hcGVyaW8udjEuUmVxdWVzdFBhc3N3b3JkUmVzZXRSZXNwb25zZRJSCg1SZXNldFBhc3N3b3JkEh8uYXBlcmlvLnYxLlJlc2V0UGFzc3dvcmRSZXF1ZXN0GiAuYXBlcmlvLnYxLlJlc2V0UGFzc3dvcmRSZXNwb25zZRJPCgxBY2NlcHRJbnZpdGUSHi5hcGVyaW8udjEuQWNjZXB0SW52aXRlUmVxdWVzdBofLmFwZXJpby52MS5BY2NlcHRJbnZpdGVSZXNwb25zZRJhChJCZWdpbk1mYUVucm9sbG1lbnQSJC5hcGVyaW8udjEuQmVnaW5NZmFFbnJvbGxtZW50UmVxdWVzdBolLmFwZXJpby52MS5CZWdpbk1mYUVucm9sbG1lbnRSZXNwb25zZRJGCglFbmFibGVNZmESGy5hcGVyaW8udjEuRW5hYmxlTWZhUmVxdWVzdBocLmFwZXJpby52MS5FbmFibGVNZmFSZXNwb25zZRJJCgpEaXNhYmxlTWZhEhwuYXBlcmlvLnYxLkRpc2FibGVNZmFSZXF1ZXN0Gh0uYXBlcmlvLnYxLkRpc2FibGVNZmFSZXNwb25zZRJMCgtDaGVja0hlYWx0aBIdLmFwZXJpby52MS5DaGVja0hlYWx0aFJlcXVlc3QaHi5hcGVyaW8udjEuQ2hlY2tIZWFsdGhSZXNwb25zZRJkChNHZXREYXNoYm9hcmRNZXRyaWNzEiUuYXBlcmlvLnYxLkdldERhc2hib2FyZE1ldHJpY3NSZXF1ZXN0GiYuYXBlcmlvLnYxLkdldERhc2hib2FyZE1ldHJpY3NSZXNwb25zZRJPCgxMaXN0RmluZGluZ3MSHi5hcGVyaW8udjEuTGlzdEZpbmRpbmdzUmVxdWVzdBofLmFwZXJpby52MS5MaXN0RmluZGluZ3NSZXNwb25zZRJJCgpHZXRGaW5kaW5nEhwuYXBlcmlvLnYxLkdldEZpbmRpbmdSZXF1ZXN0Gh0uYXBlcmlvLnYxLkdldEZpbmRpbmdSZXNwb25zZRJkChNVcGRhdGVGaW5kaW5nU3RhdHVzEiUuYXBlcmlvLnYxLlVwZGF0ZUZpbmRpbmdTdGF0dXNSZXF1ZXN0GiYuYXBlcmlvLnYxLlVwZGF0ZUZpbmRpbmdTdGF0dXNSZXNwb25zZRJbChBSZW1lZGlhdGVGaW5kaW5nEiIuYXBlcmlvLnYxLlJlbWVkaWF0ZUZpbmRpbmdSZXF1ZXN0GiMuYXBlcmlvLnYxLlJlbWVkaWF0ZUZpbmRpbmdSZXNwb25zZRJeChFMaXN0U2Fhc0luY2lkZW50cxIjLmFwZXJpby52MS5MaXN0U2Fhc0luY2lkZW50c1JlcXVlc3QaJC5hcGVyaW8udjEuTGlzdFNhYXNJbmNpZGVudHNSZXNwb25zZRJYCg9HZXRTYWFzSW5jaWRlbnQSIS5hcGVyaW8udjEuR2V0U2Fhc0luY2lkZW50UmVxdWVzdBoiLmFwZXJpby52MS5HZXRTYWFzSW5jaWRlbnRSZXNwb25zZRJhChJDcmVhdGVTYWFzSW5jaWRlbnQSJC5hcGVyaW8udjEuQ3JlYXRlU2Fhc0luY2lkZW50UmVxdWVzdBolLmFwZXJpby52MS5DcmVhdGVTYWFzSW5jaWRlbnRSZXNwb25zZRJzChhVcGRhdGVTYWFzSW5jaWRlbnRTdGF0dXMSKi5hcGVyaW8udjEuVXBkYXRlU2Fhc0luY2lkZW50U3RhdHVzUmVxdWVzdBorLmFwZXJpby52MS5VcGRhdGVTYWFzSW5jaWRlbnRTdGF0dXNSZXNwb25zZRJ2ChlQcm9wb3NlU2Fhc1Jlc3BvbnNlQWN0aW9uEisuYXBlcmlvLnYxLlByb3Bvc2VTYWFzUmVzcG9uc2VBY3Rpb25SZXF1ZXN0GiwuYXBlcmlvLnYxLlByb3Bvc2VTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRJ2ChlBcHByb3ZlU2Fhc1Jlc3BvbnNlQWN0aW9uEisuYXBlcmlvLnYxLkFwcHJvdmVTYWFzUmVzcG9uc2VBY3Rpb25SZXF1ZXN0GiwuYXBlcmlvLnYxLkFwcHJvdmVTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRJ2ChlFeGVjdXRlU2Fhc1Jlc3BvbnNlQWN0aW9uEisuYXBlcmlvLnYxLkV4ZWN1dGVTYWFzUmVzcG9uc2VBY3Rpb25SZXF1ZXN0GiwuYXBlcmlvLnYxLkV4ZWN1dGVTYWFzUmVzcG9uc2VBY3Rpb25SZXNwb25zZRJhChJMaXN0RGV0ZWN0aW9uUGFja3MSJC5hcGVyaW8udjEuTGlzdERldGVjdGlvblBhY2tzUmVxdWVzdBolLmFwZXJpby52MS5MaXN0RGV0ZWN0aW9uUGFja3NSZXNwb25zZRJnChRMaXN0Q29ubmVjdG9yQ2F0YWxvZxImLmFwZXJpby52MS5MaXN0Q29ubmVjdG9yQ2F0YWxvZ1JlcXVlc3QaJy5hcGVyaW8udjEuTGlzdENvbm5lY3RvckNhdGFsb2dSZXNwb25zZRJbChBMaXN0SW50ZWdyYXRpb25zEiIuYXBlcmlvLnYxLkxpc3RJbnRlZ3JhdGlvbnNSZXF1ZXN0GiMuYXBlcmlvLnYxLkxpc3RJbnRlZ3JhdGlvbnNSZXNwb25zZRJeChFDcmVhdGVJbnRlZ3JhdGlvbhIjLmFwZXJpby52MS5DcmVhdGVJbnRlZ3JhdGlvblJlcXVlc3QaJC5hcGVyaW8udjEuQ3JlYXRlSW50ZWdyYXRpb25SZXNwb25zZRJeChFEZWxldGVJbnRlZ3JhdGlvbhIjLmFwZXJpby52MS5EZWxldGVJbnRlZ3JhdGlvblJlcXVlc3QaJC5hcGVyaW8udjEuRGVsZXRlSW50ZWdyYXRpb25SZXNwb25zZRJnChRHZXRJbnRlZ3JhdGlvbkNoZWNrcxImLmFwZXJpby52MS5HZXRJbnRlZ3JhdGlvbkNoZWNrc1JlcXVlc3QaJy5hcGVyaW8udjEuR2V0SW50ZWdyYXRpb25DaGVja3NSZXNwb25zZRJwChdVcGRhdGVJbnRlZ3JhdGlvbkNoZWNrcxIpLmFwZXJpby52MS5VcGRhdGVJbnRlZ3JhdGlvbkNoZWNrc1JlcXVlc3QaKi5hcGVyaW8udjEuVXBkYXRlSW50ZWdyYXRpb25DaGVja3NSZXNwb25zZRJhChJMaXN0Q29ubmVjdG9yUnVsZXMSJC5hcGVyaW8udjEuTGlzdENvbm5lY3RvclJ1bGVzUmVxdWVzdBolLmFwZXJpby52MS5MaXN0Q29ubmVjdG9yUnVsZXNSZXNwb25zZRJbChBDcmVhdGVDdXN0b21SdWxlEiIuYXBlcmlvLnYxLkNyZWF0ZUN1c3RvbVJ1bGVSZXF1ZXN0GiMuYXBlcmlvLnYxLkNyZWF0ZUN1c3RvbVJ1bGVSZXNwb25zZRJbChBVcGRhdGVDdXN0b21SdWxlEiIuYXBlcmlvLnYxLlVwZGF0ZUN1c3RvbVJ1bGVSZXF1ZXN0GiMuYXBlcmlvLnYxLlVwZGF0ZUN1c3RvbVJ1bGVSZXNwb25zZRJbChBEZWxldGVDdXN0b21SdWxlEiIuYXBlcmlvLnYxLkRlbGV0ZUN1c3RvbVJ1bGVSZXF1ZXN0GiMuYXBlcmlvLnYxLkRlbGV0ZUN1c3RvbVJ1bGVSZXNwb25zZRJ5ChpHZXRHb29nbGVNYWlsYm94U2NhbkNvbmZpZxIsLmFwZXJpby52MS5HZXRHb29nbGVNYWlsYm94U2NhbkNvbmZpZ1JlcXVlc3QaLS5hcGVyaW8udjEuR2V0R29vZ2xlTWFpbGJveFNjYW5Db25maWdSZXNwb25zZRKCAQodVXBkYXRlR29vZ2xlTWFpbGJveFNjYW5Db25maWcSLy5hcGVyaW8udjEuVXBkYXRlR29vZ2xlTWFpbGJveFNjYW5Db25maWdSZXF1ZXN0GjAuYXBlcmlvLnYxLlVwZGF0ZUdvb2dsZU1haWxib3hTY2FuQ29uZmlnUmVzcG9uc2USiwEKIEdldEdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnEjIuYXBlcmlvLnYxLkdldEdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnUmVxdWVzdBozLmFwZXJpby52MS5HZXRHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1Jlc3BvbnNlEpQBCiNVcGRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZxI1LmFwZXJpby52MS5VcGRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZ1JlcXVlc3QaNi5hcGVyaW8udjEuVXBkYXRlR29vZ2xlV29ya3NwYWNlQmlnUXVlcnlDb25maWdSZXNwb25zZRKaAQolVmFsaWRhdGVHb29nbGVXb3Jrc3BhY2VCaWdRdWVyeUNvbmZpZxI3LmFwZXJpby52MS5WYWxpZGF0ZUdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnUmVxdWVzdBo4LmFwZXJpby52MS5WYWxpZGF0ZUdvb2dsZVdvcmtzcGFjZUJpZ1F1ZXJ5Q29uZmlnUmVzcG9uc2USdgoZU3RhcnRHb29nbGVXb3Jrc3BhY2VPQXV0aBIrLmFwZXJpby52MS5TdGFydEdvb2dsZVdvcmtzcGFjZU9BdXRoUmVxdWVzdBosLmFwZXJpby52MS5TdGFydEdvb2dsZVdvcmtzcGFjZU9BdXRoUmVzcG9uc2USdgoZR2V0SW50ZWdyYXRpb25PQXV0aENsaWVudBIrLmFwZXJpby52MS5HZXRJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50UmVxdWVzdBosLmFwZXJpby52MS5HZXRJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50UmVzcG9uc2USdgoZU2V0SW50ZWdyYXRpb25PQXV0aENsaWVudBIrLmFwZXJpby52MS5TZXRJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50UmVxdWVzdBosLmFwZXJpby52MS5TZXRJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50UmVzcG9uc2USfAobQ2xlYXJJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50Ei0uYXBlcmlvLnYxLkNsZWFySW50ZWdyYXRpb25PQXV0aENsaWVudFJlcXVlc3QaLi5hcGVyaW8udjEuQ2xlYXJJbnRlZ3JhdGlvbk9BdXRoQ2xpZW50UmVzcG9uc2USZwoURm9yY2VTeW5jSW50ZWdyYXRpb24SJi5hcGVyaW8udjEuRm9yY2VTeW5jSW50ZWdyYXRpb25SZXF1ZXN0GicuYXBlcmlvLnYxLkZvcmNlU3luY0ludGVncmF0aW9uUmVzcG9uc2UScwoYR2V0SW50ZWdyYXRpb25TeW5jU3RhdHVzEiouYXBlcmlvLnYxLkdldEludGVncmF0aW9uU3luY1N0YXR1c1JlcXVlc3QaKy5hcGVyaW8udjEuR2V0SW50ZWdyYXRpb25TeW5jU3RhdHVzUmVzcG9uc2UScwoYUnVuSW50ZWdyYXRpb25Tb3VyY2VTeW5jEiouYXBlcmlvLnYxLlJ1bkludGVncmF0aW9uU291cmNlU3luY1JlcXVlc3QaKy5hcGVyaW8udjEuUnVuSW50ZWdyYXRpb25Tb3VyY2VTeW5jUmVzcG9uc2USdgoZQmFja2ZpbGxJbnRlZ3JhdGlvblNvdXJjZRIrLmFwZXJpby52MS5CYWNrZmlsbEludGVncmF0aW9uU291cmNlUmVxdWVzdBosLmFwZXJpby52MS5CYWNrZmlsbEludGVncmF0aW9uU291cmNlUmVzcG9uc2USWAoPTGlzdFNpZW1DYXRhbG9nEiEuYXBlcmlvLnYxLkxpc3RTaWVtQ2F0YWxvZ1JlcXVlc3QaIi5hcGVyaW8udjEuTGlzdFNpZW1DYXRhbG9nUmVzcG9uc2USZwoUTGlzdFNpZW1EZXN0aW5hdGlvbnMSJi5hcGVyaW8udjEuTGlzdFNpZW1EZXN0aW5hdGlvbnNSZXF1ZXN0GicuYXBlcmlvLnYxLkxpc3RTaWVtRGVzdGluYXRpb25zUmVzcG9uc2USagoVQ3JlYXRlU2llbURlc3RpbmF0aW9uEicuYXBlcmlvLnYxLkNyZWF0ZVNpZW1EZXN0aW5hdGlvblJlcXVlc3QaKC5hcGVyaW8udjEuQ3JlYXRlU2llbURlc3RpbmF0aW9uUmVzcG9uc2USagoVRGVsZXRlU2llbURlc3RpbmF0aW9uEicuYXBlcmlvLnYxLkRlbGV0ZVNpZW1EZXN0aW5hdGlvblJlcXVlc3QaKC5hcGVyaW8udjEuRGVsZXRlU2llbURlc3RpbmF0aW9uUmVzcG9uc2USZAoTVGVzdFNpZW1EZXN0aW5hdGlvbhIlLmFwZXJpby52MS5UZXN0U2llbURlc3RpbmF0aW9uUmVxdWVzdBomLmFwZXJpby52MS5UZXN0U2llbURlc3RpbmF0aW9uUmVzcG9uc2USagoVTGlzdFNoYWRvd0l0T2F1dGhBcHBzEicuYXBlcmlvLnYxLkxpc3RTaGFkb3dJdE9hdXRoQXBwc1JlcXVlc3QaKC5hcGVyaW8udjEuTGlzdFNoYWRvd0l0T2F1dGhBcHBzUmVzcG9uc2USeQoaTGlzdFNoYWRvd0l0T2F1dGhBcHBHcmFudHMSLC5hcGVyaW8udjEuTGlzdFNoYWRvd0l0T2F1dGhBcHBHcmFudHNSZXF1ZXN0Gi0uYXBlcmlvLnYxLkxpc3RTaGFkb3dJdE9hdXRoQXBwR3JhbnRzUmVzcG9uc2USXgoRR2V0VGVuYW50U2V0dGluZ3MSIy5hcGVyaW8udjEuR2V0VGVuYW50U2V0dGluZ3NSZXF1ZXN0GiQuYXBlcmlvLnYxLkdldFRlbmFudFNldHRpbmdzUmVzcG9uc2USZwoUVXBkYXRlVGVuYW50U2V0dGluZ3MSJi5hcGVyaW8udjEuVXBkYXRlVGVuYW50U2V0dGluZ3NSZXF1ZXN0GicuYXBlcmlvLnYxLlVwZGF0ZVRlbmFudFNldHRpbmdzUmVzcG9uc2USXgoRTGlzdFRlbmFudE1lbWJlcnMSIy5hcGVyaW8udjEuTGlzdFRlbmFudE1lbWJlcnNSZXF1ZXN0GiQuYXBlcmlvLnYxLkxpc3RUZW5hbnRNZW1iZXJzUmVzcG9uc2USYQoSQ3JlYXRlVGVuYW50TWVtYmVyEiQuYXBlcmlvLnYxLkNyZWF0ZVRlbmFudE1lbWJlclJlcXVlc3QaJS5hcGVyaW8udjEuQ3JlYXRlVGVuYW50TWVtYmVyUmVzcG9uc2USagoVQ3JlYXRlTWVtYmVyUmVzZXRMaW5rEicuYXBlcmlvLnYxLkNyZWF0ZU1lbWJlclJlc2V0TGlua1JlcXVlc3QaKC5hcGVyaW8udjEuQ3JlYXRlTWVtYmVyUmVzZXRMaW5rUmVzcG9uc2USWwoQVXBkYXRlTWVtYmVyUm9sZRIiLmFwZXJpby52MS5VcGRhdGVNZW1iZXJSb2xlUmVxdWVzdBojLmFwZXJpby52MS5VcGRhdGVNZW1iZXJSb2xlUmVzcG9uc2USUgoNTGlzdEF1ZGl0TG9ncxIfLmFwZXJpby52MS5MaXN0QXVkaXRMb2dzUmVxdWVzdBogLmFwZXJpby52MS5MaXN0QXVkaXRMb2dzUmVzcG9uc2USZAoTR2V0U2VjdXJpdHlPdmVydmlldxIlLmFwZXJpby52MS5HZXRTZWN1cml0eU92ZXJ2aWV3UmVxdWVzdBomLmFwZXJpby52MS5HZXRTZWN1cml0eU92ZXJ2aWV3UmVzcG9uc2USagoVTGlzdEVtYWlsRG9tYWluSGVhbHRoEicuYXBlcmlvLnYxLkxpc3RFbWFpbERvbWFpbkhlYWx0aFJlcXVlc3QaKC5hcGVyaW8udjEuTGlzdEVtYWlsRG9tYWluSGVhbHRoUmVzcG9uc2USZwoUR2V0RW1haWxEb21haW5IZWFsdGgSJi5hcGVyaW8udjEuR2V0RW1haWxEb21haW5IZWFsdGhSZXF1ZXN0GicuYXBlcmlvLnYxLkdldEVtYWlsRG9tYWluSGVhbHRoUmVzcG9uc2UScwoYUmVmcmVzaEVtYWlsRG9tYWluSGVhbHRoEiouYXBlcmlvLnYxLlJlZnJlc2hFbWFpbERvbWFpbkhlYWx0aFJlcXVlc3QaKy5hcGVyaW8udjEuUmVmcmVzaEVtYWlsRG9tYWluSGVhbHRoUmVzcG9uc2USYQoSTGlzdFNlY3VyaXR5QXNzZXRzEiQuYXBlcmlvLnYxLkxpc3RTZWN1cml0eUFzc2V0c1JlcXVlc3QaJS5hcGVyaW8udjEuTGlzdFNlY3VyaXR5QXNzZXRzUmVzcG9uc2USZAoTQ3JlYXRlU2VjdXJpdHlBc3NldBIlLmFwZXJpby52MS5DcmVhdGVTZWN1cml0eUFzc2V0UmVxdWVzdBomLmFwZXJpby52MS5DcmVhdGVTZWN1cml0eUFzc2V0UmVzcG9uc2USZAoTVXBkYXRlU2VjdXJpdHlBc3NldBIlLmFwZXJpby52MS5VcGRhdGVTZWN1cml0eUFzc2V0UmVxdWVzdBomLmFwZXJpby52MS5VcGRhdGVTZWN1cml0eUFzc2V0UmVzcG9uc2USYQoSTGlzdFJpc2tFeGNlcHRpb25zEiQuYXBlcmlvLnYxLkxpc3RSaXNrRXhjZXB0aW9uc1JlcXVlc3QaJS5hcGVyaW8udjEuTGlzdFJpc2tFeGNlcHRpb25zUmVzcG9uc2USZAoTQ3JlYXRlUmlza0V4Y2VwdGlvbhIlLmFwZXJpby52MS5DcmVhdGVSaXNrRXhjZXB0aW9uUmVxdWVzdBomLmFwZXJpby52MS5DcmVhdGVSaXNrRXhjZXB0aW9uUmVzcG9uc2USZAoTVXBkYXRlUmlza0V4Y2VwdGlvbhIlLmFwZXJpby52MS5VcGRhdGVSaXNrRXhjZXB0aW9uUmVxdWVzdBomLmFwZXJpby52MS5VcGRhdGVSaXNrRXhjZXB0aW9uUmVzcG9uc2USZwoUTGlzdEV4ZWN1dGl2ZVJlcG9ydHMSJi5hcGVyaW8udjEuTGlzdEV4ZWN1dGl2ZVJlcG9ydHNSZXF1ZXN0GicuYXBlcmlvLnYxLkxpc3RFeGVjdXRpdmVSZXBvcnRzUmVzcG9uc2USYQoSR2V0RXhlY3V0aXZlUmVwb3J0EiQuYXBlcmlvLnYxLkdldEV4ZWN1dGl2ZVJlcG9ydFJlcXVlc3QaJS5hcGVyaW8udjEuR2V0RXhlY3V0aXZlUmVwb3J0UmVzcG9uc2USagoVQ3JlYXRlRXhlY3V0aXZlUmVwb3J0EicuYXBlcmlvLnYxLkNyZWF0ZUV4ZWN1dGl2ZVJlcG9ydFJlcXVlc3QaKC5hcGVyaW8udjEuQ3JlYXRlRXhlY3V0aXZlUmVwb3J0UmVzcG9uc2USagoVRGVsZXRlRXhlY3V0aXZlUmVwb3J0EicuYXBlcmlvLnYxLkRlbGV0ZUV4ZWN1dGl2ZVJlcG9ydFJlcXVlc3QaKC5hcGVyaW8udjEuRGVsZXRlRXhlY3V0aXZlUmVwb3J0UmVzcG9uc2VCMVovZ2l0aHViLmNvbS93cml0ZXIvYXBlcmlvL2dlbi9hcGVyaW8vdjE7YXBlcmlvdjFiBnByb3RvMw", [file_google_protobuf_timestamp]); /** * @generated from message aperio.v1.CallApiRequest @@ -6955,6 +6955,136 @@ export type ConnectorBuiltInRule = Message<"aperio.v1.ConnectorBuiltInRule"> & { export const ConnectorBuiltInRuleSchema: GenMessage = /*@__PURE__*/ messageDesc(file_aperio_v1_api, 223); +/** + * @generated from message aperio.v1.ListDetectionPacksRequest + */ +export type ListDetectionPacksRequest = Message<"aperio.v1.ListDetectionPacksRequest"> & { + /** + * Optional provider filter (e.g. "GOOGLE_WORKSPACE"). Empty returns every pack. + * + * @generated from field: string provider = 1; + */ + provider: string; +}; + +/** + * Describes the message aperio.v1.ListDetectionPacksRequest. + * Use `create(ListDetectionPacksRequestSchema)` to create a new message. + */ +export const ListDetectionPacksRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_aperio_v1_api, 224); + +/** + * @generated from message aperio.v1.ListDetectionPacksResponse + */ +export type ListDetectionPacksResponse = Message<"aperio.v1.ListDetectionPacksResponse"> & { + /** + * @generated from field: repeated aperio.v1.DetectionPack data = 1; + */ + data: DetectionPack[]; +}; + +/** + * Describes the message aperio.v1.ListDetectionPacksResponse. + * Use `create(ListDetectionPacksResponseSchema)` to create a new message. + */ +export const ListDetectionPacksResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_aperio_v1_api, 225); + +/** + * @generated from message aperio.v1.DetectionPack + */ +export type DetectionPack = Message<"aperio.v1.DetectionPack"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string provider = 2; + */ + provider: string; + + /** + * @generated from field: string name = 3; + */ + name: string; + + /** + * @generated from field: string description = 4; + */ + description: string; + + /** + * @generated from field: string version = 5; + */ + version: string; + + /** + * @generated from field: repeated aperio.v1.DetectionPackRule rules = 6; + */ + rules: DetectionPackRule[]; +}; + +/** + * Describes the message aperio.v1.DetectionPack. + * Use `create(DetectionPackSchema)` to create a new message. + */ +export const DetectionPackSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_aperio_v1_api, 226); + +/** + * @generated from message aperio.v1.DetectionPackRule + */ +export type DetectionPackRule = Message<"aperio.v1.DetectionPackRule"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string title = 2; + */ + title: string; + + /** + * @generated from field: string description = 3; + */ + description: string; + + /** + * @generated from field: string severity = 4; + */ + severity: string; + + /** + * @generated from field: repeated string event_types = 5; + */ + eventTypes: string[]; + + /** + * @generated from field: repeated string mitre_techniques = 6; + */ + mitreTechniques: string[]; + + /** + * @generated from field: string intent = 7; + */ + intent: string; + + /** + * @generated from field: repeated string tags = 8; + */ + tags: string[]; +}; + +/** + * Describes the message aperio.v1.DetectionPackRule. + * Use `create(DetectionPackRuleSchema)` to create a new message. + */ +export const DetectionPackRuleSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_aperio_v1_api, 227); + /** * @generated from message aperio.v1.ConnectorCustomRule */ @@ -7005,7 +7135,7 @@ export type ConnectorCustomRule = Message<"aperio.v1.ConnectorCustomRule"> & { * Use `create(ConnectorCustomRuleSchema)` to create a new message. */ export const ConnectorCustomRuleSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 224); + messageDesc(file_aperio_v1_api, 228); /** * @generated from message aperio.v1.ListConnectorRulesRequest @@ -7022,7 +7152,7 @@ export type ListConnectorRulesRequest = Message<"aperio.v1.ListConnectorRulesReq * Use `create(ListConnectorRulesRequestSchema)` to create a new message. */ export const ListConnectorRulesRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 225); + messageDesc(file_aperio_v1_api, 229); /** * @generated from message aperio.v1.ListConnectorRulesResponse @@ -7054,7 +7184,7 @@ export type ListConnectorRulesResponse = Message<"aperio.v1.ListConnectorRulesRe * Use `create(ListConnectorRulesResponseSchema)` to create a new message. */ export const ListConnectorRulesResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 226); + messageDesc(file_aperio_v1_api, 230); /** * @generated from message aperio.v1.CreateCustomRuleRequest @@ -7101,7 +7231,7 @@ export type CreateCustomRuleRequest = Message<"aperio.v1.CreateCustomRuleRequest * Use `create(CreateCustomRuleRequestSchema)` to create a new message. */ export const CreateCustomRuleRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 227); + messageDesc(file_aperio_v1_api, 231); /** * @generated from message aperio.v1.CreateCustomRuleResponse @@ -7118,7 +7248,7 @@ export type CreateCustomRuleResponse = Message<"aperio.v1.CreateCustomRuleRespon * Use `create(CreateCustomRuleResponseSchema)` to create a new message. */ export const CreateCustomRuleResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 228); + messageDesc(file_aperio_v1_api, 232); /** * @generated from message aperio.v1.UpdateCustomRuleRequest @@ -7170,7 +7300,7 @@ export type UpdateCustomRuleRequest = Message<"aperio.v1.UpdateCustomRuleRequest * Use `create(UpdateCustomRuleRequestSchema)` to create a new message. */ export const UpdateCustomRuleRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 229); + messageDesc(file_aperio_v1_api, 233); /** * @generated from message aperio.v1.UpdateCustomRuleResponse @@ -7187,7 +7317,7 @@ export type UpdateCustomRuleResponse = Message<"aperio.v1.UpdateCustomRuleRespon * Use `create(UpdateCustomRuleResponseSchema)` to create a new message. */ export const UpdateCustomRuleResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 230); + messageDesc(file_aperio_v1_api, 234); /** * @generated from message aperio.v1.DeleteCustomRuleRequest @@ -7209,7 +7339,7 @@ export type DeleteCustomRuleRequest = Message<"aperio.v1.DeleteCustomRuleRequest * Use `create(DeleteCustomRuleRequestSchema)` to create a new message. */ export const DeleteCustomRuleRequestSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 231); + messageDesc(file_aperio_v1_api, 235); /** * @generated from message aperio.v1.DeleteCustomRuleResponse @@ -7226,7 +7356,7 @@ export type DeleteCustomRuleResponse = Message<"aperio.v1.DeleteCustomRuleRespon * Use `create(DeleteCustomRuleResponseSchema)` to create a new message. */ export const DeleteCustomRuleResponseSchema: GenMessage = /*@__PURE__*/ - messageDesc(file_aperio_v1_api, 232); + messageDesc(file_aperio_v1_api, 236); /** * @generated from service aperio.v1.AperioService @@ -7440,6 +7570,14 @@ export const AperioService: GenService<{ input: typeof ExecuteSaasResponseActionRequestSchema; output: typeof ExecuteSaasResponseActionResponseSchema; }, + /** + * @generated from rpc aperio.v1.AperioService.ListDetectionPacks + */ + listDetectionPacks: { + methodKind: "unary"; + input: typeof ListDetectionPacksRequestSchema; + output: typeof ListDetectionPacksResponseSchema; + }, /** * @generated from rpc aperio.v1.AperioService.ListConnectorCatalog */ diff --git a/proto/aperio/v1/api.proto b/proto/aperio/v1/api.proto index 8e0b5f6e..d13fed23 100644 --- a/proto/aperio/v1/api.proto +++ b/proto/aperio/v1/api.proto @@ -33,6 +33,7 @@ service AperioService { rpc ProposeSaasResponseAction(ProposeSaasResponseActionRequest) returns (ProposeSaasResponseActionResponse); rpc ApproveSaasResponseAction(ApproveSaasResponseActionRequest) returns (ApproveSaasResponseActionResponse); rpc ExecuteSaasResponseAction(ExecuteSaasResponseActionRequest) returns (ExecuteSaasResponseActionResponse); + rpc ListDetectionPacks(ListDetectionPacksRequest) returns (ListDetectionPacksResponse); rpc ListConnectorCatalog(ListConnectorCatalogRequest) returns (ListConnectorCatalogResponse); rpc ListIntegrations(ListIntegrationsRequest) returns (ListIntegrationsResponse); rpc CreateIntegration(CreateIntegrationRequest) returns (CreateIntegrationResponse); @@ -1595,6 +1596,35 @@ message ConnectorBuiltInRule { bool enabled = 7; } +message ListDetectionPacksRequest { + // Optional provider filter (e.g. "GOOGLE_WORKSPACE"). Empty returns every pack. + string provider = 1; +} + +message ListDetectionPacksResponse { + repeated DetectionPack data = 1; +} + +message DetectionPack { + string id = 1; + string provider = 2; + string name = 3; + string description = 4; + string version = 5; + repeated DetectionPackRule rules = 6; +} + +message DetectionPackRule { + string id = 1; + string title = 2; + string description = 3; + string severity = 4; + repeated string event_types = 5; + repeated string mitre_techniques = 6; + string intent = 7; + repeated string tags = 8; +} + message ConnectorCustomRule { string id = 1; string name = 2; diff --git a/tests/fe-contracts.test.ts b/tests/fe-contracts.test.ts index f13bffc8..8def0885 100644 --- a/tests/fe-contracts.test.ts +++ b/tests/fe-contracts.test.ts @@ -58,7 +58,8 @@ test("frontend-consumed AperioService RPC inventory is implemented and wrapped", readRepoFile("internal/bootstrap/app.go"), readRepoFile("internal/bootstrap/typed_compat.go"), readRepoFile("internal/bootstrap/saas_dr.go"), - readRepoFile("internal/bootstrap/oauth_clients.go") + readRepoFile("internal/bootstrap/oauth_clients.go"), + readRepoFile("internal/bootstrap/detection_packs.go") ].join("\n"); const rpcs = serviceRpcNames(proto); @@ -115,6 +116,7 @@ test("React-facing API exports cover typed product RPCs without exposing CallApi ProposeSaasResponseAction: "proposeSaasResponseAction", ApproveSaasResponseAction: "approveSaasResponseAction", ExecuteSaasResponseAction: "executeSaasResponseAction", + ListDetectionPacks: "fetchDetectionPacks", ListConnectorCatalog: "fetchConnectorCatalog", ListIntegrations: "fetchIntegrations", CreateIntegration: "connectIntegration", From ce242b07cea13e73f719182acb228703c053d93d Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 00:52:28 -0700 Subject: [PATCH 02/15] Update internal/bootstrap/detection_packs.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/bootstrap/detection_packs.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/bootstrap/detection_packs.go b/internal/bootstrap/detection_packs.go index 89d87bd9..a9b87608 100644 --- a/internal/bootstrap/detection_packs.go +++ b/internal/bootstrap/detection_packs.go @@ -21,10 +21,7 @@ func (a *App) ListDetectionPacks( if _, err := a.authenticatedOrganization(ctx, req.Header()); err != nil { return nil, err } - providerFilter := "" - if req.Msg != nil { - providerFilter = req.Msg.Provider - } + providerFilter := req.Msg.Provider out := &aperiov1.ListDetectionPacksResponse{} for _, pack := range ingestionworker.DetectionPacks { if providerFilter != "" && providerFilter != pack.Provider { From 63b9bc61ff9b58811a19bc9a3a3b6ed496545dfc Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 00:52:37 -0700 Subject: [PATCH 03/15] Update internal/ingestionworker/detection_packs.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/detection_packs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/detection_packs.go b/internal/ingestionworker/detection_packs.go index e820e14c..4a849cd4 100644 --- a/internal/ingestionworker/detection_packs.go +++ b/internal/ingestionworker/detection_packs.go @@ -80,7 +80,7 @@ func DetectionPackByID(id string) (DetectionPack, bool) { } // RulesInPack returns every RuleCatalog entry that names the given pack -// ID, preserving catalog display order. An unknown pack returns nil. +// ID, preserving catalog display order. An unknown pack returns an empty slice. func RulesInPack(packID string) []RuleCatalogEntry { out := make([]RuleCatalogEntry, 0, 4) for _, entry := range RuleCatalog { From 1fdb8800f5df579e57ecbc5218c97a4256680b54 Mon Sep 17 00:00:00 2001 From: Damian Coln Date: Wed, 17 Jun 2026 00:55:01 -0700 Subject: [PATCH 04/15] saas-dr: trim detection pack descriptions to current rule coverage Pack descriptions are analyst-facing capability statements per the DetectionPack doc comment, so they cannot claim coverage that does not yet ship. Trim three packs to match only the rules backing them in this PR; the deferred detections in #157 will reintroduce the broader coverage language when they land. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/detection_packs.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/ingestionworker/detection_packs.go b/internal/ingestionworker/detection_packs.go index 4a849cd4..85ec03d1 100644 --- a/internal/ingestionworker/detection_packs.go +++ b/internal/ingestionworker/detection_packs.go @@ -27,14 +27,14 @@ var DetectionPacks = []DetectionPack{ ID: "aperio.github.core.v1", Provider: "GITHUB", Name: "GitHub repository hygiene", - Description: "Public repository creation, branch protection bypass, and personal access token misuse on GitHub.", + Description: "Public repository creation events on GitHub.", Version: "1.0.0", }, { ID: "aperio.slack.core.v1", Provider: "SLACK", Name: "Slack workspace access", - Description: "Multi-factor authentication state and external-collaborator access events on Slack.", + Description: "Multi-factor authentication disablement on Slack.", Version: "1.0.0", }, { @@ -62,7 +62,7 @@ var DetectionPacks = []DetectionPack{ ID: "aperio.google_workspace.drive.v1", Provider: "GOOGLE_WORKSPACE", Name: "Google Workspace Drive sharing & OAuth", - Description: "External Drive sharing, risky OAuth grants, and mass-download exfiltration patterns in Google Workspace.", + Description: "External Drive sharing and risky third-party OAuth grants in Google Workspace.", Version: "1.0.0", }, } From c58601d2aca520f351ddda5c6d3069045452fa0c Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 01:08:38 -0700 Subject: [PATCH 05/15] Update internal/ingestionworker/detection_packs.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/detection_packs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/detection_packs.go b/internal/ingestionworker/detection_packs.go index 85ec03d1..2e5e8669 100644 --- a/internal/ingestionworker/detection_packs.go +++ b/internal/ingestionworker/detection_packs.go @@ -55,7 +55,7 @@ var DetectionPacks = []DetectionPack{ ID: "aperio.google_workspace.mail.v1", Provider: "GOOGLE_WORKSPACE", Name: "Google Workspace mailbox exfiltration", - Description: "Mail forwarding, mailbox delegation, send-as, and legacy IMAP/SMTP auth paths attackers use to siphon Gmail.", + Description: "Mail forwarding, mailbox delegation, and legacy IMAP/SMTP auth paths attackers use to siphon Gmail.", Version: "1.0.0", }, { From ee97c2879cc6b7439289ac49fbd598f43376e6fa Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 01:23:56 -0700 Subject: [PATCH 06/15] Update internal/ingestionworker/rules_catalog.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/rules_catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/rules_catalog.go b/internal/ingestionworker/rules_catalog.go index 1aab8581..fd3b4c7c 100644 --- a/internal/ingestionworker/rules_catalog.go +++ b/internal/ingestionworker/rules_catalog.go @@ -169,7 +169,7 @@ var RuleCatalog = []RuleCatalogEntry{ Severity: "HIGH", EventTypes: []string{"ADMIN_EXTERNAL_RECOVERY_EMAIL"}, PackID: "aperio.google_workspace.identity.v1", - MitreTechniques: []string{"T1556.003"}, + MitreTechniques: []string{"T1098.001"}, Intent: "Adversary stages an off-tenant recovery path so a future password reset hands them the admin account.", Tags: []string{TagAuthAccountRecovery}, }, From a0de6fcb16db9c28fc3ff7407c5cbee2900eb72d Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 01:24:05 -0700 Subject: [PATCH 07/15] Update internal/ingestionworker/rules_catalog.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/rules_catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/rules_catalog.go b/internal/ingestionworker/rules_catalog.go index fd3b4c7c..bddfd437 100644 --- a/internal/ingestionworker/rules_catalog.go +++ b/internal/ingestionworker/rules_catalog.go @@ -147,7 +147,7 @@ var RuleCatalog = []RuleCatalogEntry{ PackID: "aperio.google_workspace.drive.v1", MitreTechniques: []string{"T1550.001", "T1528"}, Intent: "Adversary tricks a user into authorizing an OAuth app that grants long-lived access to mail and drive data.", - Tags: []string{TagOAuthRiskyGrant}, + Tags: []string{TagOAuthRiskyGrant, TagDataAccess}, }, { ID: "google_workspace.admin_mfa_not_enforced", From 60e6cc492aaa63e7c43b17aedcc555a6fa86445a Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 01:42:15 -0700 Subject: [PATCH 08/15] Update internal/ingestionworker/detection_packs_test.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/detection_packs_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/ingestionworker/detection_packs_test.go b/internal/ingestionworker/detection_packs_test.go index 1a277207..57cdf2e5 100644 --- a/internal/ingestionworker/detection_packs_test.go +++ b/internal/ingestionworker/detection_packs_test.go @@ -132,4 +132,3 @@ func TestRulesInPackPreservesCatalogOrder(t *testing.T) { } } - From 05c7a689bb81112de32160cadd05889a3b2f84ce Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 01:42:26 -0700 Subject: [PATCH 09/15] Update internal/ingestionworker/rules_catalog.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/rules_catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/rules_catalog.go b/internal/ingestionworker/rules_catalog.go index bddfd437..6f426538 100644 --- a/internal/ingestionworker/rules_catalog.go +++ b/internal/ingestionworker/rules_catalog.go @@ -111,7 +111,7 @@ var RuleCatalog = []RuleCatalogEntry{ PackID: "aperio.google_workspace.drive.v1", MitreTechniques: []string{"T1530"}, Intent: "Adversary or insider expands a Drive resource's audience to exfiltrate it through legitimate-looking sharing links.", - Tags: []string{TagDataExternalShare}, + Tags: []string{TagDataExternalShare, TagPolicyWeakened}, }, { ID: "google_workspace.super_admin_granted", From 55284cbcf7cc976c43921998c2b779fc59d8a819 Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 12:00:30 -0700 Subject: [PATCH 10/15] Update internal/ingestionworker/rules_catalog.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/rules_catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/rules_catalog.go b/internal/ingestionworker/rules_catalog.go index 6f426538..98e1342c 100644 --- a/internal/ingestionworker/rules_catalog.go +++ b/internal/ingestionworker/rules_catalog.go @@ -37,7 +37,7 @@ var RuleCatalog = []RuleCatalogEntry{ Severity: "CRITICAL", EventTypes: []string{"PUBLIC_REPOSITORY_CREATED", "REPOSITORY_PUBLICIZED"}, PackID: "aperio.github.core.v1", - MitreTechniques: []string{"T1213"}, + MitreTechniques: []string{"T1567.001"}, Intent: "Adversary publishes a private repo to exfiltrate source, secrets, or customer data outside the tenant boundary.", Tags: []string{TagDataPublicExposure}, }, From e8b722ef2de8066bd242ab512a4118fc337870d0 Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 12:00:39 -0700 Subject: [PATCH 11/15] Update internal/ingestionworker/rules_catalog.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/rules_catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/rules_catalog.go b/internal/ingestionworker/rules_catalog.go index 98e1342c..a4b80fb5 100644 --- a/internal/ingestionworker/rules_catalog.go +++ b/internal/ingestionworker/rules_catalog.go @@ -183,7 +183,7 @@ var RuleCatalog = []RuleCatalogEntry{ PackID: "aperio.google_workspace.mail.v1", MitreTechniques: []string{"T1114.003"}, Intent: "Adversary auto-forwards mailbox contents to an attacker-controlled address to silently exfiltrate mail.", - Tags: []string{TagEmailForwarding}, + Tags: []string{TagEmailForwarding, TagDataExternalShare}, }, { ID: "google_workspace.mailbox_delegation_granted", From e7ce6a8f6efec9f63e66c303bb53b737bcdb45a0 Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 12:00:49 -0700 Subject: [PATCH 12/15] Update internal/ingestionworker/rules_catalog.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/rules_catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/rules_catalog.go b/internal/ingestionworker/rules_catalog.go index a4b80fb5..f0bc25cc 100644 --- a/internal/ingestionworker/rules_catalog.go +++ b/internal/ingestionworker/rules_catalog.go @@ -195,7 +195,7 @@ var RuleCatalog = []RuleCatalogEntry{ PackID: "aperio.google_workspace.mail.v1", MitreTechniques: []string{"T1098.002"}, Intent: "Adversary persists access to the mailbox by delegating it to an attacker-controlled account.", - Tags: []string{TagEmailDelegation}, + Tags: []string{TagEmailDelegation, TagDataAccess}, }, { ID: "google_workspace.legacy_mail_auth_used", From 3cf1f2f999e0809c8005d6bc28bd29a3c61f9ba3 Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 12:00:57 -0700 Subject: [PATCH 13/15] Update internal/ingestionworker/rules_catalog.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/rules_catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ingestionworker/rules_catalog.go b/internal/ingestionworker/rules_catalog.go index f0bc25cc..38a580b6 100644 --- a/internal/ingestionworker/rules_catalog.go +++ b/internal/ingestionworker/rules_catalog.go @@ -219,7 +219,7 @@ var RuleCatalog = []RuleCatalogEntry{ PackID: "aperio.google_workspace.mail.v1", MitreTechniques: []string{"T1114.003", "T1098.002"}, Intent: "Adversary stages a multi-vector mailbox takeover that survives password rotation and silently routes mail outbound.", - Tags: []string{TagEmailForwarding, TagEmailDelegation}, + Tags: []string{TagEmailForwarding, TagEmailDelegation, TagDataExternalShare}, }, } From cf1a4efa9bcdf476e65405d29f03a2744c0b0270 Mon Sep 17 00:00:00 2001 From: dcoln25-writer Date: Wed, 17 Jun 2026 12:01:12 -0700 Subject: [PATCH 14/15] Update internal/ingestionworker/detection_packs.go Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- internal/ingestionworker/detection_packs.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/ingestionworker/detection_packs.go b/internal/ingestionworker/detection_packs.go index 2e5e8669..d12509f5 100644 --- a/internal/ingestionworker/detection_packs.go +++ b/internal/ingestionworker/detection_packs.go @@ -68,8 +68,7 @@ var DetectionPacks = []DetectionPack{ } // DetectionPackByID returns the pack with the given ID, or false if no -// pack matches. The API uses this to validate referenced pack IDs and -// to hydrate the rules under each pack for the operator UI. +// pack matches. func DetectionPackByID(id string) (DetectionPack, bool) { for _, pack := range DetectionPacks { if pack.ID == id { From 952868c0bf9a2b7ac1618fc33affd361e0608609 Mon Sep 17 00:00:00 2001 From: Jonathan Haas Date: Wed, 17 Jun 2026 15:46:57 -0700 Subject: [PATCH 15/15] test: gofmt detection pack tests --- internal/ingestionworker/detection_packs_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/ingestionworker/detection_packs_test.go b/internal/ingestionworker/detection_packs_test.go index 57cdf2e5..9ee71455 100644 --- a/internal/ingestionworker/detection_packs_test.go +++ b/internal/ingestionworker/detection_packs_test.go @@ -131,4 +131,3 @@ func TestRulesInPackPreservesCatalogOrder(t *testing.T) { } } } -