From 96465f23df7254e015de1df957f1c468322963c1 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 1 Sep 2022 18:54:01 -0700 Subject: [PATCH] adding test framework/recordings for client. Adding generic upsert fuction for models. --- backend/pkg/database/interface.go | 5 +- backend/pkg/database/sqlite_repository.go | 53 +- .../internal/fhir/base/dependency_graph.go | 28 + .../hub/internal/fhir/base/fhir401_client.go | 293 +++-- .../internal/fhir/base/fhir401_client_test.go | 115 +- .../pkg/hub/internal/fhir/base/interface.go | 4 + .../hub/internal/fhir/base/test_helpers.go | 51 + .../401-R4/encounter/cigna_encounter.json | 80 ++ .../401-R4/encounter/synthea_encounter.json | 41 + backend/pkg/hub/internal/fhir/cigna/client.go | 51 +- .../hub/internal/fhir/cigna/client_test.go | 47 + .../TestCignaClient_SyncAll.cassette | 1101 +++++++++++++++++ backend/pkg/models/medical_encounter.go | 4 +- go.mod | 5 +- 14 files changed, 1673 insertions(+), 205 deletions(-) create mode 100644 backend/pkg/hub/internal/fhir/base/dependency_graph.go create mode 100644 backend/pkg/hub/internal/fhir/base/test_helpers.go create mode 100644 backend/pkg/hub/internal/fhir/base/testdata/fixtures/401-R4/encounter/cigna_encounter.json create mode 100644 backend/pkg/hub/internal/fhir/base/testdata/fixtures/401-R4/encounter/synthea_encounter.json create mode 100644 backend/pkg/hub/internal/fhir/cigna/client_test.go create mode 100644 backend/pkg/hub/internal/fhir/cigna/testdata/govcr-fixtures/TestCignaClient_SyncAll.cassette diff --git a/backend/pkg/database/interface.go b/backend/pkg/database/interface.go index a6884c70..c04c45c0 100644 --- a/backend/pkg/database/interface.go +++ b/backend/pkg/database/interface.go @@ -10,8 +10,9 @@ type DatabaseRepository interface { Close() error GetCurrentUser() models.User - UpsertProfile(context.Context, *models.Profile) error - UpsertOrganziation(context.Context, *models.Organization) error + UpsertResource(context.Context, interface{}) error + //UpsertProfile(context.Context, *models.Profile) error + //UpsertOrganziation(context.Context, *models.Organization) error CreateSource(context.Context, *models.Source) error GetSources(context.Context) ([]models.Source, error) diff --git a/backend/pkg/database/sqlite_repository.go b/backend/pkg/database/sqlite_repository.go index 2bec89cd..cae9e28f 100644 --- a/backend/pkg/database/sqlite_repository.go +++ b/backend/pkg/database/sqlite_repository.go @@ -48,6 +48,7 @@ func NewRepository(appConfig config.Interface, globalLogger logrus.FieldLogger) &models.Source{}, &models.Profile{}, &models.Organization{}, + &models.Encounter{}, ) if err != nil { return nil, fmt.Errorf("Failed to automigrate! - %v", err) @@ -86,16 +87,48 @@ func (sr *sqliteRepository) GetCurrentUser() models.User { return currentUser } -// UpsertSourceResource Create or Update record in database -func (sr *sqliteRepository) UpsertProfile(ctx context.Context, profile *models.Profile) error { - if sr.gormClient.Debug().WithContext(ctx).Model(profile). - Where(models.OriginBase{ - SourceID: profile.GetSourceID(), - SourceResourceID: profile.GetSourceResourceID(), - SourceResourceType: profile.GetSourceResourceType(), //TODO: and UpdatedAt > old UpdatedAt - }).Updates(profile).RowsAffected == 0 { - sr.logger.Infof("profile does not exist, creating: %s %s %s", profile.GetSourceID(), profile.GetSourceResourceID(), profile.GetSourceResourceType()) - return sr.gormClient.Debug().Create(profile).Error +func (sr *sqliteRepository) UpsertResource(ctx context.Context, resourceModel interface{}) error { + sr.logger.Infof("insert/update (%T) %v", resourceModel, resourceModel) + + switch (resourceModel).(type) { + case models.Encounter: + var apiEncounter models.Encounter + apiEncounter = resourceModel.(models.Encounter) + if sr.gormClient.Debug().WithContext(ctx).Model(&apiEncounter). + Where(models.OriginBase{ + SourceID: apiEncounter.GetSourceID(), + SourceResourceID: apiEncounter.GetSourceResourceID(), + SourceResourceType: apiEncounter.GetSourceResourceType(), //TODO: and UpdatedAt > old UpdatedAt + }).Updates(&apiEncounter).RowsAffected == 0 { + sr.logger.Infof("organization does not exist, creating: %s %s %s", apiEncounter.GetSourceID(), apiEncounter.GetSourceResourceID(), apiEncounter.GetSourceResourceType()) + return sr.gormClient.Debug().Model(&apiEncounter).Create(&apiEncounter).Error + } + case models.Organization: + var apiOrganization models.Organization + apiOrganization = (resourceModel).(models.Organization) + if sr.gormClient.Debug().WithContext(ctx).Model(&apiOrganization). + Where(models.OriginBase{ + SourceID: apiOrganization.GetSourceID(), + SourceResourceID: apiOrganization.GetSourceResourceID(), + SourceResourceType: apiOrganization.GetSourceResourceType(), //TODO: and UpdatedAt > old UpdatedAt + }).Updates(&apiOrganization).RowsAffected == 0 { + sr.logger.Infof("organization does not exist, creating: %s %s %s", apiOrganization.GetSourceID(), apiOrganization.GetSourceResourceID(), apiOrganization.GetSourceResourceType()) + return sr.gormClient.Debug().Model(&apiOrganization).Create(&apiOrganization).Error + } + case models.Profile: + var apiProfile models.Profile + apiProfile = (resourceModel).(models.Profile) + if sr.gormClient.Debug().WithContext(ctx).Model(&apiProfile). + Where(models.OriginBase{ + SourceID: apiProfile.GetSourceID(), + SourceResourceID: apiProfile.GetSourceResourceID(), + SourceResourceType: apiProfile.GetSourceResourceType(), //TODO: and UpdatedAt > old UpdatedAt + }).Updates(&apiProfile).RowsAffected == 0 { + sr.logger.Infof("profile does not exist, creating: %s %s %s", apiProfile.GetSourceID(), apiProfile.GetSourceResourceID(), apiProfile.GetSourceResourceType()) + return sr.gormClient.Debug().Model(&apiProfile).Create(&apiProfile).Error + } + default: + return fmt.Errorf("unknown model (%T) %v", resourceModel, resourceModel) } return nil } diff --git a/backend/pkg/hub/internal/fhir/base/dependency_graph.go b/backend/pkg/hub/internal/fhir/base/dependency_graph.go new file mode 100644 index 00000000..79ab7d6f --- /dev/null +++ b/backend/pkg/hub/internal/fhir/base/dependency_graph.go @@ -0,0 +1,28 @@ +package base + +import "github.com/samber/lo" + +//based on algorithm - https://stackoverflow.com/a/5288547 +type DependencyGraph map[string][]string + +func (d DependencyGraph) AddDependencies(resourceRef string, dependencyResourceRefs []string) { + //check to see if the resourceRef already has an entry in the graph, if not, add it + + if _, dependencyListExists := d[resourceRef]; !dependencyListExists { + //the dependency list doesnt exist yet for this ref + d[resourceRef] = []string{} + } + + for _, dependencyResourceRef := range dependencyResourceRefs { + dependencyList, dependencyListExists := d[dependencyResourceRef] + if !dependencyListExists { + //the dependency list doesnt exist yet for this ref + dependencyList = []string{} + } + + //add the current item to the list, then make sure the list is unique. + dependencyList = append(dependencyList, resourceRef) + uniqDependencyList := lo.Uniq[string](dependencyList) + d[dependencyResourceRef] = uniqDependencyList + } +} diff --git a/backend/pkg/hub/internal/fhir/base/fhir401_client.go b/backend/pkg/hub/internal/fhir/base/fhir401_client.go index cc42bea1..384cfe7c 100644 --- a/backend/pkg/hub/internal/fhir/base/fhir401_client.go +++ b/backend/pkg/hub/internal/fhir/base/fhir401_client.go @@ -5,6 +5,7 @@ import ( "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models" "github.com/fastenhealth/gofhir-models/fhir401" + fhirutils "github.com/fastenhealth/gofhir-models/fhir401/utils" "github.com/sirupsen/logrus" "net/http" "time" @@ -23,122 +24,212 @@ func NewFHIR401Client(appConfig config.Interface, globalLogger logrus.FieldLogge //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // FHIR //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -func (c *FHIR401Client) GetPatientEverything(patientId string) (*fhir401.Bundle, error) { +func (c *FHIR401Client) GetPatientBundle(patientId string) (fhir401.Bundle, error) { // https://www.hl7.org/fhir/patient-operation-everything.html bundle := fhir401.Bundle{} err := c.GetRequest(fmt.Sprintf("Patient/%s/$everything", patientId), &bundle) - return &bundle, err + return bundle, err } -func (c *FHIR401Client) GetPatient(patientId string) (*fhir401.Patient, error) { +func (c *FHIR401Client) GetPatient(patientId string) (fhir401.Patient, error) { patient := fhir401.Patient{} err := c.GetRequest(fmt.Sprintf("Patient/%s", patientId), &patient) - return &patient, err + return patient, err +} + +// GenerateResourceDependencyGraph +// FHIR resources can reference/depend on other resources. +// When storing processed models in the database, we need to make sure that we insert them in dependency order, +// so that we can correctly update all references +func (c *FHIR401Client) GenerateResourceDependencyGraph() { + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Process Bundles +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +func (c *FHIR401Client) ProcessBundle(bundle fhir401.Bundle) (DependencyGraph, map[string]interface{}, []string, error) { + // this lookup dict maps resource references to API models + resourceRefApiModelLookup := map[string]interface{}{} + + // this map contains resource references, and a list of other resources that depend on it. + resourceRefDependencyGraph := DependencyGraph{} + + //list of all resources + allResources := []interface{}{} + + skippedResources := []string{} + for _, bundleEntry := range bundle.Entry { + resource, _ := fhirutils.MapToResource(bundleEntry.Resource, false) + allResources = append(allResources, resource) + + switch resource.(type) { + case fhir401.Patient: + typedResource := resource.(fhir401.Patient) + apiProfile, err := c.ProcessPatient(typedResource) + if err != nil { + return nil, nil, nil, err + } + resourceType, resourceId := typedResource.ResourceRef() + resourceRef := fmt.Sprintf("%s/%s", resourceType, *resourceId) + resourceRefApiModelLookup[resourceRef] = apiProfile + resourceRefDependencyGraph.AddDependencies(resourceRef, []string{}) + case fhir401.Organization: + typedResource := resource.(fhir401.Organization) + apiOrganization, err := c.ProcessOrganization(typedResource) + if err != nil { + return nil, nil, nil, err + } + resourceType, resourceId := typedResource.ResourceRef() + resourceRef := fmt.Sprintf("%s/%s", resourceType, *resourceId) + resourceRefApiModelLookup[resourceRef] = apiOrganization + resourceRefDependencyGraph.AddDependencies(resourceRef, []string{}) + case fhir401.Encounter: + typedResource := resource.(fhir401.Encounter) + apiEncounter, err := c.ProcessEncounter(typedResource) + if err != nil { + return nil, nil, nil, err + } + resourceType, resourceId := typedResource.ResourceRef() + resourceRef := fmt.Sprintf("%s/%s", resourceType, *resourceId) + resourceRefApiModelLookup[resourceRef] = apiEncounter + resourceRefDependencyGraph.AddDependencies(resourceRef, []string{}) + default: + typedResource := resource.(ResourceInterface) + resourceType, resourceId := typedResource.ResourceRef() + var resourceRef string + if resourceId != nil { + resourceRef = fmt.Sprintf("%s/%s", resourceType, *resourceId) + } else { + resourceRef = resourceType + } + skippedResources = append(skippedResources, resourceRef) + } + } + return resourceRefDependencyGraph, resourceRefApiModelLookup, skippedResources, nil } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Process & Generate API/Database Models //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -func (c *FHIR401Client) ProcessPatients(patients []fhir401.Patient) ([]models.Profile, error) { - profiles := []models.Profile{} - for _, item := range patients { - c.Logger.Debugf("item %v", item) - patientProfile := models.Profile{ - OriginBase: models.OriginBase{ - ModelBase: models.ModelBase{}, - UserID: c.Source.UserID, - SourceID: c.Source.ID, - SourceResourceID: *item.Id, - SourceResourceType: fhir401.ResourceTypePatient.Code(), - }, - Demographics: models.Demographics{ - Address: models.Address{}, - Name: models.Name{}, - }, - } - - if item.Meta != nil && item.Meta.LastUpdated != nil { - if parsed, err := time.Parse(time.RFC3339Nano, *item.Meta.LastUpdated); err == nil { - patientProfile.UpdatedAt = parsed - } - } - - if item.Address != nil && len(item.Address) > 0 { - itemAddress := item.Address[0] - patientProfile.Demographics.Address.City = itemAddress.City - patientProfile.Demographics.Address.Country = itemAddress.Country - patientProfile.Demographics.Address.State = itemAddress.State - patientProfile.Demographics.Address.Street = itemAddress.Line - patientProfile.Demographics.Address.Zip = itemAddress.PostalCode - - } - patientProfile.Demographics.Dob = item.BirthDate - - if item.Gender != nil { - itemGenderStr := item.Gender.String() - itemGenderCode := item.Gender.Code() - patientProfile.Demographics.Gender = &itemGenderStr - patientProfile.Demographics.GenderCodes = &itemGenderCode - } - patientProfile.Demographics.Language = item.Language - - if item.MaritalStatus != nil { - patientProfile.Demographics.MaritalStatus = item.MaritalStatus.Text - if len(item.MaritalStatus.Coding) > 0 { - patientProfile.Demographics.MaritalStatusCodes = item.MaritalStatus.Coding[0].Code - } - } - if item.Name != nil && len(item.Name) > 0 { - itemName := item.Name[0] - if itemName.Prefix != nil && len(itemName.Prefix) > 0 { - itemNamePrefix := itemName.Prefix[0] - patientProfile.Demographics.Name.Prefix = &itemNamePrefix - } - patientProfile.Demographics.Name.Given = itemName.Given - patientProfile.Demographics.Name.Family = itemName.Family - - } - profiles = append(profiles, patientProfile) - } - - return profiles, nil -} - -func (c *FHIR401Client) ProcessOrganizations(orgs []fhir401.Organization) ([]models.Organization, error) { - apiOrganizations := []models.Organization{} - for _, org := range orgs { - apiOrganization := models.Organization{ - OriginBase: models.OriginBase{ - ModelBase: models.ModelBase{}, - UserID: c.Source.UserID, - SourceID: c.Source.ID, - SourceResourceID: *org.Id, - SourceResourceType: fhir401.ResourceTypeOrganization.Code(), - }, +func (c *FHIR401Client) ProcessPatient(item fhir401.Patient) (models.Profile, error) { + c.Logger.Debugf("item %v", item) + patientProfile := models.Profile{ + OriginBase: models.OriginBase{ + ModelBase: models.ModelBase{}, + UserID: c.Source.UserID, + SourceID: c.Source.ID, + SourceResourceID: *item.Id, + SourceResourceType: fhir401.ResourceTypePatient.Code(), + }, + Demographics: models.Demographics{ Address: models.Address{}, - } - - if org.Meta != nil && org.Meta.LastUpdated != nil { - if parsed, err := time.Parse(time.RFC3339, *org.Meta.LastUpdated); err == nil { - apiOrganization.UpdatedAt = parsed - } - } - - if org.Address != nil && len(org.Address) > 0 { - itemAddress := org.Address[0] - apiOrganization.Address.City = itemAddress.City - apiOrganization.Address.Country = itemAddress.Country - apiOrganization.Address.State = itemAddress.State - apiOrganization.Address.Street = itemAddress.Line - apiOrganization.Address.Zip = itemAddress.PostalCode - } - apiOrganization.Name = org.Name - apiOrganization.Active = org.Active - - apiOrganizations = append(apiOrganizations, apiOrganization) + Name: models.Name{}, + }, } - return apiOrganizations, nil + + if item.Meta != nil && item.Meta.LastUpdated != nil { + if parsed, err := time.Parse(time.RFC3339Nano, *item.Meta.LastUpdated); err == nil { + patientProfile.UpdatedAt = parsed + } + } + + if item.Address != nil && len(item.Address) > 0 { + itemAddress := item.Address[0] + patientProfile.Demographics.Address.City = itemAddress.City + patientProfile.Demographics.Address.Country = itemAddress.Country + patientProfile.Demographics.Address.State = itemAddress.State + patientProfile.Demographics.Address.Street = itemAddress.Line + patientProfile.Demographics.Address.Zip = itemAddress.PostalCode + + } + patientProfile.Demographics.Dob = item.BirthDate + + if item.Gender != nil { + itemGenderStr := item.Gender.String() + itemGenderCode := item.Gender.Code() + patientProfile.Demographics.Gender = &itemGenderStr + patientProfile.Demographics.GenderCodes = &itemGenderCode + } + patientProfile.Demographics.Language = item.Language + + if item.MaritalStatus != nil { + patientProfile.Demographics.MaritalStatus = item.MaritalStatus.Text + if len(item.MaritalStatus.Coding) > 0 { + patientProfile.Demographics.MaritalStatusCodes = item.MaritalStatus.Coding[0].Code + } + } + if item.Name != nil && len(item.Name) > 0 { + itemName := item.Name[0] + if itemName.Prefix != nil && len(itemName.Prefix) > 0 { + itemNamePrefix := itemName.Prefix[0] + patientProfile.Demographics.Name.Prefix = &itemNamePrefix + } + patientProfile.Demographics.Name.Given = itemName.Given + patientProfile.Demographics.Name.Family = itemName.Family + + } + + return patientProfile, nil +} + +func (c *FHIR401Client) ProcessOrganization(item fhir401.Organization) (models.Organization, error) { + apiOrganization := models.Organization{ + OriginBase: models.OriginBase{ + ModelBase: models.ModelBase{}, + UserID: c.Source.UserID, + SourceID: c.Source.ID, + SourceResourceID: *item.Id, + SourceResourceType: fhir401.ResourceTypeOrganization.Code(), + }, + Address: models.Address{}, + } + + if item.Meta != nil && item.Meta.LastUpdated != nil { + if parsed, err := time.Parse(time.RFC3339, *item.Meta.LastUpdated); err == nil { + apiOrganization.UpdatedAt = parsed + } + } + + if item.Address != nil && len(item.Address) > 0 { + itemAddress := item.Address[0] + apiOrganization.Address.City = itemAddress.City + apiOrganization.Address.Country = itemAddress.Country + apiOrganization.Address.State = itemAddress.State + apiOrganization.Address.Street = itemAddress.Line + apiOrganization.Address.Zip = itemAddress.PostalCode + } + apiOrganization.Name = item.Name + apiOrganization.Active = item.Active + + return apiOrganization, nil +} + +//TODO +func (c *FHIR401Client) ProcessEncounter(item fhir401.Encounter) (models.Encounter, error) { + apiEncounter := models.Encounter{ + OriginBase: models.OriginBase{ + ModelBase: models.ModelBase{}, + UserID: c.Source.UserID, + SourceID: c.Source.ID, + SourceResourceID: *item.Id, + SourceResourceType: fhir401.ResourceTypeEncounter.Code(), + }, + Provider: models.Provider{}, + Orders: []models.Order{}, + } + + if item.Meta != nil && item.Meta.LastUpdated != nil { + if parsed, err := time.Parse(time.RFC3339, *item.Meta.LastUpdated); err == nil { + apiEncounter.UpdatedAt = parsed + } + } + if item.Type != nil && len(item.Type) > 0 && item.Type[0].Coding != nil && len(item.Type[0].Coding) > 0 { + apiEncounter.VisitType = item.Type[0].Coding[0].Code + } + + return apiEncounter, nil } diff --git a/backend/pkg/hub/internal/fhir/base/fhir401_client_test.go b/backend/pkg/hub/internal/fhir/base/fhir401_client_test.go index 0d27f63a..253ebea6 100644 --- a/backend/pkg/hub/internal/fhir/base/fhir401_client_test.go +++ b/backend/pkg/hub/internal/fhir/base/fhir401_client_test.go @@ -9,6 +9,7 @@ import ( "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "io/ioutil" + "log" "os" "testing" "time" @@ -47,7 +48,39 @@ func TestNewFHIR401Client(t *testing.T) { require.Equal(t, client.Source.RefreshToken, "test-refresh-token") } -func TestFHIR401Client_ProcessPatients_Cigna_Empty(t *testing.T) { +func TestFHIR401Client_ProcessBundle(t *testing.T) { + t.Parallel() + //setup + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + fakeConfig := mock_config.NewMockInterface(mockCtrl) + testLogger := logrus.WithFields(logrus.Fields{ + "type": "test", + }) + client, err := NewFHIR401Client(fakeConfig, testLogger, models.Source{ + RefreshToken: "test-refresh-token", + AccessToken: "test-access-token", + }) + require.NoError(t, err) + + jsonBytes, err := readTestFixture("testdata/fixtures/401-R4/bundle/cigna_syntheticuser05-everything.json") + require.NoError(t, err) + var bundle fhir401.Bundle + err = json.Unmarshal(jsonBytes, &bundle) + require.NoError(t, err) + + // test + dependencyGraph, resoureceApiMap, skipped, err := client.ProcessBundle(bundle) + log.Printf("%v", dependencyGraph) + log.Printf("%v", resoureceApiMap) + //assert + require.NoError(t, err) + require.Equal(t, 8, len(skipped)) + require.Equal(t, 4, len(resoureceApiMap)) + //require.Equal(t, "A00000000000005", profile.SourceResourceID) +} + +func TestFHIR401Client_ProcessPatient_Cigna_Empty(t *testing.T) { t.Parallel() //setup mockCtrl := gomock.NewController(t) @@ -69,16 +102,15 @@ func TestFHIR401Client_ProcessPatients_Cigna_Empty(t *testing.T) { require.NoError(t, err) // test - profiles, err := client.ProcessPatients([]fhir401.Patient{patient}) + profile, err := client.ProcessPatient(patient) //assert require.NoError(t, err) - require.Equal(t, 1, len(profiles)) - require.Equal(t, "Patient", profiles[0].SourceResourceType) - require.Equal(t, "A00000000000005", profiles[0].SourceResourceID) + require.Equal(t, "Patient", profile.SourceResourceType) + require.Equal(t, "A00000000000005", profile.SourceResourceID) } -func TestFHIR401Client_ProcessPatients_Cigna_Populated(t *testing.T) { +func TestFHIR401Client_ProcessPatient_Cigna_Populated(t *testing.T) { t.Parallel() //setup mockCtrl := gomock.NewController(t) @@ -100,21 +132,20 @@ func TestFHIR401Client_ProcessPatients_Cigna_Populated(t *testing.T) { require.NoError(t, err) // test - profiles, err := client.ProcessPatients([]fhir401.Patient{patient}) + profile, err := client.ProcessPatient(patient) //assert require.NoError(t, err) - require.Equal(t, 1, len(profiles)) - require.Equal(t, "Patient", profiles[0].SourceResourceType) - require.Equal(t, "ifp-A00000000000005", profiles[0].SourceResourceID) - require.Equal(t, "2022-06-20T15:45:22.043Z", profiles[0].UpdatedAt.Format(time.RFC3339Nano)) - require.Equal(t, "2013-01-12", *profiles[0].Demographics.Dob) - require.Equal(t, "female", *profiles[0].Demographics.Gender) - require.Equal(t, "female", *profiles[0].Demographics.GenderCodes) - require.Equal(t, "UNK", *profiles[0].Demographics.MaritalStatusCodes) - require.Equal(t, "unknown", *profiles[0].Demographics.MaritalStatus) - require.Equal(t, "Monahan", *profiles[0].Demographics.Name.Family) - require.Equal(t, []string{"Felecita"}, profiles[0].Demographics.Name.Given) + require.Equal(t, "Patient", profile.SourceResourceType) + require.Equal(t, "ifp-A00000000000005", profile.SourceResourceID) + require.Equal(t, "2022-06-20T15:45:22.043Z", profile.UpdatedAt.Format(time.RFC3339Nano)) + require.Equal(t, "2013-01-12", *profile.Demographics.Dob) + require.Equal(t, "female", *profile.Demographics.Gender) + require.Equal(t, "female", *profile.Demographics.GenderCodes) + require.Equal(t, "UNK", *profile.Demographics.MaritalStatusCodes) + require.Equal(t, "unknown", *profile.Demographics.MaritalStatus) + require.Equal(t, "Monahan", *profile.Demographics.Name.Family) + require.Equal(t, []string{"Felecita"}, profile.Demographics.Name.Given) } func TestFHIR401Client_ProcessPatients_Synthea_Populated(t *testing.T) { @@ -139,22 +170,21 @@ func TestFHIR401Client_ProcessPatients_Synthea_Populated(t *testing.T) { require.NoError(t, err) // test - profiles, err := client.ProcessPatients([]fhir401.Patient{patient}) + profile, err := client.ProcessPatient(patient) //assert require.NoError(t, err) - require.Equal(t, 1, len(profiles)) - require.Equal(t, "Patient", profiles[0].SourceResourceType) - require.Equal(t, "c088b7af-fc41-43cc-ab80-4a9ab8d47cd9", profiles[0].SourceResourceID) - require.Equal(t, "0001-01-01T00:00:00Z", profiles[0].UpdatedAt.Format(time.RFC3339Nano)) - require.Equal(t, "1965-11-04", *profiles[0].Demographics.Dob) - require.Equal(t, "female", *profiles[0].Demographics.Gender) - require.Equal(t, "female", *profiles[0].Demographics.GenderCodes) - require.Equal(t, "S", *profiles[0].Demographics.MaritalStatusCodes) - require.Equal(t, "S", *profiles[0].Demographics.MaritalStatus) - require.Equal(t, "Marks830", *profiles[0].Demographics.Name.Family) - require.Equal(t, []string{"Alesha810"}, profiles[0].Demographics.Name.Given) - require.Equal(t, "Ms.", *profiles[0].Demographics.Name.Prefix) + require.Equal(t, "Patient", profile.SourceResourceType) + require.Equal(t, "c088b7af-fc41-43cc-ab80-4a9ab8d47cd9", profile.SourceResourceID) + require.Equal(t, "0001-01-01T00:00:00Z", profile.UpdatedAt.Format(time.RFC3339Nano)) + require.Equal(t, "1965-11-04", *profile.Demographics.Dob) + require.Equal(t, "female", *profile.Demographics.Gender) + require.Equal(t, "female", *profile.Demographics.GenderCodes) + require.Equal(t, "S", *profile.Demographics.MaritalStatusCodes) + require.Equal(t, "S", *profile.Demographics.MaritalStatus) + require.Equal(t, "Marks830", *profile.Demographics.Name.Family) + require.Equal(t, []string{"Alesha810"}, profile.Demographics.Name.Given) + require.Equal(t, "Ms.", *profile.Demographics.Name.Prefix) } func TestFHIR401Client_ProcessOrganizations_Cigna(t *testing.T) { @@ -179,19 +209,18 @@ func TestFHIR401Client_ProcessOrganizations_Cigna(t *testing.T) { require.NoError(t, err) // test - orgs, err := client.ProcessOrganizations([]fhir401.Organization{org}) + apiOrg, err := client.ProcessOrganization(org) //assert require.NoError(t, err) - require.Equal(t, 1, len(orgs)) - require.Equal(t, "Organization", orgs[0].SourceResourceType) - require.Equal(t, "ifp-51fb06f37e5ec973ce69132a9a2571f3", orgs[0].SourceResourceID) - require.Equal(t, "2022-06-20T15:45:45.155Z", orgs[0].UpdatedAt.Format(time.RFC3339Nano)) - require.Equal(t, true, *orgs[0].Active) - require.Equal(t, "SURPRISE", *orgs[0].Address.City) - require.Equal(t, "AZ", *orgs[0].Address.State) - require.Equal(t, []string{"13991 W GRAND AVE STE 105"}, orgs[0].Address.Street) - require.Nil(t, orgs[0].Address.Country) - require.Equal(t, "85374", *orgs[0].Address.Zip) - require.Equal(t, "CIGNA MED GRP PHCY-SUN CITY WE", *orgs[0].Name) + require.Equal(t, "Organization", apiOrg.SourceResourceType) + require.Equal(t, "ifp-51fb06f37e5ec973ce69132a9a2571f3", apiOrg.SourceResourceID) + require.Equal(t, "2022-06-20T15:45:45.155Z", apiOrg.UpdatedAt.Format(time.RFC3339Nano)) + require.Equal(t, true, *apiOrg.Active) + require.Equal(t, "SURPRISE", *apiOrg.Address.City) + require.Equal(t, "AZ", *apiOrg.Address.State) + require.Equal(t, []string{"13991 W GRAND AVE STE 105"}, apiOrg.Address.Street) + require.Nil(t, apiOrg.Address.Country) + require.Equal(t, "85374", *apiOrg.Address.Zip) + require.Equal(t, "CIGNA MED GRP PHCY-SUN CITY WE", *apiOrg.Name) } diff --git a/backend/pkg/hub/internal/fhir/base/interface.go b/backend/pkg/hub/internal/fhir/base/interface.go index ae727794..1274ba9c 100644 --- a/backend/pkg/hub/internal/fhir/base/interface.go +++ b/backend/pkg/hub/internal/fhir/base/interface.go @@ -24,3 +24,7 @@ type Client interface { //Demographics() //SocialHistory() } + +type ResourceInterface interface { + ResourceRef() (string, *string) +} diff --git a/backend/pkg/hub/internal/fhir/base/test_helpers.go b/backend/pkg/hub/internal/fhir/base/test_helpers.go new file mode 100644 index 00000000..3d39514d --- /dev/null +++ b/backend/pkg/hub/internal/fhir/base/test_helpers.go @@ -0,0 +1,51 @@ +package base + +import ( + "context" + "crypto/tls" + "github.com/seborama/govcr" + "golang.org/x/oauth2" + "net/http" + "path" + "testing" +) + +func OAuthVcrSetup(t *testing.T, enableRecording bool) *http.Client { + accessToken := "PLACEHOLDER" + if enableRecording { + //this has to be disabled because CI is empty inside docker containers. + accessToken = "" + } + + ts := oauth2.StaticTokenSource( + //setting a real access token here will allow API calls to connect successfully + &oauth2.Token{AccessToken: accessToken}, + ) + + tr := http.DefaultTransport.(*http.Transport) + tr.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, //disable certificate validation because we're playing back http requests. + } + insecureClient := http.Client{ + Transport: tr, + } + + ctx := context.WithValue(oauth2.NoContext, oauth2.HTTPClient, insecureClient) + tc := oauth2.NewClient(ctx, ts) + + vcrConfig := govcr.VCRConfig{ + Logging: true, + CassettePath: path.Join("testdata", "govcr-fixtures"), + Client: tc, + + //this line ensures that we do not attempt to create new recordings. + //Comment this out if you would like to make recordings. + DisableRecording: !enableRecording, + } + + // HTTP headers are case-insensitive + vcrConfig.RequestFilters.Add(govcr.RequestDeleteHeaderKeys("User-Agent", "user-agent")) + + vcr := govcr.NewVCR(t.Name(), &vcrConfig) + return vcr.Client +} diff --git a/backend/pkg/hub/internal/fhir/base/testdata/fixtures/401-R4/encounter/cigna_encounter.json b/backend/pkg/hub/internal/fhir/base/testdata/fixtures/401-R4/encounter/cigna_encounter.json new file mode 100644 index 00000000..6b313bff --- /dev/null +++ b/backend/pkg/hub/internal/fhir/base/testdata/fixtures/401-R4/encounter/cigna_encounter.json @@ -0,0 +1,80 @@ +{ + "id": "ifp-1C9A46F07B3CADE33EFC75ABA3DC37CF", + "meta": { + "lastUpdated": "2022-06-20T15:45:29.685000+00:00", + "profile": ["http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter"], + "source": "IFP#e7zkeLCSmQFgUX0Z", + "versionId": "1" + }, + "class": { + "extension": [{ + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unknown" + }] + }, + "diagnosis": [{ + "condition": { + "reference": "Condition/ifp-A00000000000005-OP0447575426-K57.80-Y-" + }, + "use": { + "coding": [{ + "display": "Admission diagnosis" + }] + } + }], + "identifier": [{ + "system": "http://dev.cigna.com/system/TRCR", + "value": "TRCR-OP0447575426-1" + }], + "location": [{ + "location": { + "reference": "Location/ifp-7312532" + } + }, { + "location": { + "reference": "Location/ifp-0566265" + } + }], + "participant": [{ + "individual": { + "reference": "Practitioner/ifp-50ef4542ecb5ae5eddc0dac76a10aaed" + } + }, { + "individual": { + "reference": "Practitioner/ifp-6a4d3d6fe165b6a0a79b6a976d043c2c" + } + }], + "period": { + "end": "2019-12-31", + "start": "2019-11-07" + }, + "reasonCode": [{ + "coding": [{ + "code": "K57.80", + "display": "Dvtrcli of intest, part unsp, w perf and abscess w/o bleed" + }] + }], + "reasonReference": [{ + "reference": "Condition/ifp-A00000000000005-OP0447575426-K57.80-Y-" + }], + "serviceProvider": { + "reference": "Organization/ifp-0566265" + }, + "serviceType": { + "coding": [{ + "code": "302", + "display": "Medical Outpatient" + }] + }, + "status": "unknown", + "subject": { + "reference": "Patient/ifp-A00000000000005" + }, + "type": [{ + "extension": [{ + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unknown" + }] + }], + "resourceType": "Encounter" +} diff --git a/backend/pkg/hub/internal/fhir/base/testdata/fixtures/401-R4/encounter/synthea_encounter.json b/backend/pkg/hub/internal/fhir/base/testdata/fixtures/401-R4/encounter/synthea_encounter.json new file mode 100644 index 00000000..055332c7 --- /dev/null +++ b/backend/pkg/hub/internal/fhir/base/testdata/fixtures/401-R4/encounter/synthea_encounter.json @@ -0,0 +1,41 @@ +{ + "resourceType": "Encounter", + "id": "3476a881-bb6b-4670-b0d9-aa3eb12be267", + "status": "finished", + "class": { + "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", + "code": "AMB" + }, + "type": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "162673000", + "display": "General examination of patient (procedure)" + } + ], + "text": "General examination of patient (procedure)" + } + ], + "subject": { + "reference": "urn:uuid:d7714835-c7e2-408f-9652-c8c2bdd9d2bf", + "display": "Mr. Blair400 Grady603" + }, + "participant": [ + { + "individual": { + "reference": "urn:uuid:0000016d-3a85-4cca-0000-0000000016d0", + "display": "Dr. María Soledad68 Marrero674" + } + } + ], + "period": { + "start": "2011-08-10T08:19:16-04:00", + "end": "2011-08-10T08:34:16-04:00" + }, + "serviceProvider": { + "reference": "urn:uuid:a0123c36-2436-3609-a5eb-3c3857ed711d", + "display": "PCP8367" + } +} diff --git a/backend/pkg/hub/internal/fhir/cigna/client.go b/backend/pkg/hub/internal/fhir/cigna/client.go index 89dd6718..0544d635 100644 --- a/backend/pkg/hub/internal/fhir/cigna/client.go +++ b/backend/pkg/hub/internal/fhir/cigna/client.go @@ -2,14 +2,10 @@ package cigna import ( "context" - "fmt" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/database" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models" - "github.com/fastenhealth/gofhir-models/fhir401" - fhirutils "github.com/fastenhealth/gofhir-models/fhir401/utils" - "github.com/google/uuid" "github.com/sirupsen/logrus" "net/http" ) @@ -27,57 +23,20 @@ func NewClient(appConfig config.Interface, globalLogger logrus.FieldLogger, sour func (c CignaClient) SyncAll(db database.DatabaseRepository) error { - bundle, err := c.GetPatientEverything(c.Source.PatientId) + bundle, err := c.GetPatientBundle(c.Source.PatientId) if err != nil { return err } - resources := []interface{}{} - for _, bundleEntry := range bundle.Entry { - resource, _ := fhirutils.MapToResource(bundleEntry.Resource, false) - resources = append(resources, resource) - } + _, resourceRefApiModelLookup, _, err := c.ProcessBundle(bundle) - resourceRefLookup := map[string]uuid.UUID{} + //todo, create the resources in dependency order - ////////////////////////////////////////////////////////////////////// - // Patient - ////////////////////////////////////////////////////////////////////// - patientResources := []fhir401.Patient{} - for _, resource := range resources { - if patient, isPatient := resource.(fhir401.Patient); isPatient { - patientResources = append(patientResources, patient) - } - } - apiProfiles, err := c.ProcessPatients(patientResources) - for _, profile := range apiProfiles { - err = db.UpsertProfile(context.Background(), &profile) + for _, apiModel := range resourceRefApiModelLookup { + err = db.UpsertResource(context.Background(), apiModel) if err != nil { return err } - //add upserted resource uuids to lookup - resourceRefLookup[fmt.Sprintf("%s/%s", profile.SourceResourceType, profile.SourceResourceID)] = profile.ID } - - ////////////////////////////////////////////////////////////////////// - // Organization - ////////////////////////////////////////////////////////////////////// - - organizations := []fhir401.Organization{} - for _, resource := range resources { - if org, isOrganization := resource.(fhir401.Organization); isOrganization { - organizations = append(organizations, org) - } - } - apiOrgs, err := c.ProcessOrganizations(organizations) - for _, apiOrg := range apiOrgs { - err = db.UpsertOrganziation(context.Background(), &apiOrg) - if err != nil { - return err - } - //add upserted resource uuids to lookup - resourceRefLookup[fmt.Sprintf("%s/%s", apiOrg.SourceResourceType, apiOrg.SourceResourceID)] = apiOrg.ID - } - return nil } diff --git a/backend/pkg/hub/internal/fhir/cigna/client_test.go b/backend/pkg/hub/internal/fhir/cigna/client_test.go new file mode 100644 index 00000000..61688ddd --- /dev/null +++ b/backend/pkg/hub/internal/fhir/cigna/client_test.go @@ -0,0 +1,47 @@ +package cigna + +import ( + mock_config "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config/mock" + "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/database" + "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base" + "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models" + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "io/ioutil" + "os" + "testing" +) + +func TestCignaClient_SyncAll(t *testing.T) { + t.Parallel() + //setup + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + fakeConfig := mock_config.NewMockInterface(mockCtrl) + + testDatabase, err := ioutil.TempFile("testdata", "fasten.db") + require.NoError(t, err) + defer os.Remove(testDatabase.Name()) + fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(testDatabase.Name()) + testLogger := logrus.WithFields(logrus.Fields{ + "type": "test", + }) + httpClient := base.OAuthVcrSetup(t, false) + client, err := NewClient(fakeConfig, testLogger, models.Source{ + ProviderId: "cigna", + PatientId: "A00000000000005", + ApiEndpointBaseUrl: "https://p-hi2.digitaledge.cigna.com/PatientAccess/v1-devportal", + ClientId: "e434426c-2aaf-413a-a39a-8f5f6130f287", + }, httpClient) + + db, err := database.NewRepository(fakeConfig, testLogger) + require.NoError(t, err) + + //test + err = client.SyncAll(db) + require.NoError(t, err) + + //assert + require.NoError(t, err) +} diff --git a/backend/pkg/hub/internal/fhir/cigna/testdata/govcr-fixtures/TestCignaClient_SyncAll.cassette b/backend/pkg/hub/internal/fhir/cigna/testdata/govcr-fixtures/TestCignaClient_SyncAll.cassette new file mode 100644 index 00000000..c648c11d --- /dev/null +++ b/backend/pkg/hub/internal/fhir/cigna/testdata/govcr-fixtures/TestCignaClient_SyncAll.cassette @@ -0,0 +1,1101 @@ +{ + "Name": "TestCignaClient_SyncAll", + "Tracks": [ + { + "Request": { + "Method": "GET", + "URL": { + "Scheme": "https", + "Opaque": "", + "User": null, + "Host": "p-hi2.digitaledge.cigna.com", + "Path": "/PatientAccess/v1-devportal/Patient/A00000000000005/$everything", + "RawPath": "", + "ForceQuery": false, + "RawQuery": "", + "Fragment": "", + "RawFragment": "" + }, + "Header": {}, + "Body": "" + }, + "Response": { + "Status": "200 OK", + "StatusCode": 200, + "Proto": "HTTP/2.0", + "ProtoMajor": 2, + "ProtoMinor": 0, + "Header": { + "Access-Control-Allow-Origin": [ + "*" + ], + "Cache-Control": [ + "no-store, no-cache" + ], + "Content-Length": [ + "29617" + ], + "Content-Security-Policy": [ + "default-src 'self'" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 01 Sep 2022 22:28:33 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Referrer-Policy": [ + "no-referrer" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "X-Amz-Apigw-Id": [ + "XzTCxFrJoAMFbTQ=" + ], + "X-Amzn-Requestid": [ + "7b3d2796-acc0-4f28-885e-194076e64c7d" + ], + "X-Amzn-Trace-Id": [ + "Root=1-63113211-0fe0195607ec3be656b70f76;Sampled=0" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Request-Id": [ + "1ef80a22-daa0-4872-9a11-67a70f7ef8b9" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "eyJtZXRhIjogeyJzb3VyY2UiOiAiaHR0cHM6Ly9wLWhpMi5kaWdpdGFsZWRnZS5jaWduYS5jb20ifSwgImVudHJ5IjogW3siZnVsbFVybCI6ICJodHRwczovL3AtaGkyLmRpZ2l0YWxlZGdlLmNpZ25hLmNvbS9QYXRpZW50QWNjZXNzL3YxLWRldnBvcnRhbC9QYXRpZW50L2lmcC1BMDAwMDAwMDAwMDAwMDUiLCAicmVzb3VyY2UiOiB7ImlkIjogImlmcC1BMDAwMDAwMDAwMDAwMDUiLCAibWV0YSI6IHsibGFzdFVwZGF0ZWQiOiAiMjAyMi0wNi0yMFQxNTo0NToyMi4wNDMwMDArMDA6MDAiLCAicHJvZmlsZSI6IFsiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9TdHJ1Y3R1cmVEZWZpbml0aW9uL0M0QkItUGF0aWVudCJdLCAic291cmNlIjogIklGUCNDcVAwNkFSdkpvOVhTOUNsIiwgInZlcnNpb25JZCI6ICIxIn0sICJ0ZXh0IjogeyJkaXYiOiAiPGRpdiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWxcIj48ZGl2IGNsYXNzPVwiaGFwaUhlYWRlclRleHRcIj5GZWxlY2l0YSA8Yj5NT05BSEFOIDwvYj48L2Rpdj48dGFibGUgY2xhc3M9XCJoYXBpUHJvcGVydHlUYWJsZVwiPjx0Ym9keT48dHI+PHRkPklkZW50aWZpZXI8L3RkPjx0ZD5BMDAwMDAwMDAwMDAwMDU8L3RkPjwvdHI+PHRyPjx0ZD5EYXRlIG9mIGJpcnRoPC90ZD48dGQ+PHNwYW4+MTIgSmFudWFyeSAyMDEzPC9zcGFuPjwvdGQ+PC90cj48L3Rib2R5PjwvdGFibGU+PC9kaXY+IiwgInN0YXR1cyI6ICJnZW5lcmF0ZWQifSwgImJpcnRoRGF0ZSI6ICIyMDEzLTAxLTEyIiwgImdlbmRlciI6ICJmZW1hbGUiLCAiaWRlbnRpZmllciI6IFt7InN5c3RlbSI6ICJodHRwczovL2RldmVsb3Blci5jaWduYS5jb20iLCAidHlwZSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJ1bSIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0lkZW50aWZpZXJUeXBlQ1MifV19LCAidmFsdWUiOiAiQTAwMDAwMDAwMDAwMDA1In0sIHsic3lzdGVtIjogImh0dHBzOi8vZGV2ZWxvcGVyLmNpZ25hLmNvbSIsICJ0eXBlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogIm1iIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vSWRlbnRpZmllclR5cGVDUyJ9XX0sICJ2YWx1ZSI6ICJ1bmtub3duIn1dLCAibWFyaXRhbFN0YXR1cyI6IHsiY29kaW5nIjogW3siY29kZSI6ICJVTksiLCAiZGlzcGxheSI6ICJ1bmtub3duIiwgInN5c3RlbSI6ICJodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL3YzLU51bGxGbGF2b3IifV0sICJ0ZXh0IjogInVua25vd24ifSwgIm5hbWUiOiBbeyJmYW1pbHkiOiAiTW9uYWhhbiIsICJnaXZlbiI6IFsiRmVsZWNpdGEiXSwgInVzZSI6ICJvZmZpY2lhbCJ9XSwgInRlbGVjb20iOiBbeyJzeXN0ZW0iOiAicGhvbmUiLCAidXNlIjogIm1vYmlsZSIsICJ2YWx1ZSI6ICI5NDA0NTM1NDk2In1dLCAicmVzb3VyY2VUeXBlIjogIlBhdGllbnQifSwgInNlYXJjaCI6IHsibW9kZSI6ICJtYXRjaCJ9fSwgeyJmdWxsVXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnRBY2Nlc3MvdjEtZGV2cG9ydGFsL0NvbmRpdGlvbi9pZnAtQTAwMDAwMDAwMDAwMDA1LUNTMDAwMDQ0OTUzNC1LNTcuOTIiLCAicmVzb3VyY2UiOiB7ImlkIjogImlmcC1BMDAwMDAwMDAwMDAwMDUtQ1MwMDAwNDQ5NTM0LUs1Ny45MiIsICJtZXRhIjogeyJsYXN0VXBkYXRlZCI6ICIyMDIyLTA2LTIwVDE1OjQ1OjIyLjQzMTAwMCswMDowMCIsICJwcm9maWxlIjogWyJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NvcmUvU3RydWN0dXJlRGVmaW5pdGlvbi91cy1jb3JlLWNvbmRpdGlvbiJdLCAic291cmNlIjogIklGUCNCZlZEbWpjVkF4QWZyNUJlIiwgInZlcnNpb25JZCI6ICIxIn0sICJjYXRlZ29yeSI6IFt7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfV0sICJjbGluaWNhbFN0YXR1cyI6IHsiY29kaW5nIjogW3siY29kZSI6ICJhY3RpdmUiLCAiZGlzcGxheSI6ICJhY3RpdmUiLCAic3lzdGVtIjogImh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNsaW5pY2FsIn1dLCAidGV4dCI6ICJhY3RpdmUifSwgImNvZGUiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiSzU3LjkyIiwgImRpc3BsYXkiOiAiRFZUUkNMSSBPRiBJTlRFU1QsIFBBUlQgVU5TUCwgVy9PIFBFUkYgT1IgQUJTQ0VTUyBXL08gQkxFRUQifV0sICJ0ZXh0IjogIk51bGwifSwgImlkZW50aWZpZXIiOiBbeyJ2YWx1ZSI6ICJBMDAwMDAwMDAwMDAwMDUtQ1MwMDAwNDQ5NTM0LUs1Ny45MiJ9XSwgInJlY29yZGVkRGF0ZSI6ICIyMDE5LTEwLTIyIiwgInN1YmplY3QiOiB7InJlZmVyZW5jZSI6ICJQYXRpZW50L2lmcC1BMDAwMDAwMDAwMDAwMDUifSwgInJlc291cmNlVHlwZSI6ICJDb25kaXRpb24ifSwgInNlYXJjaCI6IHsibW9kZSI6ICJtYXRjaCJ9fSwgeyJmdWxsVXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnRBY2Nlc3MvdjEtZGV2cG9ydGFsL0VuY291bnRlci9pZnAtMUM5QTQ2RjA3QjNDQURFMzNFRkM3NUFCQTNEQzM3Q0YiLCAicmVzb3VyY2UiOiB7ImlkIjogImlmcC0xQzlBNDZGMDdCM0NBREUzM0VGQzc1QUJBM0RDMzdDRiIsICJtZXRhIjogeyJsYXN0VXBkYXRlZCI6ICIyMDIyLTA2LTIwVDE1OjQ1OjI5LjY4NTAwMCswMDowMCIsICJwcm9maWxlIjogWyJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NvcmUvU3RydWN0dXJlRGVmaW5pdGlvbi91cy1jb3JlLWVuY291bnRlciJdLCAic291cmNlIjogIklGUCNlN3prZUxDU21RRmdVWDBaIiwgInZlcnNpb25JZCI6ICIxIn0sICJjbGFzcyI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19LCAiZGlhZ25vc2lzIjogW3siY29uZGl0aW9uIjogeyJyZWZlcmVuY2UiOiAiQ29uZGl0aW9uL2lmcC1BMDAwMDAwMDAwMDAwMDUtT1AwNDQ3NTc1NDI2LUs1Ny44MC1ZLSJ9LCAidXNlIjogeyJjb2RpbmciOiBbeyJkaXNwbGF5IjogIkFkbWlzc2lvbiBkaWFnbm9zaXMifV19fV0sICJpZGVudGlmaWVyIjogW3sic3lzdGVtIjogImh0dHA6Ly9kZXYuY2lnbmEuY29tL3N5c3RlbS9UUkNSIiwgInZhbHVlIjogIlRSQ1ItT1AwNDQ3NTc1NDI2LTEifV0sICJsb2NhdGlvbiI6IFt7ImxvY2F0aW9uIjogeyJyZWZlcmVuY2UiOiAiTG9jYXRpb24vaWZwLTczMTI1MzIifX0sIHsibG9jYXRpb24iOiB7InJlZmVyZW5jZSI6ICJMb2NhdGlvbi9pZnAtMDU2NjI2NSJ9fV0sICJwYXJ0aWNpcGFudCI6IFt7ImluZGl2aWR1YWwiOiB7InJlZmVyZW5jZSI6ICJQcmFjdGl0aW9uZXIvaWZwLTUwZWY0NTQyZWNiNWFlNWVkZGMwZGFjNzZhMTBhYWVkIn19LCB7ImluZGl2aWR1YWwiOiB7InJlZmVyZW5jZSI6ICJQcmFjdGl0aW9uZXIvaWZwLTZhNGQzZDZmZTE2NWI2YTBhNzliNmE5NzZkMDQzYzJjIn19XSwgInBlcmlvZCI6IHsiZW5kIjogIjIwMTktMTItMzEiLCAic3RhcnQiOiAiMjAxOS0xMS0wNyJ9LCAicmVhc29uQ29kZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAiSzU3LjgwIiwgImRpc3BsYXkiOiAiRHZ0cmNsaSBvZiBpbnRlc3QsIHBhcnQgdW5zcCwgdyBwZXJmIGFuZCBhYnNjZXNzIHcvbyBibGVlZCJ9XX1dLCAicmVhc29uUmVmZXJlbmNlIjogW3sicmVmZXJlbmNlIjogIkNvbmRpdGlvbi9pZnAtQTAwMDAwMDAwMDAwMDA1LU9QMDQ0NzU3NTQyNi1LNTcuODAtWS0ifV0sICJzZXJ2aWNlUHJvdmlkZXIiOiB7InJlZmVyZW5jZSI6ICJPcmdhbml6YXRpb24vaWZwLTA1NjYyNjUifSwgInNlcnZpY2VUeXBlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogIjMwMiIsICJkaXNwbGF5IjogIk1lZGljYWwgT3V0cGF0aWVudCJ9XX0sICJzdGF0dXMiOiAidW5rbm93biIsICJzdWJqZWN0IjogeyJyZWZlcmVuY2UiOiAiUGF0aWVudC9pZnAtQTAwMDAwMDAwMDAwMDA1In0sICJ0eXBlIjogW3siZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19XSwgInJlc291cmNlVHlwZSI6ICJFbmNvdW50ZXIifSwgInNlYXJjaCI6IHsibW9kZSI6ICJtYXRjaCJ9fSwgeyJmdWxsVXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnRBY2Nlc3MvdjEtZGV2cG9ydGFsL0V4cGxhbmF0aW9uT2ZCZW5lZml0L2lmcC01NzdCOTM5ODQ0Mjg4RUMyNzAyRUE5MkE4QTJCRUFBMCIsICJyZXNvdXJjZSI6IHsiaWQiOiAiaWZwLTU3N0I5Mzk4NDQyODhFQzI3MDJFQTkyQThBMkJFQUEwIiwgIm1ldGEiOiB7Imxhc3RVcGRhdGVkIjogIjIwMjItMDYtMjBUMTU6NDU6MzQuMTc2MDAwKzAwOjAwIiwgInByb2ZpbGUiOiBbImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvU3RydWN0dXJlRGVmaW5pdGlvbi9DNEJCLUV4cGxhbmF0aW9uT2ZCZW5lZml0LUlucGF0aWVudC1JbnN0aXR1dGlvbmFsIl0sICJzb3VyY2UiOiAiSUZQIzhTZGt2a1JaNTFhbUM1c1kiLCAidmVyc2lvbklkIjogIjEifSwgImFjY2lkZW50IjogeyJ0eXBlIjogeyJjb2RpbmciOiBbeyJkaXNwbGF5IjogIlhYWFhYIn1dfX0sICJiaWxsYWJsZVBlcmlvZCI6IHsiZW5kIjogIjIwMTktMTEtMjIiLCAic3RhcnQiOiAiMjAxOS0xMS0wOCJ9LCAiY2FyZVRlYW0iOiBbeyJwcm92aWRlciI6IHsicmVmZXJlbmNlIjogIk9yZ2FuaXphdGlvbi9pZnAtMDU2NjI2NSJ9LCAicm9sZSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJwZXJmb3JtaW5nIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltQ2FyZVRlYW1Sb2xlIn1dfSwgIl9zZXF1ZW5jZSI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19fV0sICJfY3JlYXRlZCI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19LCAiZGlhZ25vc2lzIjogW3siZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIks1NzIwIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJvbkFkbWlzc2lvbiI6IHsiY29kaW5nIjogW3siY29kZSI6ICJ5IiwgInN5c3RlbSI6ICJodHRwOi8vd3d3Lm51YmMub3JnL1ByZXNlbnRPbkFkbWlzc2lvbiJ9XX0sICJzZXF1ZW5jZSI6IDEsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJwcmluY2lwYWwiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJOMTg2IiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJvbkFkbWlzc2lvbiI6IHsiY29kaW5nIjogW3siY29kZSI6ICJ5IiwgInN5c3RlbSI6ICJodHRwOi8vd3d3Lm51YmMub3JnL1ByZXNlbnRPbkFkbWlzc2lvbiJ9XX0sICJzZXF1ZW5jZSI6IDIsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIks1NzIwIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDEsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJhZG1pdHRpbmciLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJaOTA1IiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDExLCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJaODc0NDIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgInNlcXVlbmNlIjogMTIsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIlo5ODg5MCIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAic2VxdWVuY2UiOiAxNCwgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiRDY0OSIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAib25BZG1pc3Npb24iOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAieSIsICJzeXN0ZW0iOiAiaHR0cDovL3d3dy5udWJjLm9yZy9QcmVzZW50T25BZG1pc3Npb24ifV19LCAic2VxdWVuY2UiOiA3LCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJRNjEyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDUsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIkU4NzYiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgIm9uQWRtaXNzaW9uIjogeyJjb2RpbmciOiBbeyJjb2RlIjogInkiLCAic3lzdGVtIjogImh0dHA6Ly93d3cubnViYy5vcmcvUHJlc2VudE9uQWRtaXNzaW9uIn1dfSwgInNlcXVlbmNlIjogOSwgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiWjc5ODIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgInNlcXVlbmNlIjogMTAsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIlo4MjQ5IiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDEzLCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJFODcxIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJvbkFkbWlzc2lvbiI6IHsiY29kaW5nIjogW3siY29kZSI6ICJ5IiwgInN5c3RlbSI6ICJodHRwOi8vd3d3Lm51YmMub3JnL1ByZXNlbnRPbkFkbWlzc2lvbiJ9XX0sICJzZXF1ZW5jZSI6IDMsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIkkxMjAiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgIm9uQWRtaXNzaW9uIjogeyJjb2RpbmciOiBbeyJjb2RlIjogInkiLCAic3lzdGVtIjogImh0dHA6Ly93d3cubnViYy5vcmcvUHJlc2VudE9uQWRtaXNzaW9uIn1dfSwgInNlcXVlbmNlIjogNCwgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiWjk0MCIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAic2VxdWVuY2UiOiA2LCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJFNzg1IiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJvbkFkbWlzc2lvbiI6IHsiY29kaW5nIjogW3siY29kZSI6ICJ5IiwgInN5c3RlbSI6ICJodHRwOi8vd3d3Lm51YmMub3JnL1ByZXNlbnRPbkFkbWlzc2lvbiJ9XX0sICJzZXF1ZW5jZSI6IDgsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX1dLCAiaWRlbnRpZmllciI6IFt7InR5cGUiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgInZhbHVlIjogIjE5MjUzODExMzEtOC1GQ1RTIn1dLCAiaW5zdXJhbmNlIjogW3siY292ZXJhZ2UiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgIl9mb2NhbCI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19fV0sICJpbnN1cmVyIjogeyJkaXNwbGF5IjogIkNpZ25hIn0sICJvdXRjb21lIjogImNvbXBsZXRlIiwgInBhdGllbnQiOiB7InJlZmVyZW5jZSI6ICJQYXRpZW50L2lmcC1BMDAwMDAwMDAwMDAwMDUifSwgInBheWVlIjogeyJwYXJ0eSI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19LCAidHlwZSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJkaXNwbGF5IjogIlByb3ZpZGVyIiwgInN5c3RlbSI6ICJodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL3BheWVldHlwZSJ9XX19LCAicGF5bWVudCI6IHsiZGF0ZSI6ICIyMDIwLTAxLTAyIn0sICJwcm92aWRlciI6IHsicmVmZXJlbmNlIjogIk9yZ2FuaXphdGlvbi9pZnAtMDU2NjI2NSJ9LCAiX3N0YXR1cyI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19LCAidG90YWwiOiBbeyJhbW91bnQiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgImNhdGVnb3J5IjogeyJjb2RpbmciOiBbeyJjb2RlIjogImlubmV0d29yayIsICJkaXNwbGF5IjogIkluIE5ldHdvcmsiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCUGF5ZXJBZGp1ZGljYXRpb25TdGF0dXMifV19fV0sICJ0eXBlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogImluc3RpdHV0aW9uYWwiLCAiZGlzcGxheSI6ICJJbnN0aXR1dGlvbmFsIENsYWltIiwgInN5c3RlbSI6ICJodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL2NsYWltLXR5cGUifV19LCAidXNlIjogImNsYWltIiwgInJlc291cmNlVHlwZSI6ICJFeHBsYW5hdGlvbk9mQmVuZWZpdCJ9LCAic2VhcmNoIjogeyJtb2RlIjogIm1hdGNoIn19LCB7ImZ1bGxVcmwiOiAiaHR0cHM6Ly9wLWhpMi5kaWdpdGFsZWRnZS5jaWduYS5jb20vUGF0aWVudEFjY2Vzcy92MS1kZXZwb3J0YWwvRXhwbGFuYXRpb25PZkJlbmVmaXQvaWZwLUI0MDI4QjVCOTVFM0U1NDBDRDFERkExOTY4RDVDMDhEIiwgInJlc291cmNlIjogeyJpZCI6ICJpZnAtQjQwMjhCNUI5NUUzRTU0MENEMURGQTE5NjhENUMwOEQiLCAibWV0YSI6IHsibGFzdFVwZGF0ZWQiOiAiMjAyMi0wNi0yMFQxNTo0NTozNC42OTkwMDArMDA6MDAiLCAicHJvZmlsZSI6IFsiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9TdHJ1Y3R1cmVEZWZpbml0aW9uL0M0QkItRXhwbGFuYXRpb25PZkJlbmVmaXQtUHJvZmVzc2lvbmFsLU5vbkNsaW5pY2lhbiJdLCAic291cmNlIjogIklGUCNCbVVmdjA1dDl3RGN5QXQwIiwgInZlcnNpb25JZCI6ICIxIn0sICJhY2NpZGVudCI6IHsidHlwZSI6IHsiY29kaW5nIjogW3siZGlzcGxheSI6ICJYWFhYWCJ9XX19LCAiYmlsbGFibGVQZXJpb2QiOiB7ImVuZCI6ICIyMDE5LTExLTIyIiwgInN0YXJ0IjogIjIwMTktMTEtMjIifSwgImNhcmVUZWFtIjogW3sicHJvdmlkZXIiOiB7InJlZmVyZW5jZSI6ICJPcmdhbml6YXRpb24vaWZwLTE0NjUxMjAifSwgInF1YWxpZmljYXRpb24iOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAidW5rbm93biIsICJkaXNwbGF5IjogIlBhdGhvbG9neSwgQW5hdG9taWMiLCAic3lzdGVtIjogImh0dHA6Ly9udWNjLm9yZy9wcm92aWRlci10YXhvbm9teSJ9XX0sICJyb2xlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogInBlcmZvcm1pbmciLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1DYXJlVGVhbVJvbGUifV19LCAiX3NlcXVlbmNlIjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX19XSwgIl9jcmVhdGVkIjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX0sICJkaWFnbm9zaXMiOiBbeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiTjE4NiIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAic2VxdWVuY2UiOiAyLCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAic2Vjb25kYXJ5IiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiSzU3MjAiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgInNlcXVlbmNlIjogMSwgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogInByaW5jaXBhbCIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIkU4NzEiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgInNlcXVlbmNlIjogMywgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogInNlY29uZGFyeSIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIlE2MTIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgInNlcXVlbmNlIjogNCwgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogInNlY29uZGFyeSIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX1dLCAiaWRlbnRpZmllciI6IFt7InR5cGUiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgInZhbHVlIjogIjE5MjcyNDY3OTgtNi1GQ1RTIn1dLCAiaW5zdXJhbmNlIjogW3siY292ZXJhZ2UiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgIl9mb2NhbCI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19fV0sICJpbnN1cmVyIjogeyJkaXNwbGF5IjogIkNpZ25hIn0sICJpdGVtIjogW3siYWRqdWRpY2F0aW9uIjogW3siY2F0ZWdvcnkiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiaW5uZXR3b3JrIiwgImRpc3BsYXkiOiAiSW4gTmV0d29yayIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJQYXllckFkanVkaWNhdGlvblN0YXR1cyJ9XX19XSwgIm5ldCI6IHsidmFsdWUiOiAyNX0sICJwcm9kdWN0T3JTZXJ2aWNlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogIjgzNzM1IiwgImRpc3BsYXkiOiAiQVNTQVkgT0YgTUFHTkVTSVVNIiwgInN5c3RlbSI6ICJodHRwOi8vd3d3LmFtYS1hc3NuLm9yZy9nby9jcHQifV19LCAicXVhbnRpdHkiOiB7InVuaXQiOiAiaXRlbV9xdWFudGl0eV91bml0IiwgInZhbHVlIjogMX0sICJfc2VxdWVuY2UiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgInNlcnZpY2VkUGVyaW9kIjogeyJlbmQiOiAiMjAxOS0xMS0yMiIsICJzdGFydCI6ICIyMDE5LTExLTIyIn19XSwgIm91dGNvbWUiOiAiY29tcGxldGUiLCAicGF0aWVudCI6IHsicmVmZXJlbmNlIjogIlBhdGllbnQvaWZwLUEwMDAwMDAwMDAwMDAwNSJ9LCAicGF5ZWUiOiB7InBhcnR5IjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX0sICJ0eXBlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgImRpc3BsYXkiOiAiUHJvdmlkZXIiLCAic3lzdGVtIjogImh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vcGF5ZWV0eXBlIn1dfX0sICJwYXltZW50IjogeyJkYXRlIjogIjIwMjAtMDEtMDkifSwgInByb3ZpZGVyIjogeyJyZWZlcmVuY2UiOiAiT3JnYW5pemF0aW9uL2lmcC0xNDY1MTIwIn0sICJfc3RhdHVzIjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX0sICJ0eXBlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogInByb2Zlc3Npb25hbCIsICJkaXNwbGF5IjogIlByb2Zlc3Npb25hbCBDbGFpbSIsICJzeXN0ZW0iOiAiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9jbGFpbS10eXBlIn1dfSwgInVzZSI6ICJjbGFpbSIsICJyZXNvdXJjZVR5cGUiOiAiRXhwbGFuYXRpb25PZkJlbmVmaXQifSwgInNlYXJjaCI6IHsibW9kZSI6ICJtYXRjaCJ9fSwgeyJmdWxsVXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnRBY2Nlc3MvdjEtZGV2cG9ydGFsL0V4cGxhbmF0aW9uT2ZCZW5lZml0L2lmcC1CMjcyNDA5RTgwMUVERjQ0Q0REQUQ4NjI1OURCQUM1MCIsICJyZXNvdXJjZSI6IHsiaWQiOiAiaWZwLUIyNzI0MDlFODAxRURGNDRDRERBRDg2MjU5REJBQzUwIiwgIm1ldGEiOiB7Imxhc3RVcGRhdGVkIjogIjIwMjItMDYtMjBUMTU6NDU6MzUuMjE4MDAwKzAwOjAwIiwgInByb2ZpbGUiOiBbImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvU3RydWN0dXJlRGVmaW5pdGlvbi9DNEJCLUV4cGxhbmF0aW9uT2ZCZW5lZml0LUlucGF0aWVudC1JbnN0aXR1dGlvbmFsIl0sICJzb3VyY2UiOiAiSUZQIzZPQWtlRU9meXJnYm5PbjEiLCAidmVyc2lvbklkIjogIjEifSwgImFjY2lkZW50IjogeyJ0eXBlIjogeyJjb2RpbmciOiBbeyJkaXNwbGF5IjogIlhYWFhYIn1dfX0sICJiaWxsYWJsZVBlcmlvZCI6IHsiZW5kIjogIjIwMTktMTEtMjIiLCAic3RhcnQiOiAiMjAxOS0xMS0wOCJ9LCAiY2FyZVRlYW0iOiBbeyJwcm92aWRlciI6IHsicmVmZXJlbmNlIjogIk9yZ2FuaXphdGlvbi9pZnAtMDU2NjI2NSJ9LCAicm9sZSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJwZXJmb3JtaW5nIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltQ2FyZVRlYW1Sb2xlIn1dfSwgIl9zZXF1ZW5jZSI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19fV0sICJfY3JlYXRlZCI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19LCAiZGlhZ25vc2lzIjogW3siZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIlo4NzQ0MiIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAic2VxdWVuY2UiOiAxMiwgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiWjk4ODkwIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDE0LCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJaOTQwIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDYsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIks1NzIwIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJvbkFkbWlzc2lvbiI6IHsiY29kaW5nIjogW3siY29kZSI6ICJ5IiwgInN5c3RlbSI6ICJodHRwOi8vd3d3Lm51YmMub3JnL1ByZXNlbnRPbkFkbWlzc2lvbiJ9XX0sICJzZXF1ZW5jZSI6IDEsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJwcmluY2lwYWwiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJRNjEyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDUsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIkU3ODUiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgIm9uQWRtaXNzaW9uIjogeyJjb2RpbmciOiBbeyJjb2RlIjogInkiLCAic3lzdGVtIjogImh0dHA6Ly93d3cubnViYy5vcmcvUHJlc2VudE9uQWRtaXNzaW9uIn1dfSwgInNlcXVlbmNlIjogOCwgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiRDY0OSIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAib25BZG1pc3Npb24iOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAieSIsICJzeXN0ZW0iOiAiaHR0cDovL3d3dy5udWJjLm9yZy9QcmVzZW50T25BZG1pc3Npb24ifV19LCAic2VxdWVuY2UiOiA3LCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJLNTcyMCIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAic2VxdWVuY2UiOiAxLCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAiYWRtaXR0aW5nIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiRTg3MSIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAib25BZG1pc3Npb24iOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAieSIsICJzeXN0ZW0iOiAiaHR0cDovL3d3dy5udWJjLm9yZy9QcmVzZW50T25BZG1pc3Npb24ifV19LCAic2VxdWVuY2UiOiAzLCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJaOTA1IiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDExLCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJaODI0OSIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAic2VxdWVuY2UiOiAxMywgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiWjc5ODIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgInNlcXVlbmNlIjogMTAsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX0sIHsiZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIkU4NzYiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbSIsICJ2ZXJzaW9uIjogIjEwIn1dfSwgIm9uQWRtaXNzaW9uIjogeyJjb2RpbmciOiBbeyJjb2RlIjogInkiLCAic3lzdGVtIjogImh0dHA6Ly93d3cubnViYy5vcmcvUHJlc2VudE9uQWRtaXNzaW9uIn1dfSwgInNlcXVlbmNlIjogOSwgInR5cGUiOiBbeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltRGlhZ25vc2lzVHlwZSJ9XX1dfSwgeyJkaWFnbm9zaXNDb2RlYWJsZUNvbmNlcHQiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiSTEyMCIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvaWNkLTEwLWNtIiwgInZlcnNpb24iOiAiMTAifV19LCAib25BZG1pc3Npb24iOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAieSIsICJzeXN0ZW0iOiAiaHR0cDovL3d3dy5udWJjLm9yZy9QcmVzZW50T25BZG1pc3Npb24ifV19LCAic2VxdWVuY2UiOiA0LCAidHlwZSI6IFt7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJOMTg2IiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJvbkFkbWlzc2lvbiI6IHsiY29kaW5nIjogW3siY29kZSI6ICJ5IiwgInN5c3RlbSI6ICJodHRwOi8vd3d3Lm51YmMub3JnL1ByZXNlbnRPbkFkbWlzc2lvbiJ9XX0sICJzZXF1ZW5jZSI6IDIsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJvdGhlciIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci91cy9jYXJpbi1iYi9Db2RlU3lzdGVtL0M0QkJDbGFpbURpYWdub3Npc1R5cGUifV19XX1dLCAiaWRlbnRpZmllciI6IFt7InR5cGUiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgInZhbHVlIjogIjE5MjUzODExMzEtMTYtRkNUUyJ9XSwgImluc3VyYW5jZSI6IFt7ImNvdmVyYWdlIjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX0sICJfZm9jYWwiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfX1dLCAiaW5zdXJlciI6IHsiZGlzcGxheSI6ICJDaWduYSJ9LCAib3V0Y29tZSI6ICJjb21wbGV0ZSIsICJwYXRpZW50IjogeyJyZWZlcmVuY2UiOiAiUGF0aWVudC9pZnAtQTAwMDAwMDAwMDAwMDA1In0sICJwYXllZSI6IHsicGFydHkiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgInR5cGUiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAib3RoZXIiLCAiZGlzcGxheSI6ICJQcm92aWRlciIsICJzeXN0ZW0iOiAiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9wYXllZXR5cGUifV19fSwgInBheW1lbnQiOiB7ImRhdGUiOiAiMjAyMC0wMS0wMiJ9LCAicHJvdmlkZXIiOiB7InJlZmVyZW5jZSI6ICJPcmdhbml6YXRpb24vaWZwLTA1NjYyNjUifSwgIl9zdGF0dXMiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgInRvdGFsIjogW3siYW1vdW50IjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX0sICJjYXRlZ29yeSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJpbm5ldHdvcmsiLCAiZGlzcGxheSI6ICJJbiBOZXR3b3JrIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQlBheWVyQWRqdWRpY2F0aW9uU3RhdHVzIn1dfX1dLCAidHlwZSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJpbnN0aXR1dGlvbmFsIiwgImRpc3BsYXkiOiAiSW5zdGl0dXRpb25hbCBDbGFpbSIsICJzeXN0ZW0iOiAiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9jbGFpbS10eXBlIn1dfSwgInVzZSI6ICJjbGFpbSIsICJyZXNvdXJjZVR5cGUiOiAiRXhwbGFuYXRpb25PZkJlbmVmaXQifSwgInNlYXJjaCI6IHsibW9kZSI6ICJtYXRjaCJ9fSwgeyJmdWxsVXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnRBY2Nlc3MvdjEtZGV2cG9ydGFsL0V4cGxhbmF0aW9uT2ZCZW5lZml0L2lmcC1DMEI1NEMzOEU3RkJCNEFBRUZFRjNCQjZFNzRGMzA4MSIsICJyZXNvdXJjZSI6IHsiaWQiOiAiaWZwLUMwQjU0QzM4RTdGQkI0QUFFRkVGM0JCNkU3NEYzMDgxIiwgIm1ldGEiOiB7Imxhc3RVcGRhdGVkIjogIjIwMjItMDYtMjBUMTU6NDU6NDkuMzEyMDAwKzAwOjAwIiwgInByb2ZpbGUiOiBbImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvU3RydWN0dXJlRGVmaW5pdGlvbi9DNEJCLUV4cGxhbmF0aW9uT2ZCZW5lZml0LVByb2Zlc3Npb25hbC1Ob25DbGluaWNpYW4iXSwgInNvdXJjZSI6ICJJRlAjYzNQNWtCd1V1Z00zRXZ3RyIsICJ2ZXJzaW9uSWQiOiAiMSJ9LCAiYWNjaWRlbnQiOiB7InR5cGUiOiB7ImNvZGluZyI6IFt7ImRpc3BsYXkiOiAiWFhYWFgifV19fSwgImJpbGxhYmxlUGVyaW9kIjogeyJlbmQiOiAiMjAxOS0xMC0xMCIsICJzdGFydCI6ICIyMDE5LTEwLTEwIn0sICJjYXJlVGVhbSI6IFt7InByb3ZpZGVyIjogeyJyZWZlcmVuY2UiOiAiT3JnYW5pemF0aW9uL2lmcC01MWZiMDZmMzdlNWVjOTczY2U2OTEzMmE5YTI1NzFmMyJ9LCAicXVhbGlmaWNhdGlvbiI6IHsiY29kaW5nIjogW3siY29kZSI6ICJ1bmtub3duIiwgImRpc3BsYXkiOiAiUmFkaW9sb2d5LCBEaWFnbm9zdGljIiwgInN5c3RlbSI6ICJodHRwOi8vbnVjYy5vcmcvcHJvdmlkZXItdGF4b25vbXkifV19LCAicm9sZSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJwZXJmb3JtaW5nIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vQzRCQkNsYWltQ2FyZVRlYW1Sb2xlIn1dfSwgIl9zZXF1ZW5jZSI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19fV0sICJfY3JlYXRlZCI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19LCAiZGlhZ25vc2lzIjogW3siZGlhZ25vc2lzQ29kZWFibGVDb25jZXB0IjogeyJjb2RpbmciOiBbeyJjb2RlIjogIlo5OTExIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDMsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJzZWNvbmRhcnkiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJaNDUyIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDIsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJzZWNvbmRhcnkiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19LCB7ImRpYWdub3Npc0NvZGVhYmxlQ29uY2VwdCI6IHsiY29kaW5nIjogW3siY29kZSI6ICJEMzI5IiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC9pY2QtMTAtY20iLCAidmVyc2lvbiI6ICIxMCJ9XX0sICJzZXF1ZW5jZSI6IDEsICJ0eXBlIjogW3siY29kaW5nIjogW3siY29kZSI6ICJwcmluY2lwYWwiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCQ2xhaW1EaWFnbm9zaXNUeXBlIn1dfV19XSwgImlkZW50aWZpZXIiOiBbeyJ0eXBlIjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX0sICJ2YWx1ZSI6ICIxOTIxNjY2NjAwLTEtRkNUUyJ9XSwgImluc3VyYW5jZSI6IFt7ImNvdmVyYWdlIjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX0sICJfZm9jYWwiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfX1dLCAiaW5zdXJlciI6IHsiZGlzcGxheSI6ICJDaWduYSJ9LCAiaXRlbSI6IFt7ImFkanVkaWNhdGlvbiI6IFt7ImNhdGVnb3J5IjogeyJjb2RpbmciOiBbeyJjb2RlIjogImlubmV0d29yayIsICJkaXNwbGF5IjogIkluIE5ldHdvcmsiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9DNEJCUGF5ZXJBZGp1ZGljYXRpb25TdGF0dXMifV19fV0sICJuZXQiOiB7InZhbHVlIjogMTY1LjY2fSwgInByb2R1Y3RPclNlcnZpY2UiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAiNzA0NzAiLCAiZGlzcGxheSI6ICJDVCBIRUFEL0JSQUlOIFcvTyAmIFcvRFlFIiwgInN5c3RlbSI6ICJodHRwOi8vd3d3LmFtYS1hc3NuLm9yZy9nby9jcHQifV19LCAicXVhbnRpdHkiOiB7InVuaXQiOiAiaXRlbV9xdWFudGl0eV91bml0IiwgInZhbHVlIjogMX0sICJfc2VxdWVuY2UiOiB7ImV4dGVuc2lvbiI6IFt7InVybCI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vZGF0YS1hYnNlbnQtcmVhc29uIiwgInZhbHVlQ29kZSI6ICJ1bmtub3duIn1dfSwgInNlcnZpY2VkUGVyaW9kIjogeyJlbmQiOiAiMjAxOS0xMC0xMCIsICJzdGFydCI6ICIyMDE5LTEwLTEwIn19XSwgIm91dGNvbWUiOiAiY29tcGxldGUiLCAicGF0aWVudCI6IHsicmVmZXJlbmNlIjogIlBhdGllbnQvaWZwLUEwMDAwMDAwMDAwMDAwNSJ9LCAicGF5ZWUiOiB7InBhcnR5IjogeyJleHRlbnNpb24iOiBbeyJ1cmwiOiAiaHR0cDovL2hsNy5vcmcvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL2RhdGEtYWJzZW50LXJlYXNvbiIsICJ2YWx1ZUNvZGUiOiAidW5rbm93biJ9XX0sICJ0eXBlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogIm90aGVyIiwgImRpc3BsYXkiOiAiUHJvdmlkZXIiLCAic3lzdGVtIjogImh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vcGF5ZWV0eXBlIn1dfX0sICJwYXltZW50IjogeyJkYXRlIjogIjIwMTktMTAtMTcifSwgInByb3ZpZGVyIjogeyJyZWZlcmVuY2UiOiAiT3JnYW5pemF0aW9uL2lmcC01MWZiMDZmMzdlNWVjOTczY2U2OTEzMmE5YTI1NzFmMyJ9LCAiX3N0YXR1cyI6IHsiZXh0ZW5zaW9uIjogW3sidXJsIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi9kYXRhLWFic2VudC1yZWFzb24iLCAidmFsdWVDb2RlIjogInVua25vd24ifV19LCAidHlwZSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJwcm9mZXNzaW9uYWwiLCAiZGlzcGxheSI6ICJQcm9mZXNzaW9uYWwgQ2xhaW0iLCAic3lzdGVtIjogImh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY2xhaW0tdHlwZSJ9XX0sICJ1c2UiOiAiY2xhaW0iLCAicmVzb3VyY2VUeXBlIjogIkV4cGxhbmF0aW9uT2ZCZW5lZml0In0sICJzZWFyY2giOiB7Im1vZGUiOiAibWF0Y2gifX0sIHsiZnVsbFVybCI6ICJodHRwczovL3AtaGkyLmRpZ2l0YWxlZGdlLmNpZ25hLmNvbS9QYXRpZW50QWNjZXNzL3YxLWRldnBvcnRhbC9JbW11bml6YXRpb24vaWZwLTJmMjZjYWhiLTUzNmMtNGUwMS04NjcyLTcyYTZiNTQzZmE2NSIsICJyZXNvdXJjZSI6IHsiaWQiOiAiaWZwLTJmMjZjYWhiLTUzNmMtNGUwMS04NjcyLTcyYTZiNTQzZmE2NSIsICJtZXRhIjogeyJsYXN0VXBkYXRlZCI6ICIyMDIyLTA2LTIwVDE1OjQ1OjUxLjg4NTAwMCswMDowMCIsICJzb3VyY2UiOiAiSUZQI0FHM09ZeWVZd281SXQwSm8iLCAidmVyc2lvbklkIjogIjEifSwgImxvY2F0aW9uIjogeyJyZWZlcmVuY2UiOiAiTG9jYXRpb24vaWZwLTJmMjZjYWFiLTUzNmMtNGUwMC04NjcyLTcyYTZiNTQzZmE4OSJ9LCAib2NjdXJyZW5jZURhdGVUaW1lIjogIjIwMjEtMDItMjJUMTU6MjA6MTIrMDA6MDAiLCAicGF0aWVudCI6IHsicmVmZXJlbmNlIjogIlBhdGllbnQvaWZwLUEwMDAwMDAwMDAwMDAwNSJ9LCAicHJpbWFyeVNvdXJjZSI6IHRydWUsICJzdGF0dXMiOiAiY29tcGxldGVkIiwgInZhY2NpbmVDb2RlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogIjIxMiIsICJzeXN0ZW0iOiAiaHR0cDovL2hsNy5vcmcvZmhpci9zaWQvY3Z4In1dfSwgInJlc291cmNlVHlwZSI6ICJJbW11bml6YXRpb24ifSwgInNlYXJjaCI6IHsibW9kZSI6ICJtYXRjaCJ9fSwgeyJmdWxsVXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnRBY2Nlc3MvdjEtZGV2cG9ydGFsL0xvY2F0aW9uL2lmcC0yZjI2Y2FhYi01MzZjLTRlMDAtODY3Mi03MmE2YjU0M2ZhODkiLCAicmVzb3VyY2UiOiB7ImlkIjogImlmcC0yZjI2Y2FhYi01MzZjLTRlMDAtODY3Mi03MmE2YjU0M2ZhODkiLCAibWV0YSI6IHsibGFzdFVwZGF0ZWQiOiAiMjAyMi0wNi0yMFQxNTo0NTo1MC4zNDUwMDArMDA6MDAiLCAic291cmNlIjogIklGUCNZZ2xmNVUzNHpUdXE5amZXIiwgInZlcnNpb25JZCI6ICIxIn0sICJhZGRyZXNzIjogeyJjaXR5IjogIkJPSVNFIiwgImNvdW50cnkiOiAiVVMiLCAibGluZSI6IFsiNjUgTUFJTiBTVCJdLCAicG9zdGFsQ29kZSI6ICI4MzcwMSIsICJzdGF0ZSI6ICJJRCJ9LCAibmFtZSI6ICJUUklTVEFURSBIRUFMVEggU0VSVklDRSIsICJyZXNvdXJjZVR5cGUiOiAiTG9jYXRpb24ifSwgInNlYXJjaCI6IHsibW9kZSI6ICJtYXRjaCJ9fSwgeyJmdWxsVXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnRBY2Nlc3MvdjEtZGV2cG9ydGFsL09yZ2FuaXphdGlvbi9pZnAtNTFmYjA2ZjM3ZTVlYzk3M2NlNjkxMzJhOWEyNTcxZjMiLCAicmVzb3VyY2UiOiB7ImlkIjogImlmcC01MWZiMDZmMzdlNWVjOTczY2U2OTEzMmE5YTI1NzFmMyIsICJtZXRhIjogeyJsYXN0VXBkYXRlZCI6ICIyMDIyLTA2LTIwVDE1OjQ1OjQ1LjE1NTAwMCswMDowMCIsICJwcm9maWxlIjogWyJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL1N0cnVjdHVyZURlZmluaXRpb24vQzRCQi1Pcmdhbml6YXRpb24iXSwgInNvdXJjZSI6ICJJRlAjMUhjN2xvM3VNQm1HTlAxeiIsICJ2ZXJzaW9uSWQiOiAiMSJ9LCAiYWN0aXZlIjogdHJ1ZSwgImFkZHJlc3MiOiBbeyJjaXR5IjogIlNVUlBSSVNFIiwgImxpbmUiOiBbIjEzOTkxIFcgR1JBTkQgQVZFIFNURSAxMDUiXSwgInBvc3RhbENvZGUiOiAiODUzNzQiLCAic3RhdGUiOiAiQVoiLCAidGV4dCI6ICIxMzk5MSBXIEdSQU5EIEFWRSBTVEUgMTA1IFNVUlBSSVNFIEFaIDg1Mzc0In1dLCAiaWRlbnRpZmllciI6IFt7InN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3NpZC91cy1ucGkiLCAidHlwZSI6IHsiY29kaW5nIjogW3siY29kZSI6ICJucGkiLCAic3lzdGVtIjogImh0dHA6Ly9obDcub3JnL2ZoaXIvdXMvY2FyaW4tYmIvQ29kZVN5c3RlbS9JZGVudGlmaWVyVHlwZUNTIn1dfSwgInZhbHVlIjogIjE2MDk4Njg2NzgifSwgeyJzeXN0ZW0iOiAiaHR0cHM6Ly9kZXZlbG9wZXIuY2lnbmEuY29tIiwgInR5cGUiOiB7ImNvZGluZyI6IFt7ImNvZGUiOiAicHJvdmlkIiwgInN5c3RlbSI6ICJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NhcmluLWJiL0NvZGVTeXN0ZW0vSWRlbnRpZmllclR5cGVDUyJ9XX19LCB7InN5c3RlbSI6ICJ1cm46b2lkOjIuMTYuODQwLjEuMTEzODgzLjQuNCIsICJ0eXBlIjogeyJjb2RpbmciOiBbeyJjb2RlIjogIlRBWCIsICJzeXN0ZW0iOiAiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS92Mi0wMjAzIn1dfX1dLCAibmFtZSI6ICJDSUdOQSBNRUQgR1JQIFBIQ1ktU1VOIENJVFkgV0UiLCAicmVzb3VyY2VUeXBlIjogIk9yZ2FuaXphdGlvbiJ9LCAic2VhcmNoIjogeyJtb2RlIjogIm1hdGNoIn19LCB7InJlc291cmNlIjogeyJpc3N1ZSI6IFt7ImNvZGUiOiAicHJvY2Vzc2luZyIsICJkaWFnbm9zdGljcyI6ICJFcnJvciBjb2RlIENMQ09NLTAwNjsgeC1yZXF1ZXN0LWlkOiA1MTM4MTMwZC02MmVkLTQ4YjEtYjdhYi05YTE4MzljNTViNTUiLCAic2V2ZXJpdHkiOiAiZmF0YWwifV0sICJyZXNvdXJjZVR5cGUiOiAiT3BlcmF0aW9uT3V0Y29tZSJ9fSwgeyJmdWxsVXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnQvQTAwMDAwMDAwMDAwMDA1IiwgInJlc291cmNlIjogeyJpZCI6ICJBMDAwMDAwMDAwMDAwMDUiLCAibGluayI6IFt7Im90aGVyIjogeyJyZWZlcmVuY2UiOiAiUGF0aWVudC9pZnAtQTAwMDAwMDAwMDAwMDA1In0sICJ0eXBlIjogInNlZWFsc28ifSwgeyJvdGhlciI6IHsicmVmZXJlbmNlIjogIlBhdGllbnQvY29tLTQ0YTA0ZWJiLTdhYmEtNGU2Ni05OWM3LTEyYjk5NDA1ZjMwZCJ9LCAidHlwZSI6ICJzZWVhbHNvIn1dLCAicmVzb3VyY2VUeXBlIjogIlBhdGllbnQifX1dLCAibGluayI6IFt7InJlbGF0aW9uIjogInNlbGYiLCAidXJsIjogImh0dHBzOi8vcC1oaTIuZGlnaXRhbGVkZ2UuY2lnbmEuY29tL1BhdGllbnRBY2Nlc3MvdjEtZGV2cG9ydGFsL1BhdGllbnQvQTAwMDAwMDAwMDAwMDA1LyRldmVyeXRoaW5nIn1dLCAidG90YWwiOiAxMSwgInR5cGUiOiAic2VhcmNoc2V0IiwgInJlc291cmNlVHlwZSI6ICJCdW5kbGUifQ==", + "ContentLength": 29617, + "TransferEncoding": null, + "Trailer": null, + "TLS": { + "Version": 771, + "HandshakeComplete": true, + "DidResume": false, + "CipherSuite": 49199, + "NegotiatedProtocol": "h2", + "NegotiatedProtocolIsMutual": true, + "ServerName": "p-hi2.digitaledge.cigna.com", + "PeerCertificates": [ + { + "Raw": "MIIGFjCCBP6gAwIBAgIQBFYMkK/A2/56qcNp/QjwZzANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2ZXIgQ0EgMUIxDzANBgNVBAMTBkFtYXpvbjAeFw0yMjAyMDEwMDAwMDBaFw0yMzAzMDEyMzU5NTlaMCAxHjAcBgNVBAMTFWRpZ2l0YWxlZGdlLmNpZ25hLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK+YoeE7a7I5d4VIjge1aaXJ4ZBHrvsNLIEMIb90pQR+6crHHC/7XUZDsG1NgD8Kq3WoOVN1ujlj5r5RPpv1YYAEWZ+ydk+S0NTUO3gnOvGnkCL26pTH8blkQk39E9aaxCliQGiJ22igJ+W8udcpBo4QukIlZU/i8yV5ZjRWNrx7gZBMWYUjDhZDLkfqS7E/R93QxUpnI7+7XegtuzBL89FLWN/rouQIHPCm735WzXap81AHlmYQmH6PfSE4v9Ob4uLbiRkPAptU8RSGsLEQfuF1qZTekEtyNq/1cJWYsakru2djv7u1ghBzBvjwuKJ+MqWtemrHhqa2Mih8j869CyUCAwEAAaOCAyQwggMgMB8GA1UdIwQYMBaAFFmkZgZSoHuVkjyjlAcnlnRb+T3QMB0GA1UdDgQWBBShX21ZtUJKIYg8oN05p4jy/73j5zBUBgNVHREETTBLghVkaWdpdGFsZWRnZS5jaWduYS5jb22CFyouZGlnaXRhbGVkZ2UuY2lnbmEuY29tghl3d3cuZGlnaXRhbGVkZ2UuY2lnbmEuY29tMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5zY2ExYi5hbWF6b250cnVzdC5jb20vc2NhMWItMS5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwdQYIKwYBBQUHAQEEaTBnMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5zY2ExYi5hbWF6b250cnVzdC5jb20wNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuc2NhMWIuYW1hem9udHJ1c3QuY29tL3NjYTFiLmNydDAMBgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgCt9776fP8QyIudPZwePhhqtGcpXc+xDCTKhYY069yCigAAAX60JKGaAAAEAwBHMEUCIHQuQDuE17u1aNHT8eXFYLxqfQR3BIJpSsLvraw9evpSAiEAnZDXi6SaB/ARQ5kztbyz7LmRFf0/EOlEVc55PfH865YAdwA1zxkbv7FsV78PrUxtQsu7ticgJlHqP+Eq76gDwzvWTAAAAX60JKGhAAAEAwBIMEYCIQDDOZxHCBrO6y+15FOt673LjRr8CUXcDiVu6VAg6HCxuAIhAPsvYKbh+ElmQuNR5vqWJ/6N2a+ZKVda37HjbrmStDXKAHUAs3N3B+GEUPhjhtYFqdwRCUp5LbFnDAuH3PADDnk2pZoAAAF+tCShugAABAMARjBEAiBhCs4TVne+f9Rp3lDjtd4ZShvkJy+EXVHlkj3V8o4FlgIgT3xKhAQth5I5S63KtY1FZxKECYFV/6HWKKQBlWuIFZowDQYJKoZIhvcNAQELBQADggEBACqcwP5S3v5mIQ88h8nHbLttMerxAZO/WCZVfKH3SCB1vyuouYqChN69c2b3xKgbqlZ1sIMwTLSvsWY+YILf1Kkfc/qdVv3ZT/em06UZBsf64VHS1Ltg+qtE7gkwN2AuNd2sXBHNMgMcieuAkx72eHpypIc8KOe67bRKehC0dIAuwwQDH3nABjKCOPI8WZKwArf2SLq3F+jWCxSWr4WAZD0QwrBG2ascr7YvG1k0i95leH6GQJFdmv0xe9sig1UdIkU7GWrQIQQxhbKF8spzdEcVm7GOjqYDwaPBncJp9dEJ0kDkcCsGBqQgLnQHTyh97nvAJ6p2oDvRlp+ckSwPDxw=", + "RawTBSCertificate": "MIIE/qADAgECAhAEVgyQr8Db/nqpw2n9CPBnMA0GCSqGSIb3DQEBCwUAMEYxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZBbWF6b24xFTATBgNVBAsTDFNlcnZlciBDQSAxQjEPMA0GA1UEAxMGQW1hem9uMB4XDTIyMDIwMTAwMDAwMFoXDTIzMDMwMTIzNTk1OVowIDEeMBwGA1UEAxMVZGlnaXRhbGVkZ2UuY2lnbmEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr5ih4Ttrsjl3hUiOB7VppcnhkEeu+w0sgQwhv3SlBH7pysccL/tdRkOwbU2APwqrdag5U3W6OWPmvlE+m/VhgARZn7J2T5LQ1NQ7eCc68aeQIvbqlMfxuWRCTf0T1prEKWJAaInbaKAn5by51ykGjhC6QiVlT+LzJXlmNFY2vHuBkExZhSMOFkMuR+pLsT9H3dDFSmcjv7td6C27MEvz0UtY3+ui5Agc8KbvflbNdqnzUAeWZhCYfo99ITi/05vi4tuJGQ8Cm1TxFIawsRB+4XWplN6QS3I2r/VwlZixqSu7Z2O/u7WCEHMG+PC4on4ypa16aseGprYyKHyPzr0LJQIDAQABo4IDJDCCAyAwHwYDVR0jBBgwFoAUWaRmBlKge5WSPKOUByeWdFv5PdAwHQYDVR0OBBYEFKFfbVm1QkohiDyg3TmniPL/vePnMFQGA1UdEQRNMEuCFWRpZ2l0YWxlZGdlLmNpZ25hLmNvbYIXKi5kaWdpdGFsZWRnZS5jaWduYS5jb22CGXd3dy5kaWdpdGFsZWRnZS5jaWduYS5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnNjYTFiLmFtYXpvbnRydXN0LmNvbS9zY2ExYi0xLmNybDATBgNVHSAEDDAKMAgGBmeBDAECATB1BggrBgEFBQcBAQRpMGcwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLnNjYTFiLmFtYXpvbnRydXN0LmNvbTA2BggrBgEFBQcwAoYqaHR0cDovL2NydC5zY2ExYi5hbWF6b250cnVzdC5jb20vc2NhMWIuY3J0MAwGA1UdEwEB/wQCMAAwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2AK33vvp8/xDIi509nB4+GGq0Zyldz7EMJMqFhjTr3IKKAAABfrQkoZoAAAQDAEcwRQIgdC5AO4TXu7Vo0dPx5cVgvGp9BHcEgmlKwu+trD16+lICIQCdkNeLpJoH8BFDmTO1vLPsuZEV/T8Q6URVznk98fzrlgB3ADXPGRu/sWxXvw+tTG1Cy7u2JyAmUeo/4SrvqAPDO9ZMAAABfrQkoaEAAAQDAEgwRgIhAMM5nEcIGs7rL7XkU63rvcuNGvwJRdwOJW7pUCDocLG4AiEA+y9gpuH4SWZC41Hm+pYn/o3Zr5kpV1rfseNuuZK0NcoAdQCzc3cH4YRQ+GOG1gWp3BEJSnktsWcMC4fc8AMOeTalmgAAAX60JKG6AAAEAwBGMEQCIGEKzhNWd75/1GneUOO13hlKG+QnL4RdUeWSPdXyjgWWAiBPfEqEBC2HkjlLrcq1jUVnEoQJgVX/odYopAGVa4gVmg==", + "RawSubjectPublicKeyInfo": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr5ih4Ttrsjl3hUiOB7VppcnhkEeu+w0sgQwhv3SlBH7pysccL/tdRkOwbU2APwqrdag5U3W6OWPmvlE+m/VhgARZn7J2T5LQ1NQ7eCc68aeQIvbqlMfxuWRCTf0T1prEKWJAaInbaKAn5by51ykGjhC6QiVlT+LzJXlmNFY2vHuBkExZhSMOFkMuR+pLsT9H3dDFSmcjv7td6C27MEvz0UtY3+ui5Agc8KbvflbNdqnzUAeWZhCYfo99ITi/05vi4tuJGQ8Cm1TxFIawsRB+4XWplN6QS3I2r/VwlZixqSu7Z2O/u7WCEHMG+PC4on4ypa16aseGprYyKHyPzr0LJQIDAQAB", + "RawSubject": "MCAxHjAcBgNVBAMTFWRpZ2l0YWxlZGdlLmNpZ25hLmNvbQ==", + "RawIssuer": "MEYxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZBbWF6b24xFTATBgNVBAsTDFNlcnZlciBDQSAxQjEPMA0GA1UEAxMGQW1hem9u", + "Signature": "KpzA/lLe/mYhDzyHycdsu20x6vEBk79YJlV8ofdIIHW/K6i5ioKE3r1zZvfEqBuqVnWwgzBMtK+xZj5ggt/UqR9z+p1W/dlP96bTpRkGx/rhUdLUu2D6q0TuCTA3YC413axcEc0yAxyJ64CTHvZ4enKkhzwo57rttEp6ELR0gC7DBAMfecAGMoI48jxZkrACt/ZIurcX6NYLFJavhYBkPRDCsEbZqxyvti8bWTSL3mV4foZAkV2a/TF72yKDVR0iRTsZatAhBDGFsoXyynN0RxWbsY6OpgPBo8Gdwmn10QnSQORwKwYGpCAudAdPKH3ue8AnqnagO9GWn5yRLA8PHA==", + "SignatureAlgorithm": 4, + "PublicKeyAlgorithm": 1, + "PublicKey": { + "N": "22166969182598356385963476374493665596454538792795790631866824229967665083833770693178182776154501364704405753058817654199629527114658278918028939765605728373537511190525588045185917626177195780119603554998440945140628359102212389483816839395313927433584114192582224531579886054652469109136187472813021894264686603662371070321952728562881616446499465567798084682066692385230743029368958766096624324048248107335897172375894403433591048370297897685707172808718765317463336434508229311011148360809639365379591352691204117336692049651307709728326887373286852287067875643991043752744947691034693363571924571949087799970597", + "E": 65537 + }, + "Version": 3, + "SerialNumber": 5763704365137333910451501369362280551, + "Issuer": { + "Country": [ + "US" + ], + "Organization": [ + "Amazon" + ], + "OrganizationalUnit": [ + "Server CA 1B" + ], + "Locality": null, + "Province": null, + "StreetAddress": null, + "PostalCode": null, + "SerialNumber": "", + "CommonName": "Amazon", + "Names": [ + { + "Type": [ + 2, + 5, + 4, + 6 + ], + "Value": "US" + }, + { + "Type": [ + 2, + 5, + 4, + 10 + ], + "Value": "Amazon" + }, + { + "Type": [ + 2, + 5, + 4, + 11 + ], + "Value": "Server CA 1B" + }, + { + "Type": [ + 2, + 5, + 4, + 3 + ], + "Value": "Amazon" + } + ], + "ExtraNames": null + }, + "Subject": { + "Country": null, + "Organization": null, + "OrganizationalUnit": null, + "Locality": null, + "Province": null, + "StreetAddress": null, + "PostalCode": null, + "SerialNumber": "", + "CommonName": "digitaledge.cigna.com", + "Names": [ + { + "Type": [ + 2, + 5, + 4, + 3 + ], + "Value": "digitaledge.cigna.com" + } + ], + "ExtraNames": null + }, + "NotBefore": "2022-02-01T00:00:00Z", + "NotAfter": "2023-03-01T23:59:59Z", + "KeyUsage": 5, + "Extensions": [ + { + "Id": [ + 2, + 5, + 29, + 35 + ], + "Critical": false, + "Value": "MBaAFFmkZgZSoHuVkjyjlAcnlnRb+T3Q" + }, + { + "Id": [ + 2, + 5, + 29, + 14 + ], + "Critical": false, + "Value": "BBShX21ZtUJKIYg8oN05p4jy/73j5w==" + }, + { + "Id": [ + 2, + 5, + 29, + 17 + ], + "Critical": false, + "Value": "MEuCFWRpZ2l0YWxlZGdlLmNpZ25hLmNvbYIXKi5kaWdpdGFsZWRnZS5jaWduYS5jb22CGXd3dy5kaWdpdGFsZWRnZS5jaWduYS5jb20=" + }, + { + "Id": [ + 2, + 5, + 29, + 15 + ], + "Critical": true, + "Value": "AwIFoA==" + }, + { + "Id": [ + 2, + 5, + 29, + 37 + ], + "Critical": false, + "Value": "MBQGCCsGAQUFBwMBBggrBgEFBQcDAg==" + }, + { + "Id": [ + 2, + 5, + 29, + 31 + ], + "Critical": false, + "Value": "MDQwMqAwoC6GLGh0dHA6Ly9jcmwuc2NhMWIuYW1hem9udHJ1c3QuY29tL3NjYTFiLTEuY3Js" + }, + { + "Id": [ + 2, + 5, + 29, + 32 + ], + "Critical": false, + "Value": "MAowCAYGZ4EMAQIB" + }, + { + "Id": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 1, + 1 + ], + "Critical": false, + "Value": "MGcwLQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLnNjYTFiLmFtYXpvbnRydXN0LmNvbTA2BggrBgEFBQcwAoYqaHR0cDovL2NydC5zY2ExYi5hbWF6b250cnVzdC5jb20vc2NhMWIuY3J0" + }, + { + "Id": [ + 2, + 5, + 29, + 19 + ], + "Critical": true, + "Value": "MAA=" + }, + { + "Id": [ + 1, + 3, + 6, + 1, + 4, + 1, + 11129, + 2, + 4, + 2 + ], + "Critical": false, + "Value": "BIIBagFoAHYArfe++nz/EMiLnT2cHj4YarRnKV3PsQwkyoWGNOvcgooAAAF+tCShmgAABAMARzBFAiB0LkA7hNe7tWjR0/HlxWC8an0EdwSCaUrC762sPXr6UgIhAJ2Q14ukmgfwEUOZM7W8s+y5kRX9PxDpRFXOeT3x/OuWAHcANc8ZG7+xbFe/D61MbULLu7YnICZR6j/hKu+oA8M71kwAAAF+tCShoQAABAMASDBGAiEAwzmcRwgazusvteRTreu9y40a/AlF3A4lbulQIOhwsbgCIQD7L2Cm4fhJZkLjUeb6lif+jdmvmSlXWt+x4265krQ1ygB1ALNzdwfhhFD4Y4bWBancEQlKeS2xZwwLh9zwAw55NqWaAAABfrQkoboAAAQDAEYwRAIgYQrOE1Z3vn/Uad5Q47XeGUob5CcvhF1R5ZI91fKOBZYCIE98SoQELYeSOUutyrWNRWcShAmBVf+h1iikAZVriBWa" + } + ], + "ExtraExtensions": null, + "UnhandledCriticalExtensions": null, + "ExtKeyUsage": [ + 1, + 2 + ], + "UnknownExtKeyUsage": null, + "BasicConstraintsValid": true, + "IsCA": false, + "MaxPathLen": -1, + "MaxPathLenZero": false, + "SubjectKeyId": "oV9tWbVCSiGIPKDdOaeI8v+94+c=", + "AuthorityKeyId": "WaRmBlKge5WSPKOUByeWdFv5PdA=", + "OCSPServer": [ + "http://ocsp.sca1b.amazontrust.com" + ], + "IssuingCertificateURL": [ + "http://crt.sca1b.amazontrust.com/sca1b.crt" + ], + "DNSNames": [ + "digitaledge.cigna.com", + "*.digitaledge.cigna.com", + "www.digitaledge.cigna.com" + ], + "EmailAddresses": null, + "IPAddresses": null, + "URIs": null, + "PermittedDNSDomainsCritical": false, + "PermittedDNSDomains": null, + "ExcludedDNSDomains": null, + "PermittedIPRanges": null, + "ExcludedIPRanges": null, + "PermittedEmailAddresses": null, + "ExcludedEmailAddresses": null, + "PermittedURIDomains": null, + "ExcludedURIDomains": null, + "CRLDistributionPoints": [ + "http://crl.sca1b.amazontrust.com/sca1b-1.crl" + ], + "PolicyIdentifiers": [ + [ + 2, + 23, + 140, + 1, + 2, + 1 + ] + ] + }, + { + "Raw": "MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENBIDFCMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCThZn3c68asg3Wuw6MLAd5tES6BIoSMzoKcG5blPVo+sDORrMd4f2AbnZcMzPa43j4wNxhplty6aUKk4T1qe9BOwKFjwK6zmxxLVYo7bHViXsPlJ6qOMpFge5blDP+18x+B26A0piiQOuPkfyDyeR4xQghfj66Yo19V+emU3nazfvpFA+ROz6WoVmB5x+F2pV8xeKNR7u6azDdU5YVX1TawprmxRC1+WsAYmz6qP+z8ArDITC2FMVy2fw0IjKOtEXc/VfmtTFch5+AfGYMGMqqvJ6LcXiAhqG5TI+Dr0RtM88k+8XUBCeQ8IGKuANaL7TiItKZYxK1MMuTJtV9IblAgMBAAGjggE7MIIBNzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUWaRmBlKge5WSPKOUByeWdFv5PdAwHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUHAQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRydXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5yb290Y2ExLmFtYXpvbnRydXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IBAQCFkr41u3nPo4FCHOTjY3NTOVI159Gt/a6ZiqyJEi+752+a1U5y6iAwYfmXss2lJwJFqMp2PphKg5625kXg8kP2CN5t6G7bMQcT8C8xDZNtYTd7WPD8UZiRKAJPBXa30/AbwuZe0GaFEQ8ugcYQgSn+IGBI8/LwhBNTZTUVEWuCUUBVV18YtbAiPq3yXqMB48Oz+ctBWuZSkbvkNodPLamkB2g1upRyzQ7qDn1X8nn8N8V7YJ6y68AtkHcNSRAnpTitxBKjtKPISLMVCx7i4hncxHZSyLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/", + "RawTBSCertificate": "MIIDMaADAgECAhMGf5RXhYforHfeslMyW7yZi1YNMA0GCSqGSIb3DQEBCwUAMDkxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZBbWF6b24xGTAXBgNVBAMTEEFtYXpvbiBSb290IENBIDEwHhcNMTUxMDIyMDAwMDAwWhcNMjUxMDE5MDAwMDAwWjBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUwEwYDVQQLEwxTZXJ2ZXIgQ0EgMUIxDzANBgNVBAMTBkFtYXpvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMJOFmfdzrxqyDda7DowsB3m0RLoEihIzOgpwbluU9Wj6wM5Gsx3h/YBudlwzM9rjePjA3GGmW3LppQqThPWp70E7AoWPArrObHEtVijtsdWJew+Unqo4ykWB7luUM/7XzH4HboDSmKJA64+R/IPJ5HjFCCF+PrpijX1X56ZTedrN++kUD5E7PpahWYHnH4XalXzF4o1Hu7prMN1TlhVfVNrCmubFELX5awBibPqo/7PwCsMhMLYUxXLZ/DQiMo60Rdz9V+a1MVyHn4B8ZgwYyqq8notxeICGoblMj4OvRG0zzyT7xdQEJ5DwgYq4A1ovtOIi0pljErUwy5Mm1X0huUCAwEAAaOCATswggE3MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBRZpGYGUqB7lZI8o5QHJ5Z0W/k90DAfBgNVHSMEGDAWgBSEGMyFNOy8DJSULghZnMeyEE4KCDB7BggrBgEFBQcBAQRvMG0wLwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLnJvb3RjYTEuYW1hem9udHJ1c3QuY29tMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY2VyMD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly9jcmwucm9vdGNhMS5hbWF6b250cnVzdC5jb20vcm9vdGNhMS5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgE=", + "RawSubjectPublicKeyInfo": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwk4WZ93OvGrIN1rsOjCwHebREugSKEjM6CnBuW5T1aPrAzkazHeH9gG52XDMz2uN4+MDcYaZbcumlCpOE9anvQTsChY8Cus5scS1WKO2x1Yl7D5SeqjjKRYHuW5Qz/tfMfgdugNKYokDrj5H8g8nkeMUIIX4+umKNfVfnplN52s376RQPkTs+lqFZgecfhdqVfMXijUe7umsw3VOWFV9U2sKa5sUQtflrAGJs+qj/s/AKwyEwthTFctn8NCIyjrRF3P1X5rUxXIefgHxmDBjKqryei3F4gIahuUyPg69EbTPPJPvF1AQnkPCBirgDWi+04iLSmWMStTDLkybVfSG5QIDAQAB", + "RawSubject": "MEYxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZBbWF6b24xFTATBgNVBAsTDFNlcnZlciBDQSAxQjEPMA0GA1UEAxMGQW1hem9u", + "RawIssuer": "MDkxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZBbWF6b24xGTAXBgNVBAMTEEFtYXpvbiBSb290IENBIDE=", + "Signature": "hZK+Nbt5z6OBQhzk42NzUzlSNefRrf2umYqsiRIvu+dvmtVOcuogMGH5l7LNpScCRajKdj6YSoOetuZF4PJD9gjebehu2zEHE/AvMQ2TbWE3e1jw/FGYkSgCTwV2t9PwG8LmXtBmhREPLoHGEIEp/iBgSPPy8IQTU2U1FRFrglFAVVdfGLWwIj6t8l6jAePDs/nLQVrmUpG75DaHTy2ppAdoNbqUcs0O6g59V/J5/DfFe2CesuvALZB3DUkQJ6U4rcQSo7SjyEizFQse4uIZ3MR2Usi8ikF4cNltl7NKi3gtXrQPo0xgyuFHy3gtEhexUovKOSy9tS/CMwKWq9qUfw==", + "SignatureAlgorithm": 4, + "PublicKeyAlgorithm": 1, + "PublicKey": { + "N": "24528737555851895213919827617064808536856788789868126310716752303420041319710819680867697306230985630039655096548324364189962675576756038921107965025585889330528490649228935527969954506874750514159926943451238689552458142167021149788529783891257271028002485075630471793111207960868638365698705018555597520367289025831586046483446904825820575805338475813865444295353094097022678376192149453480223428943386514159000527368947588174705227657134217583008630047462959260157651883088072156905420231950318110240318878613016990846576820326568049365612395397183597930457965295993595011597251067348997341253617591444999389873893", + "E": 65537 + }, + "Version": 3, + "SerialNumber": 144918209630989264145272943054026349679957517, + "Issuer": { + "Country": [ + "US" + ], + "Organization": [ + "Amazon" + ], + "OrganizationalUnit": null, + "Locality": null, + "Province": null, + "StreetAddress": null, + "PostalCode": null, + "SerialNumber": "", + "CommonName": "Amazon Root CA 1", + "Names": [ + { + "Type": [ + 2, + 5, + 4, + 6 + ], + "Value": "US" + }, + { + "Type": [ + 2, + 5, + 4, + 10 + ], + "Value": "Amazon" + }, + { + "Type": [ + 2, + 5, + 4, + 3 + ], + "Value": "Amazon Root CA 1" + } + ], + "ExtraNames": null + }, + "Subject": { + "Country": [ + "US" + ], + "Organization": [ + "Amazon" + ], + "OrganizationalUnit": [ + "Server CA 1B" + ], + "Locality": null, + "Province": null, + "StreetAddress": null, + "PostalCode": null, + "SerialNumber": "", + "CommonName": "Amazon", + "Names": [ + { + "Type": [ + 2, + 5, + 4, + 6 + ], + "Value": "US" + }, + { + "Type": [ + 2, + 5, + 4, + 10 + ], + "Value": "Amazon" + }, + { + "Type": [ + 2, + 5, + 4, + 11 + ], + "Value": "Server CA 1B" + }, + { + "Type": [ + 2, + 5, + 4, + 3 + ], + "Value": "Amazon" + } + ], + "ExtraNames": null + }, + "NotBefore": "2015-10-22T00:00:00Z", + "NotAfter": "2025-10-19T00:00:00Z", + "KeyUsage": 97, + "Extensions": [ + { + "Id": [ + 2, + 5, + 29, + 19 + ], + "Critical": true, + "Value": "MAYBAf8CAQA=" + }, + { + "Id": [ + 2, + 5, + 29, + 15 + ], + "Critical": true, + "Value": "AwIBhg==" + }, + { + "Id": [ + 2, + 5, + 29, + 14 + ], + "Critical": false, + "Value": "BBRZpGYGUqB7lZI8o5QHJ5Z0W/k90A==" + }, + { + "Id": [ + 2, + 5, + 29, + 35 + ], + "Critical": false, + "Value": "MBaAFIQYzIU07LwMlJQuCFmcx7IQTgoI" + }, + { + "Id": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 1, + 1 + ], + "Critical": false, + "Value": "MG0wLwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLnJvb3RjYTEuYW1hem9udHJ1c3QuY29tMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY2Vy" + }, + { + "Id": [ + 2, + 5, + 29, + 31 + ], + "Critical": false, + "Value": "MDYwNKAyoDCGLmh0dHA6Ly9jcmwucm9vdGNhMS5hbWF6b250cnVzdC5jb20vcm9vdGNhMS5jcmw=" + }, + { + "Id": [ + 2, + 5, + 29, + 32 + ], + "Critical": false, + "Value": "MAowCAYGZ4EMAQIB" + } + ], + "ExtraExtensions": null, + "UnhandledCriticalExtensions": null, + "ExtKeyUsage": null, + "UnknownExtKeyUsage": null, + "BasicConstraintsValid": true, + "IsCA": true, + "MaxPathLen": 0, + "MaxPathLenZero": true, + "SubjectKeyId": "WaRmBlKge5WSPKOUByeWdFv5PdA=", + "AuthorityKeyId": "hBjMhTTsvAyUlC4IWZzHshBOCgg=", + "OCSPServer": [ + "http://ocsp.rootca1.amazontrust.com" + ], + "IssuingCertificateURL": [ + "http://crt.rootca1.amazontrust.com/rootca1.cer" + ], + "DNSNames": null, + "EmailAddresses": null, + "IPAddresses": null, + "URIs": null, + "PermittedDNSDomainsCritical": false, + "PermittedDNSDomains": null, + "ExcludedDNSDomains": null, + "PermittedIPRanges": null, + "ExcludedIPRanges": null, + "PermittedEmailAddresses": null, + "ExcludedEmailAddresses": null, + "PermittedURIDomains": null, + "ExcludedURIDomains": null, + "CRLDistributionPoints": [ + "http://crl.rootca1.amazontrust.com/rootca1.crl" + ], + "PolicyIdentifiers": [ + [ + 2, + 23, + 140, + 1, + 2, + 1 + ] + ] + }, + { + "Raw": "MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaOCATEwggEtMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSEGMyFNOy8DJSULghZnMeyEE4KCDAfBgNVHSMEGDAWgBScXwDfqgHXMCs4iKK4bUqc8hGRgzB4BggrBgEFBQcBAQRsMGowLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250cnVzdC5jb20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9jcnQucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY2VyMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQsFAAOCAQEAYjdCXLwQtT6LLOkMm2xF4gcAevnFWAu5CIw+7bMlPLVvUOTNNWqnkzSWMiGpSESrnO09tKpzbeR/FoCJbM8oAxiDR3mjEH4wW6w7sGDgd9QIpuEdfF7Au/maeyKdpwAJfqxGF4PcnCZXmTA5YpaP7dreqsXMGz7KQ2hsVxa81Q4gLv7/wmpdLqBKbRRYh5TmOTFffHPLkIhqhBGWJ6bt2YFGpn6jcgAKUj6DiAdjd4lpFw85hdKrCEVN0FE6/V1dN2RMfjCyVSRCnTawXZwXgWHxyvkQAiSr6w10kY17RSlQOYiypok1JR4UakcjMS9cmvqtmg5iUaQqqcT5NJ0hGA==", + "RawTBSCertificate": "MIIDeqADAgECAhMGf5RKKifN8/rCrisB+QjuucTGMA0GCSqGSIb3DQEBCwUAMIGYMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZpZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwHhcNMTUwNTI1MTIwMDAwWhcNMzcxMjMxMDEwMDAwWjA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsniAccp41eNxr0eAUHR9btjXiHb0mWj3WCFg+XSEAS+sAi2G06BDek6ypNA2ugG+jdtIyAcXNkz07ogjxz7rN/W1GfhJaLDe17l2OB1hnqT+gjal5UpW5EXh+f20Fvp02pybNTkv+rAgUAZsetCAsqb5r+xHGY9QOAfcooc5WPi61an5SGcwlu6UeF5viaNRwDCGZqFFZrpU66PDkflI3P/R6DAtfS10cDXXiCT3nsRZbrtzhxfyMkYouEP6tx2qyrTynyQOLUv3cVxeaf/qlQLLOIquUDhv2/stYhvFxx5U4XfgZ8gPnIcj1j9AIH8ggMSATD47JCaOBK5smsiqDQIDAQABo4IBMTCCAS0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMB8GA1UdIwQYMBaAFJxfAN+qAdcwKziIorhtSpzyEZGDMHgGCCsGAQUFBwEBBGwwajAuBggrBgEFBQcwAYYiaHR0cDovL29jc3Aucm9vdGcyLmFtYXpvbnRydXN0LmNvbTA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5yb290ZzIuYW1hem9udHJ1c3QuY29tL3Jvb3RnMi5jZXIwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5yb290ZzIuYW1hem9udHJ1c3QuY29tL3Jvb3RnMi5jcmwwEQYDVR0gBAowCDAGBgRVHSAA", + "RawSubjectPublicKeyInfo": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsniAccp41eNxr0eAUHR9btjXiHb0mWj3WCFg+XSEAS+sAi2G06BDek6ypNA2ugG+jdtIyAcXNkz07ogjxz7rN/W1GfhJaLDe17l2OB1hnqT+gjal5UpW5EXh+f20Fvp02pybNTkv+rAgUAZsetCAsqb5r+xHGY9QOAfcooc5WPi61an5SGcwlu6UeF5viaNRwDCGZqFFZrpU66PDkflI3P/R6DAtfS10cDXXiCT3nsRZbrtzhxfyMkYouEP6tx2qyrTynyQOLUv3cVxeaf/qlQLLOIquUDhv2/stYhvFxx5U4XfgZ8gPnIcj1j9AIH8ggMSATD47JCaOBK5smsiqDQIDAQAB", + "RawSubject": "MDkxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZBbWF6b24xGTAXBgNVBAMTEEFtYXpvbiBSb290IENBIDE=", + "RawIssuer": "MIGYMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZpZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzI=", + "Signature": "YjdCXLwQtT6LLOkMm2xF4gcAevnFWAu5CIw+7bMlPLVvUOTNNWqnkzSWMiGpSESrnO09tKpzbeR/FoCJbM8oAxiDR3mjEH4wW6w7sGDgd9QIpuEdfF7Au/maeyKdpwAJfqxGF4PcnCZXmTA5YpaP7dreqsXMGz7KQ2hsVxa81Q4gLv7/wmpdLqBKbRRYh5TmOTFffHPLkIhqhBGWJ6bt2YFGpn6jcgAKUj6DiAdjd4lpFw85hdKrCEVN0FE6/V1dN2RMfjCyVSRCnTawXZwXgWHxyvkQAiSr6w10kY17RSlQOYiypok1JR4UakcjMS9cmvqtmg5iUaQqqcT5NJ0hGA==", + "SignatureAlgorithm": 4, + "PublicKeyAlgorithm": 1, + "PublicKey": { + "N": "22529839904807742196558773392430766620630713202204326167346456925862066285712069978308045976033918808540171076811098215136401323342247576789054764683787147408289170989302937775178809187827657352584557953877946352196797789035355954596527030584944622221752357105572088106020206921431118198373122638305846252087992561841631797199384157902018140720267433956687491591657652730221337591680012205319549572614035105482287002884850178224609018864719685310905426619874727796905080238179726224664042154200651710137931048812546957419686875805576245376866031854569863410951649630469236463991472642618512857920826701027482532358669", + "E": 65537 + }, + "Version": 3, + "SerialNumber": 144918191876577076464031512351042010504348870, + "Issuer": { + "Country": [ + "US" + ], + "Organization": [ + "Starfield Technologies, Inc." + ], + "OrganizationalUnit": null, + "Locality": [ + "Scottsdale" + ], + "Province": [ + "Arizona" + ], + "StreetAddress": null, + "PostalCode": null, + "SerialNumber": "", + "CommonName": "Starfield Services Root Certificate Authority - G2", + "Names": [ + { + "Type": [ + 2, + 5, + 4, + 6 + ], + "Value": "US" + }, + { + "Type": [ + 2, + 5, + 4, + 8 + ], + "Value": "Arizona" + }, + { + "Type": [ + 2, + 5, + 4, + 7 + ], + "Value": "Scottsdale" + }, + { + "Type": [ + 2, + 5, + 4, + 10 + ], + "Value": "Starfield Technologies, Inc." + }, + { + "Type": [ + 2, + 5, + 4, + 3 + ], + "Value": "Starfield Services Root Certificate Authority - G2" + } + ], + "ExtraNames": null + }, + "Subject": { + "Country": [ + "US" + ], + "Organization": [ + "Amazon" + ], + "OrganizationalUnit": null, + "Locality": null, + "Province": null, + "StreetAddress": null, + "PostalCode": null, + "SerialNumber": "", + "CommonName": "Amazon Root CA 1", + "Names": [ + { + "Type": [ + 2, + 5, + 4, + 6 + ], + "Value": "US" + }, + { + "Type": [ + 2, + 5, + 4, + 10 + ], + "Value": "Amazon" + }, + { + "Type": [ + 2, + 5, + 4, + 3 + ], + "Value": "Amazon Root CA 1" + } + ], + "ExtraNames": null + }, + "NotBefore": "2015-05-25T12:00:00Z", + "NotAfter": "2037-12-31T01:00:00Z", + "KeyUsage": 97, + "Extensions": [ + { + "Id": [ + 2, + 5, + 29, + 19 + ], + "Critical": true, + "Value": "MAMBAf8=" + }, + { + "Id": [ + 2, + 5, + 29, + 15 + ], + "Critical": true, + "Value": "AwIBhg==" + }, + { + "Id": [ + 2, + 5, + 29, + 14 + ], + "Critical": false, + "Value": "BBSEGMyFNOy8DJSULghZnMeyEE4KCA==" + }, + { + "Id": [ + 2, + 5, + 29, + 35 + ], + "Critical": false, + "Value": "MBaAFJxfAN+qAdcwKziIorhtSpzyEZGD" + }, + { + "Id": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 1, + 1 + ], + "Critical": false, + "Value": "MGowLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250cnVzdC5jb20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9jcnQucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY2Vy" + }, + { + "Id": [ + 2, + 5, + 29, + 31 + ], + "Critical": false, + "Value": "MDQwMqAwoC6GLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY3Js" + }, + { + "Id": [ + 2, + 5, + 29, + 32 + ], + "Critical": false, + "Value": "MAgwBgYEVR0gAA==" + } + ], + "ExtraExtensions": null, + "UnhandledCriticalExtensions": null, + "ExtKeyUsage": null, + "UnknownExtKeyUsage": null, + "BasicConstraintsValid": true, + "IsCA": true, + "MaxPathLen": -1, + "MaxPathLenZero": false, + "SubjectKeyId": "hBjMhTTsvAyUlC4IWZzHshBOCgg=", + "AuthorityKeyId": "nF8A36oB1zArOIiiuG1KnPIRkYM=", + "OCSPServer": [ + "http://ocsp.rootg2.amazontrust.com" + ], + "IssuingCertificateURL": [ + "http://crt.rootg2.amazontrust.com/rootg2.cer" + ], + "DNSNames": null, + "EmailAddresses": null, + "IPAddresses": null, + "URIs": null, + "PermittedDNSDomainsCritical": false, + "PermittedDNSDomains": null, + "ExcludedDNSDomains": null, + "PermittedIPRanges": null, + "ExcludedIPRanges": null, + "PermittedEmailAddresses": null, + "ExcludedEmailAddresses": null, + "PermittedURIDomains": null, + "ExcludedURIDomains": null, + "CRLDistributionPoints": [ + "http://crl.rootg2.amazontrust.com/rootg2.crl" + ], + "PolicyIdentifiers": [ + [ + 2, + 5, + 29, + 32, + 0 + ] + ] + }, + { + "Raw": "MIIEdTCCA12gAwIBAgIJAKcOSkw0grd/MA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wOTA5MDIwMDAwMDBaFw0zNDA2MjgxNzM5MTZaMIGYMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZpZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVDDrEKvlO4vW+GZdfjohTsR8/y8+fIBNtKTrID30892t2OGPZNmCom15cAICyL1l/9of5JUOG52kbUpqQ4XHj2C0NTm/2yEnZtvMaVq4rtnQU68/7JuMauh2WLmo7WJSJR1b/JaCTcFOD2oR0FMNnngRoOt+OQFodSk7PQ5E751bWAHDLUu57fa4657wx+UX2wmDPE1kCK4DMNEffud6QZW0CzyyRpqbn3oUYSXxmTqM6bam17jQuug0DuDPfR+uxa40l2ZvOgdFFRjKWcIfeAg5JQ4W2bHO7ZOphQazJ1FTfhy/HIrImzJ9ZVGif/L4qL8RVHHVAYBeFAlU5i38FAgMBAAGjgfAwge0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtVrNzXEMIOqYjnME8GCCsGAQUFBwEBBEMwQTAcBggrBgEFBQcwAYYQaHR0cDovL28uc3MyLnVzLzAhBggrBgEFBQcwAoYVaHR0cDovL3guc3MyLnVzL3guY2VyMCYGA1UdHwQfMB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBACMd44pXyn3pF3lM8R5V/cxTbj5HD9/GVfKyBDbtgB9TxF00KGu+x1X8Z+rLP3+QsjPNG1gQggL4+C/1E2DUBc7xgQjB3ad1l08YuW3e95ORCLp+QCztweq7dp4zBncdDQh/U90bZKuCJ/Fp1U1ervShw3WnWEQt8jxwmKy6abaVd38PMV4s/KCHOkdp8Hlf9BRUpJVeEXgSYCfOn8J3/yNTd126/+pZ59vPr5KW7ySaNRB6nJHGDn2Z9j8Z3/VyVOEVqQdZe4O/Ui5GjLIAZHYcSNPYeehuVsyuLAOQ1xk4meTKCRlb/weWsKh/NEnfVqn3sF/tM+2MR7cwA130A4w=", + "RawTBSCertificate": "MIIDXaADAgECAgkApw5KTDSCt38wDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA5MDkwMjAwMDAwMFoXDTM0MDYyODE3MzkxNlowgZgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaOB8DCB7TAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUnF8A36oB1zArOIiiuG1KnPIRkYMwHwYDVR0jBBgwFoAUv1+30c7dH4b0W1Ws3NcQwg6piOcwTwYIKwYBBQUHAQEEQzBBMBwGCCsGAQUFBzABhhBodHRwOi8vby5zczIudXMvMCEGCCsGAQUFBzAChhVodHRwOi8veC5zczIudXMveC5jZXIwJgYDVR0fBB8wHTAboBmgF4YVaHR0cDovL3Muc3MyLnVzL3IuY3JsMBEGA1UdIAQKMAgwBgYEVR0gAA==", + "RawSubjectPublicKeyInfo": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Qw6xCr5TuL1vhmXX46IU7EfP8vPnyATbSk6yA99PPdrdjhj2TZgqJteXACAsi9Zf/aH+SVDhudpG1KakOFx49gtDU5v9shJ2bbzGlauK7Z0FOvP+ybjGrodli5qO1iUiUdW/yWgk3BTg9qEdBTDZ54EaDrfjkBaHUpOz0ORO+dW1gBwy1Lue32uOue8MflF9sJgzxNZAiuAzDRH37nekGVtAs8skaam596FGEl8Zk6jOm2pte40LroNA7gz30frsWuNJdmbzoHRRUYylnCH3gIOSUOFtmxzu2TqYUGsydRU34cvxyKyJsyfWVRon/y+Ki/EVRx1QGAXhQJVOYt/BQIDAQAB", + "RawSubject": "MIGYMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZpZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzI=", + "RawIssuer": "MGgxCzAJBgNVBAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==", + "Signature": "Ix3jilfKfekXeUzxHlX9zFNuPkcP38ZV8rIENu2AH1PEXTQoa77HVfxn6ss/f5CyM80bWBCCAvj4L/UTYNQFzvGBCMHdp3WXTxi5bd73k5EIun5ALO3B6rt2njMGdx0NCH9T3Rtkq4In8WnVTV6u9KHDdadYRC3yPHCYrLpptpV3fw8xXiz8oIc6R2nweV/0FFSklV4ReBJgJ86fwnf/I1N3Xbr/6lnn28+vkpbvJJo1EHqckcYOfZn2Pxnf9XJU4RWpB1l7g79SLkaMsgBkdhxI09h56G5WzK4sA5DXGTiZ5MoJGVv/B5awqH80Sd9WqfewX+0z7YxHtzADXfQDjA==", + "SignatureAlgorithm": 4, + "PublicKeyAlgorithm": 1, + "PublicKey": { + "N": "26894789576491863019171445242018370132029525033879210664513024255165308689836081694724912552986436241602345929261854187816625921774943728567119070351838976265193901442169339571326613928339955106648223197498035701437846440970934704192382084561469274550003268570741310868032789070264835003681318445644941362885752628282968349509706358865971392279088395067847314610178969555804359319567178098112935181143559364150874524817692694181296058297355335204675211145990489303168553611700020424738364579606192390834705213026692659672388567853246354560726855054573503174641583891075106464210711468427779853334564691648681991700229", + "E": 65537 + }, + "Version": 3, + "SerialNumber": 12037640545166866303, + "Issuer": { + "Country": [ + "US" + ], + "Organization": [ + "Starfield Technologies, Inc." + ], + "OrganizationalUnit": [ + "Starfield Class 2 Certification Authority" + ], + "Locality": null, + "Province": null, + "StreetAddress": null, + "PostalCode": null, + "SerialNumber": "", + "CommonName": "", + "Names": [ + { + "Type": [ + 2, + 5, + 4, + 6 + ], + "Value": "US" + }, + { + "Type": [ + 2, + 5, + 4, + 10 + ], + "Value": "Starfield Technologies, Inc." + }, + { + "Type": [ + 2, + 5, + 4, + 11 + ], + "Value": "Starfield Class 2 Certification Authority" + } + ], + "ExtraNames": null + }, + "Subject": { + "Country": [ + "US" + ], + "Organization": [ + "Starfield Technologies, Inc." + ], + "OrganizationalUnit": null, + "Locality": [ + "Scottsdale" + ], + "Province": [ + "Arizona" + ], + "StreetAddress": null, + "PostalCode": null, + "SerialNumber": "", + "CommonName": "Starfield Services Root Certificate Authority - G2", + "Names": [ + { + "Type": [ + 2, + 5, + 4, + 6 + ], + "Value": "US" + }, + { + "Type": [ + 2, + 5, + 4, + 8 + ], + "Value": "Arizona" + }, + { + "Type": [ + 2, + 5, + 4, + 7 + ], + "Value": "Scottsdale" + }, + { + "Type": [ + 2, + 5, + 4, + 10 + ], + "Value": "Starfield Technologies, Inc." + }, + { + "Type": [ + 2, + 5, + 4, + 3 + ], + "Value": "Starfield Services Root Certificate Authority - G2" + } + ], + "ExtraNames": null + }, + "NotBefore": "2009-09-02T00:00:00Z", + "NotAfter": "2034-06-28T17:39:16Z", + "KeyUsage": 97, + "Extensions": [ + { + "Id": [ + 2, + 5, + 29, + 19 + ], + "Critical": true, + "Value": "MAMBAf8=" + }, + { + "Id": [ + 2, + 5, + 29, + 15 + ], + "Critical": true, + "Value": "AwIBhg==" + }, + { + "Id": [ + 2, + 5, + 29, + 14 + ], + "Critical": false, + "Value": "BBScXwDfqgHXMCs4iKK4bUqc8hGRgw==" + }, + { + "Id": [ + 2, + 5, + 29, + 35 + ], + "Critical": false, + "Value": "MBaAFL9ft9HO3R+G9FtVrNzXEMIOqYjn" + }, + { + "Id": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 1, + 1 + ], + "Critical": false, + "Value": "MEEwHAYIKwYBBQUHMAGGEGh0dHA6Ly9vLnNzMi51cy8wIQYIKwYBBQUHMAKGFWh0dHA6Ly94LnNzMi51cy94LmNlcg==" + }, + { + "Id": [ + 2, + 5, + 29, + 31 + ], + "Critical": false, + "Value": "MB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybA==" + }, + { + "Id": [ + 2, + 5, + 29, + 32 + ], + "Critical": false, + "Value": "MAgwBgYEVR0gAA==" + } + ], + "ExtraExtensions": null, + "UnhandledCriticalExtensions": null, + "ExtKeyUsage": null, + "UnknownExtKeyUsage": null, + "BasicConstraintsValid": true, + "IsCA": true, + "MaxPathLen": -1, + "MaxPathLenZero": false, + "SubjectKeyId": "nF8A36oB1zArOIiiuG1KnPIRkYM=", + "AuthorityKeyId": "v1+30c7dH4b0W1Ws3NcQwg6piOc=", + "OCSPServer": [ + "http://o.ss2.us/" + ], + "IssuingCertificateURL": [ + "http://x.ss2.us/x.cer" + ], + "DNSNames": null, + "EmailAddresses": null, + "IPAddresses": null, + "URIs": null, + "PermittedDNSDomainsCritical": false, + "PermittedDNSDomains": null, + "ExcludedDNSDomains": null, + "PermittedIPRanges": null, + "ExcludedIPRanges": null, + "PermittedEmailAddresses": null, + "ExcludedEmailAddresses": null, + "PermittedURIDomains": null, + "ExcludedURIDomains": null, + "CRLDistributionPoints": [ + "http://s.ss2.us/r.crl" + ], + "PolicyIdentifiers": [ + [ + 2, + 5, + 29, + 32, + 0 + ] + ] + } + ], + "VerifiedChains": null, + "SignedCertificateTimestamps": null, + "OCSPResponse": null, + "TLSUnique": "uRDxMw0NqFZwym3Y" + } + }, + "ErrType": "", + "ErrMsg": "" + } + ] +} \ No newline at end of file diff --git a/backend/pkg/models/medical_encounter.go b/backend/pkg/models/medical_encounter.go index 26f7d732..8ca294cd 100644 --- a/backend/pkg/models/medical_encounter.go +++ b/backend/pkg/models/medical_encounter.go @@ -13,8 +13,8 @@ type Encounter struct { //Diagnoses []Diagnosis `json:"diagnoses,omitempty"` // diagnoses Array[Object] (optional) A list of diagnoses for the encounter where object contains a "name" field e.g. *[{"name": "Sacroiliac dysfunction"}, {"name": "Bilateral hand pain"}] //vitals Object (optional) Vitals captured during the encounter (e.g. {"temperature" : 95.2 [degF]","weight" : 180 [lb_av]","height" : "69 [in_us]"}) //vitalSigns Array[Object] (optional) A list of vital signs from the encounter (see link object) - Reasons []string `json:"reasons,omitempty"` // reasons Array[String] (optional) A list of reasons for the encounter (e.g. [‘Follow-up’, 'Consult’, 'DYSPHONIA', 'Back Pain’]) - Orders []Order `json:"orders,omitempty" gorm:"serializer:json;default:'{}'"` // orders Array[Object] (optional) A list of medication orders for the patient (see orders object) + Reasons []string `json:"reasons,omitempty" gorm:"serializer:json;default:'[]'"` // reasons Array[String] (optional) A list of reasons for the encounter (e.g. [‘Follow-up’, 'Consult’, 'DYSPHONIA', 'Back Pain’]) + Orders []Order `json:"orders,omitempty" gorm:"serializer:json;default:'{}'"` // orders Array[Object] (optional) A list of medication orders for the patient (see orders object) //testResults Array[Object] (optional) A list of test results for the patient (see link object) //plansOfCare Array[Object] (optional) A list of plans of care from the encounter (see link object) //medications Array[Object] (optional) A list of medications used by the patient. Objects in array can have some or many of the properties of medications. Common properties are "name", "productName", "startDate", "endDate", "instructions". diff --git a/go.mod b/go.mod index a3b68f50..59843189 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,13 @@ go 1.18 require ( github.com/analogj/go-util v0.0.0-20210417161720-39b497cca03b - github.com/fastenhealth/gofhir-models v0.0.3 + github.com/fastenhealth/gofhir-models v0.0.4 github.com/gin-gonic/gin v1.8.1 github.com/glebarez/sqlite v1.4.6 github.com/golang/mock v1.4.4 github.com/google/uuid v1.3.0 + github.com/samber/lo v1.27.1 + github.com/seborama/govcr v4.5.0+incompatible github.com/sirupsen/logrus v1.9.0 github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.7.1 @@ -55,6 +57,7 @@ require ( github.com/ugorji/go/codec v1.2.7 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect