From 63cdb81e2cfd3e3f2d5514b4664ea4117505c4e3 Mon Sep 17 00:00:00 2001 From: Gabe Lyons Date: Mon, 30 Dec 2024 10:57:55 -0800 Subject: [PATCH 01/10] feat(data transform): adding dataTransformLogic models (#12198) --- .../mappers/DataTransformLogicMapper.java | 73 +++++++++++ .../common/mappers/QueryPropertiesMapper.java | 61 +++++++++ .../graphql/types/datajob/DataJobType.java | 3 +- .../types/datajob/mappers/DataJobMapper.java | 24 +--- .../graphql/types/query/QueryMapper.java | 43 +------ .../src/main/resources/entity.graphql | 25 ++++ .../mappers/DataTransformLogicMapperTest.java | 103 +++++++++++++++ .../mappers/QueryPropertiesMapperTest.java | 121 ++++++++++++++++++ .../java/com/linkedin/metadata/Constants.java | 1 + .../com/linkedin/common/DataTransform.pdl | 13 ++ .../linkedin/common/DataTransformLogic.pdl | 14 ++ .../src/main/resources/entity-registry.yml | 1 + 12 files changed, 424 insertions(+), 58 deletions(-) create mode 100644 datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/DataTransformLogicMapper.java create mode 100644 datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapper.java create mode 100644 datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/DataTransformLogicMapperTest.java create mode 100644 datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapperTest.java create mode 100644 metadata-models/src/main/pegasus/com/linkedin/common/DataTransform.pdl create mode 100644 metadata-models/src/main/pegasus/com/linkedin/common/DataTransformLogic.pdl diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/DataTransformLogicMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/DataTransformLogicMapper.java new file mode 100644 index 00000000000000..04602e7ff6dde9 --- /dev/null +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/DataTransformLogicMapper.java @@ -0,0 +1,73 @@ +package com.linkedin.datahub.graphql.types.common.mappers; + +import com.linkedin.datahub.graphql.QueryContext; +import com.linkedin.datahub.graphql.generated.DataTransform; +import com.linkedin.datahub.graphql.generated.DataTransformLogic; +import com.linkedin.datahub.graphql.generated.QueryLanguage; +import com.linkedin.datahub.graphql.generated.QueryStatement; +import com.linkedin.datahub.graphql.types.mappers.ModelMapper; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class DataTransformLogicMapper + implements ModelMapper< + com.linkedin.common.DataTransformLogic, + com.linkedin.datahub.graphql.generated.DataTransformLogic> { + + public static final DataTransformLogicMapper INSTANCE = new DataTransformLogicMapper(); + + public static DataTransformLogic map( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.DataTransformLogic input) { + return INSTANCE.apply(context, input); + } + + @Override + public DataTransformLogic apply( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.DataTransformLogic input) { + + final DataTransformLogic result = new DataTransformLogic(); + + // Map transforms array using DataTransformMapper + result.setTransforms( + input.getTransforms().stream() + .map(transform -> DataTransformMapper.map(context, transform)) + .collect(Collectors.toList())); + + return result; + } +} + +class DataTransformMapper + implements ModelMapper< + com.linkedin.common.DataTransform, com.linkedin.datahub.graphql.generated.DataTransform> { + + public static final DataTransformMapper INSTANCE = new DataTransformMapper(); + + public static DataTransform map( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.DataTransform input) { + return INSTANCE.apply(context, input); + } + + @Override + public DataTransform apply( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.DataTransform input) { + + final DataTransform result = new DataTransform(); + + // Map query statement if present + if (input.hasQueryStatement()) { + QueryStatement statement = + new QueryStatement( + input.getQueryStatement().getValue(), + QueryLanguage.valueOf(input.getQueryStatement().getLanguage().toString())); + result.setQueryStatement(statement); + } + + return result; + } +} diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapper.java new file mode 100644 index 00000000000000..e29bea5b3943ce --- /dev/null +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapper.java @@ -0,0 +1,61 @@ +package com.linkedin.datahub.graphql.types.common.mappers; + +import com.linkedin.data.template.GetMode; +import com.linkedin.datahub.graphql.QueryContext; +import com.linkedin.datahub.graphql.generated.*; +import com.linkedin.datahub.graphql.types.mappers.ModelMapper; +import com.linkedin.query.QueryProperties; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class QueryPropertiesMapper + implements ModelMapper< + QueryProperties, com.linkedin.datahub.graphql.generated.QueryProperties> { + + public static final QueryPropertiesMapper INSTANCE = new QueryPropertiesMapper(); + + public static com.linkedin.datahub.graphql.generated.QueryProperties map( + @Nullable final QueryContext context, @Nonnull final QueryProperties input) { + return INSTANCE.apply(context, input); + } + + @Override + public com.linkedin.datahub.graphql.generated.QueryProperties apply( + @Nullable final QueryContext context, @Nonnull final QueryProperties input) { + + final com.linkedin.datahub.graphql.generated.QueryProperties result = + new com.linkedin.datahub.graphql.generated.QueryProperties(); + + // Map Query Source + result.setSource(QuerySource.valueOf(input.getSource().toString())); + + // Map Query Statement + result.setStatement( + new QueryStatement( + input.getStatement().getValue(), + QueryLanguage.valueOf(input.getStatement().getLanguage().toString()))); + + // Map optional fields + result.setName(input.getName(GetMode.NULL)); + result.setDescription(input.getDescription(GetMode.NULL)); + + // Map origin if present + if (input.hasOrigin() && input.getOrigin() != null) { + result.setOrigin(UrnToEntityMapper.map(context, input.getOrigin())); + } + + // Map created audit stamp + AuditStamp created = new AuditStamp(); + created.setTime(input.getCreated().getTime()); + created.setActor(input.getCreated().getActor(GetMode.NULL).toString()); + result.setCreated(created); + + // Map last modified audit stamp + AuditStamp lastModified = new AuditStamp(); + lastModified.setTime(input.getLastModified().getTime()); + lastModified.setActor(input.getLastModified().getActor(GetMode.NULL).toString()); + result.setLastModified(lastModified); + + return result; + } +} diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java index b32832a28d5d57..8d55ca6dbf7ac9 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java @@ -79,7 +79,8 @@ public class DataJobType BROWSE_PATHS_V2_ASPECT_NAME, SUB_TYPES_ASPECT_NAME, STRUCTURED_PROPERTIES_ASPECT_NAME, - FORMS_ASPECT_NAME); + FORMS_ASPECT_NAME, + DATA_TRANSFORM_LOGIC_ASPECT_NAME); private static final Set FACET_FIELDS = ImmutableSet.of("flow"); private final EntityClient _entityClient; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/mappers/DataJobMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/mappers/DataJobMapper.java index 772871d77f2175..ec57c95ce151e2 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/mappers/DataJobMapper.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/mappers/DataJobMapper.java @@ -4,16 +4,7 @@ import static com.linkedin.metadata.Constants.*; import com.google.common.collect.ImmutableList; -import com.linkedin.common.BrowsePathsV2; -import com.linkedin.common.DataPlatformInstance; -import com.linkedin.common.Deprecation; -import com.linkedin.common.Forms; -import com.linkedin.common.GlobalTags; -import com.linkedin.common.GlossaryTerms; -import com.linkedin.common.InstitutionalMemory; -import com.linkedin.common.Ownership; -import com.linkedin.common.Status; -import com.linkedin.common.SubTypes; +import com.linkedin.common.*; import com.linkedin.common.urn.Urn; import com.linkedin.data.DataMap; import com.linkedin.datahub.graphql.QueryContext; @@ -26,15 +17,7 @@ import com.linkedin.datahub.graphql.generated.DataJobProperties; import com.linkedin.datahub.graphql.generated.Dataset; import com.linkedin.datahub.graphql.generated.EntityType; -import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper; -import com.linkedin.datahub.graphql.types.common.mappers.CustomPropertiesMapper; -import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper; -import com.linkedin.datahub.graphql.types.common.mappers.DeprecationMapper; -import com.linkedin.datahub.graphql.types.common.mappers.FineGrainedLineagesMapper; -import com.linkedin.datahub.graphql.types.common.mappers.InstitutionalMemoryMapper; -import com.linkedin.datahub.graphql.types.common.mappers.OwnershipMapper; -import com.linkedin.datahub.graphql.types.common.mappers.StatusMapper; -import com.linkedin.datahub.graphql.types.common.mappers.SubTypesMapper; +import com.linkedin.datahub.graphql.types.common.mappers.*; import com.linkedin.datahub.graphql.types.common.mappers.util.SystemMetadataUtils; import com.linkedin.datahub.graphql.types.domain.DomainAssociationMapper; import com.linkedin.datahub.graphql.types.form.FormsMapper; @@ -139,6 +122,9 @@ public DataJob apply( context, new StructuredProperties(data), entityUrn)); } else if (FORMS_ASPECT_NAME.equals(name)) { result.setForms(FormsMapper.map(new Forms(data), entityUrn.toString())); + } else if (DATA_TRANSFORM_LOGIC_ASPECT_NAME.equals(name)) { + result.setDataTransformLogic( + DataTransformLogicMapper.map(context, new DataTransformLogic(data))); } }); diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/query/QueryMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/query/QueryMapper.java index e71b569e9ae238..916ebc772f545f 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/query/QueryMapper.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/query/QueryMapper.java @@ -5,18 +5,13 @@ import com.linkedin.common.DataPlatformInstance; import com.linkedin.common.urn.Urn; import com.linkedin.data.DataMap; -import com.linkedin.data.template.GetMode; import com.linkedin.datahub.graphql.QueryContext; -import com.linkedin.datahub.graphql.generated.AuditStamp; import com.linkedin.datahub.graphql.generated.DataPlatform; import com.linkedin.datahub.graphql.generated.Dataset; import com.linkedin.datahub.graphql.generated.EntityType; import com.linkedin.datahub.graphql.generated.QueryEntity; -import com.linkedin.datahub.graphql.generated.QueryLanguage; -import com.linkedin.datahub.graphql.generated.QuerySource; -import com.linkedin.datahub.graphql.generated.QueryStatement; import com.linkedin.datahub.graphql.generated.QuerySubject; -import com.linkedin.datahub.graphql.types.common.mappers.UrnToEntityMapper; +import com.linkedin.datahub.graphql.types.common.mappers.QueryPropertiesMapper; import com.linkedin.datahub.graphql.types.common.mappers.util.MappingHelper; import com.linkedin.datahub.graphql.types.mappers.ModelMapper; import com.linkedin.entity.EntityResponse; @@ -48,7 +43,10 @@ public QueryEntity apply( result.setType(EntityType.QUERY); EnvelopedAspectMap aspectMap = entityResponse.getAspects(); MappingHelper mappingHelper = new MappingHelper<>(aspectMap, result); - mappingHelper.mapToResult(context, QUERY_PROPERTIES_ASPECT_NAME, this::mapQueryProperties); + mappingHelper.mapToResult( + QUERY_PROPERTIES_ASPECT_NAME, + (entity, dataMap) -> + entity.setProperties(QueryPropertiesMapper.map(context, new QueryProperties(dataMap)))); mappingHelper.mapToResult(QUERY_SUBJECTS_ASPECT_NAME, this::mapQuerySubjects); mappingHelper.mapToResult(DATA_PLATFORM_INSTANCE_ASPECT_NAME, this::mapPlatform); return mappingHelper.getResult(); @@ -64,37 +62,6 @@ private void mapPlatform(@Nonnull QueryEntity query, @Nonnull DataMap dataMap) { } } - private void mapQueryProperties( - @Nullable final QueryContext context, @Nonnull QueryEntity query, @Nonnull DataMap dataMap) { - QueryProperties queryProperties = new QueryProperties(dataMap); - com.linkedin.datahub.graphql.generated.QueryProperties res = - new com.linkedin.datahub.graphql.generated.QueryProperties(); - - // Query Source must be kept in sync. - res.setSource(QuerySource.valueOf(queryProperties.getSource().toString())); - res.setStatement( - new QueryStatement( - queryProperties.getStatement().getValue(), - QueryLanguage.valueOf(queryProperties.getStatement().getLanguage().toString()))); - res.setName(queryProperties.getName(GetMode.NULL)); - res.setDescription(queryProperties.getDescription(GetMode.NULL)); - if (queryProperties.hasOrigin() && queryProperties.getOrigin() != null) { - res.setOrigin(UrnToEntityMapper.map(context, queryProperties.getOrigin())); - } - - AuditStamp created = new AuditStamp(); - created.setTime(queryProperties.getCreated().getTime()); - created.setActor(queryProperties.getCreated().getActor(GetMode.NULL).toString()); - res.setCreated(created); - - AuditStamp lastModified = new AuditStamp(); - lastModified.setTime(queryProperties.getLastModified().getTime()); - lastModified.setActor(queryProperties.getLastModified().getActor(GetMode.NULL).toString()); - res.setLastModified(lastModified); - - query.setProperties(res); - } - @Nonnull private void mapQuerySubjects(@Nonnull QueryEntity query, @Nonnull DataMap dataMap) { QuerySubjects querySubjects = new QuerySubjects(dataMap); diff --git a/datahub-graphql-core/src/main/resources/entity.graphql b/datahub-graphql-core/src/main/resources/entity.graphql index 9abf4e16f12dd7..a5cb0893a64fae 100644 --- a/datahub-graphql-core/src/main/resources/entity.graphql +++ b/datahub-graphql-core/src/main/resources/entity.graphql @@ -6569,6 +6569,11 @@ type DataJob implements EntityWithRelationships & Entity & BrowsableEntity { The forms associated with the Dataset """ forms: Forms + + """ + Data Transform Logic associated with the Data Job + """ + dataTransformLogic: DataTransformLogic } """ @@ -6786,6 +6791,26 @@ type DataJobInputOutput { fineGrainedLineages: [FineGrainedLineage!] } +""" +Information about a transformation applied to data assets +""" +type DataTransform { + """ + The transformation may be defined by a query statement + """ + queryStatement: QueryStatement +} + +""" +Information about transformations applied to data assets +""" +type DataTransformLogic { + """ + List of transformations applied + """ + transforms: [DataTransform!]! +} + """ Information about individual user usage of a Dataset """ diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/DataTransformLogicMapperTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/DataTransformLogicMapperTest.java new file mode 100644 index 00000000000000..f94738ff049efb --- /dev/null +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/DataTransformLogicMapperTest.java @@ -0,0 +1,103 @@ +package com.linkedin.datahub.graphql.types.common.mappers; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + +import com.linkedin.common.DataTransform; +import com.linkedin.common.DataTransformArray; +import com.linkedin.common.DataTransformLogic; +import com.linkedin.query.QueryLanguage; +import com.linkedin.query.QueryStatement; +import java.util.Arrays; +import org.testng.annotations.Test; + +public class DataTransformLogicMapperTest { + + @Test + public void testMapWithQueryStatement() throws Exception { + // Create test data + DataTransformLogic input = new DataTransformLogic(); + + // Create a transform with query statement + DataTransform transform1 = new DataTransform(); + QueryStatement statement = new QueryStatement(); + statement.setValue("SELECT * FROM source_table"); + statement.setLanguage(QueryLanguage.SQL); + transform1.setQueryStatement(statement); + + // Create another transform + DataTransform transform2 = new DataTransform(); + QueryStatement statement2 = new QueryStatement(); + statement2.setValue("INSERT INTO target_table SELECT * FROM temp_table"); + statement2.setLanguage(QueryLanguage.SQL); + transform2.setQueryStatement(statement2); + + // Set transforms + input.setTransforms(new DataTransformArray(Arrays.asList(transform1, transform2))); + + // Map the object + com.linkedin.datahub.graphql.generated.DataTransformLogic result = + DataTransformLogicMapper.map(null, input); + + // Verify result + assertNotNull(result); + assertEquals(result.getTransforms().size(), 2); + + // Verify first transform + com.linkedin.datahub.graphql.generated.DataTransform resultTransform1 = + result.getTransforms().get(0); + assertNotNull(resultTransform1.getQueryStatement()); + assertEquals(resultTransform1.getQueryStatement().getValue(), "SELECT * FROM source_table"); + assertEquals(resultTransform1.getQueryStatement().getLanguage().toString(), "SQL"); + + // Verify second transform + com.linkedin.datahub.graphql.generated.DataTransform resultTransform2 = + result.getTransforms().get(1); + assertNotNull(resultTransform2.getQueryStatement()); + assertEquals( + resultTransform2.getQueryStatement().getValue(), + "INSERT INTO target_table SELECT * FROM temp_table"); + assertEquals(resultTransform2.getQueryStatement().getLanguage().toString(), "SQL"); + } + + @Test + public void testMapWithoutQueryStatement() throws Exception { + // Create test data + DataTransformLogic input = new DataTransformLogic(); + + // Create a transform without query statement + DataTransform transform = new DataTransform(); + + // Set transforms + input.setTransforms(new DataTransformArray(Arrays.asList(transform))); + + // Map the object + com.linkedin.datahub.graphql.generated.DataTransformLogic result = + DataTransformLogicMapper.map(null, input); + + // Verify result + assertNotNull(result); + assertEquals(result.getTransforms().size(), 1); + + // Verify transform + com.linkedin.datahub.graphql.generated.DataTransform resultTransform = + result.getTransforms().get(0); + assertNull(resultTransform.getQueryStatement()); + } + + @Test + public void testMapWithEmptyTransforms() throws Exception { + // Create test data + DataTransformLogic input = new DataTransformLogic(); + input.setTransforms(new DataTransformArray(Arrays.asList())); + + // Map the object + com.linkedin.datahub.graphql.generated.DataTransformLogic result = + DataTransformLogicMapper.map(null, input); + + // Verify result + assertNotNull(result); + assertEquals(result.getTransforms().size(), 0); + } +} diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapperTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapperTest.java new file mode 100644 index 00000000000000..756115cf2054a9 --- /dev/null +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapperTest.java @@ -0,0 +1,121 @@ +package com.linkedin.datahub.graphql.types.common.mappers; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + +import com.linkedin.common.AuditStamp; +import com.linkedin.common.urn.Urn; +import com.linkedin.query.QueryLanguage; +import com.linkedin.query.QueryProperties; +import com.linkedin.query.QuerySource; +import com.linkedin.query.QueryStatement; +import org.testng.annotations.Test; + +public class QueryPropertiesMapperTest { + + @Test + public void testMapWithRequiredFields() throws Exception { + // Create test data + QueryProperties input = new QueryProperties(); + + // Set required fields + QueryStatement statement = new QueryStatement(); + statement.setValue("SELECT * FROM table"); + statement.setLanguage(QueryLanguage.SQL); + input.setStatement(statement); + + input.setSource(QuerySource.MANUAL); + + Urn userUrn = Urn.createFromString("urn:li:corpuser:test"); + + AuditStamp created = new AuditStamp(); + created.setTime(1000L); + created.setActor(userUrn); + input.setCreated(created); + + AuditStamp lastModified = new AuditStamp(); + lastModified.setTime(2000L); + lastModified.setActor(userUrn); + input.setLastModified(lastModified); + + // Map the object + com.linkedin.datahub.graphql.generated.QueryProperties result = + QueryPropertiesMapper.map(null, input); + + // Verify required fields + assertNotNull(result); + assertEquals(result.getSource().toString(), "MANUAL"); + assertEquals(result.getStatement().getValue(), "SELECT * FROM table"); + assertEquals(result.getStatement().getLanguage().toString(), "SQL"); + + // Verify audit stamps + assertEquals(result.getCreated().getTime().longValue(), 1000L); + assertEquals(result.getCreated().getActor(), userUrn.toString()); + assertEquals(result.getLastModified().getTime().longValue(), 2000L); + assertEquals(result.getLastModified().getActor(), userUrn.toString()); + + // Verify createdOn resolved stamp + assertEquals(result.getCreatedOn().getTime().longValue(), 1000L); + assertEquals(result.getCreatedOn().getActor().getUrn(), userUrn.toString()); + + // Verify optional fields are null + assertNull(result.getName()); + assertNull(result.getDescription()); + assertNull(result.getOrigin()); + } + + @Test + public void testMapWithOptionalFields() throws Exception { + // Create test data + QueryProperties input = new QueryProperties(); + + // Set required fields + QueryStatement statement = new QueryStatement(); + statement.setValue("SELECT * FROM table"); + statement.setLanguage(QueryLanguage.SQL); + input.setStatement(statement); + + input.setSource(QuerySource.SYSTEM); + + Urn userUrn = Urn.createFromString("urn:li:corpuser:test"); + Urn originUrn = Urn.createFromString("urn:li:dataset:test"); + + AuditStamp created = new AuditStamp(); + created.setTime(1000L); + created.setActor(userUrn); + input.setCreated(created); + + AuditStamp lastModified = new AuditStamp(); + lastModified.setTime(2000L); + lastModified.setActor(userUrn); + input.setLastModified(lastModified); + + // Set optional fields + input.setName("Test Query"); + input.setDescription("Test Description"); + input.setOrigin(originUrn); + + // Map the object + com.linkedin.datahub.graphql.generated.QueryProperties result = + QueryPropertiesMapper.map(null, input); + + // Verify required fields + assertNotNull(result); + assertEquals(result.getSource().toString(), "SYSTEM"); + assertEquals(result.getStatement().getValue(), "SELECT * FROM table"); + assertEquals(result.getStatement().getLanguage().toString(), "SQL"); + + // Verify audit stamps + assertEquals(result.getCreated().getTime().longValue(), 1000L); + assertEquals(result.getCreated().getActor(), userUrn.toString()); + assertEquals(result.getLastModified().getTime().longValue(), 2000L); + assertEquals(result.getLastModified().getActor(), userUrn.toString()); + + // Verify optional fields + assertEquals(result.getName(), "Test Query"); + assertEquals(result.getDescription(), "Test Description"); + assertNotNull(result.getOrigin()); + assertEquals(result.getOrigin().getUrn(), originUrn.toString()); + } +} diff --git a/li-utils/src/main/java/com/linkedin/metadata/Constants.java b/li-utils/src/main/java/com/linkedin/metadata/Constants.java index 09f873ebf7bc96..42080e4e17596e 100644 --- a/li-utils/src/main/java/com/linkedin/metadata/Constants.java +++ b/li-utils/src/main/java/com/linkedin/metadata/Constants.java @@ -127,6 +127,7 @@ public class Constants { public static final String EMBED_ASPECT_NAME = "embed"; public static final String INCIDENTS_SUMMARY_ASPECT_NAME = "incidentsSummary"; public static final String DOCUMENTATION_ASPECT_NAME = "documentation"; + public static final String DATA_TRANSFORM_LOGIC_ASPECT_NAME = "dataTransformLogic"; // User public static final String CORP_USER_KEY_ASPECT_NAME = "corpUserKey"; diff --git a/metadata-models/src/main/pegasus/com/linkedin/common/DataTransform.pdl b/metadata-models/src/main/pegasus/com/linkedin/common/DataTransform.pdl new file mode 100644 index 00000000000000..adc8d693b28e24 --- /dev/null +++ b/metadata-models/src/main/pegasus/com/linkedin/common/DataTransform.pdl @@ -0,0 +1,13 @@ +namespace com.linkedin.common + +import com.linkedin.query.QueryStatement + +/** + * Information about a transformation. It may be a query, + */ +record DataTransform { + /** + * The data transform may be defined by a query statement + */ + queryStatement: optional QueryStatement +} diff --git a/metadata-models/src/main/pegasus/com/linkedin/common/DataTransformLogic.pdl b/metadata-models/src/main/pegasus/com/linkedin/common/DataTransformLogic.pdl new file mode 100644 index 00000000000000..431cebf436ffbc --- /dev/null +++ b/metadata-models/src/main/pegasus/com/linkedin/common/DataTransformLogic.pdl @@ -0,0 +1,14 @@ +namespace com.linkedin.common + +/** + * Information about a Query against one or more data assets (e.g. Tables or Views). + */ +@Aspect = { + "name": "dataTransformLogic" +} +record DataTransformLogic { + /** + * List of transformations applied + */ + transforms: array[DataTransform], +} diff --git a/metadata-models/src/main/resources/entity-registry.yml b/metadata-models/src/main/resources/entity-registry.yml index 4fe170ced69f33..0193e5e2c5c6c3 100644 --- a/metadata-models/src/main/resources/entity-registry.yml +++ b/metadata-models/src/main/resources/entity-registry.yml @@ -76,6 +76,7 @@ entities: - subTypes - incidentsSummary - testResults + - dataTransformLogic - name: dataFlow category: core keyAspect: dataFlowKey From abb64433fc7a1d5e7c852ee65675c8abebd8fda1 Mon Sep 17 00:00:00 2001 From: Gabe Lyons Date: Mon, 30 Dec 2024 13:32:28 -0800 Subject: [PATCH 02/10] fix(tests): fixing QueryPropertiesMapperTest.java (#12241) --- .../types/common/mappers/QueryPropertiesMapperTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapperTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapperTest.java index 756115cf2054a9..a0251adca78f9d 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapperTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/common/mappers/QueryPropertiesMapperTest.java @@ -55,10 +55,6 @@ public void testMapWithRequiredFields() throws Exception { assertEquals(result.getLastModified().getTime().longValue(), 2000L); assertEquals(result.getLastModified().getActor(), userUrn.toString()); - // Verify createdOn resolved stamp - assertEquals(result.getCreatedOn().getTime().longValue(), 1000L); - assertEquals(result.getCreatedOn().getActor().getUrn(), userUrn.toString()); - // Verify optional fields are null assertNull(result.getName()); assertNull(result.getDescription()); From ee54f1fb6181c85a85194dde7cc86ab7af5745b7 Mon Sep 17 00:00:00 2001 From: david-leifker <114954101+david-leifker@users.noreply.github.com> Date: Mon, 30 Dec 2024 17:44:09 -0600 Subject: [PATCH 03/10] feat(delete): delete logic non-strict monotonically increasing version (#12242) --- .../linkedin/metadata/entity/AspectDao.java | 11 ++ .../metadata/entity/EntityServiceImpl.java | 18 ++- .../entity/cassandra/CassandraAspectDao.java | 33 ++++-- .../metadata/entity/ebean/EbeanAspectDao.java | 53 ++++++--- .../metadata/entity/EntityServiceTest.java | 105 ++++++++++++++++++ 5 files changed, 188 insertions(+), 32 deletions(-) diff --git a/metadata-io/src/main/java/com/linkedin/metadata/entity/AspectDao.java b/metadata-io/src/main/java/com/linkedin/metadata/entity/AspectDao.java index 7a8c5c76c31c3a..0d5bdd9ff64286 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/entity/AspectDao.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/entity/AspectDao.java @@ -6,6 +6,7 @@ import com.linkedin.metadata.entity.ebean.PartitionedStream; import com.linkedin.metadata.entity.restoreindices.RestoreIndicesArgs; import com.linkedin.metadata.utils.metrics.MetricUtils; +import com.linkedin.util.Pair; import java.sql.Timestamp; import java.util.List; import java.util.Map; @@ -155,6 +156,16 @@ default Map getNextVersions( long getMaxVersion(@Nonnull final String urn, @Nonnull final String aspectName); + /** + * Return the min/max version for the given URN & aspect + * + * @param urn the urn + * @param aspectName the aspect + * @return the range of versions, if they do not exist -1 is returned + */ + @Nonnull + Pair getVersionRange(@Nonnull final String urn, @Nonnull final String aspectName); + void setWritable(boolean canWrite); @Nonnull diff --git a/metadata-io/src/main/java/com/linkedin/metadata/entity/EntityServiceImpl.java b/metadata-io/src/main/java/com/linkedin/metadata/entity/EntityServiceImpl.java index 8ae09111204cab..75f16ae4d981d2 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/entity/EntityServiceImpl.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/entity/EntityServiceImpl.java @@ -2229,8 +2229,9 @@ public Set exists( } /** Does not emit MCL */ + @VisibleForTesting @Nullable - private RollbackResult deleteAspectWithoutMCL( + RollbackResult deleteAspectWithoutMCL( @Nonnull OperationContext opContext, String urn, String aspectName, @@ -2288,11 +2289,14 @@ private RollbackResult deleteAspectWithoutMCL( // 4. Fetch all preceding aspects, that match List aspectsToDelete = new ArrayList<>(); - long maxVersion = aspectDao.getMaxVersion(urn, aspectName); + Pair versionRange = aspectDao.getVersionRange(urn, aspectName); + long minVersion = Math.max(0, versionRange.getFirst()); + long maxVersion = Math.max(0, versionRange.getSecond()); + EntityAspect.EntitySystemAspect survivingAspect = null; - String previousMetadata = null; + boolean filterMatch = true; - while (maxVersion > 0 && filterMatch) { + while (maxVersion > minVersion && filterMatch) { EntityAspect.EntitySystemAspect candidateAspect = (EntityAspect.EntitySystemAspect) EntityUtils.toSystemAspect( @@ -2305,11 +2309,13 @@ private RollbackResult deleteAspectWithoutMCL( previousSysMetadata != null && filterMatch(previousSysMetadata, conditions); if (filterMatch) { aspectsToDelete.add(candidateAspect.getEntityAspect()); - maxVersion = maxVersion - 1; + } else if (candidateAspect == null) { + // potential gap + filterMatch = true; } else { survivingAspect = candidateAspect; - previousMetadata = survivingAspect.getMetadataRaw(); } + maxVersion = maxVersion - 1; } // Delete validation hooks diff --git a/metadata-io/src/main/java/com/linkedin/metadata/entity/cassandra/CassandraAspectDao.java b/metadata-io/src/main/java/com/linkedin/metadata/entity/cassandra/CassandraAspectDao.java index 4d177d50ea44de..c5a6615ac4face 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/entity/cassandra/CassandraAspectDao.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/entity/cassandra/CassandraAspectDao.java @@ -36,6 +36,7 @@ import com.linkedin.metadata.query.ExtraInfo; import com.linkedin.metadata.query.ExtraInfoArray; import com.linkedin.metadata.query.ListResultMetadata; +import com.linkedin.util.Pair; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.sql.Timestamp; @@ -110,7 +111,14 @@ public Map> getLatestAspects( @Override public long getMaxVersion(@Nonnull final String urn, @Nonnull final String aspectName) { validateConnection(); - Map result = getMaxVersions(urn, ImmutableSet.of(aspectName)); + Map> result = getVersionRanges(urn, ImmutableSet.of(aspectName)); + return result.get(aspectName).getSecond(); + } + + @Override + @Nonnull + public Pair getVersionRange(@Nonnull String urn, @Nonnull String aspectName) { + Map> result = getVersionRanges(urn, ImmutableSet.of(aspectName)); return result.get(aspectName); } @@ -148,15 +156,17 @@ public boolean checkIfAspectExists(@Nonnull String aspectName) { return rs.one() != null; } - private Map getMaxVersions( + private Map> getVersionRanges( @Nonnull final String urn, @Nonnull final Set aspectNames) { SimpleStatement ss = selectFrom(CassandraAspect.TABLE_NAME) .selectors( Selector.column(CassandraAspect.URN_COLUMN), Selector.column(CassandraAspect.ASPECT_COLUMN), + Selector.function("min", Selector.column(CassandraAspect.VERSION_COLUMN)) + .as("min_version"), Selector.function("max", Selector.column(CassandraAspect.VERSION_COLUMN)) - .as(CassandraAspect.VERSION_COLUMN)) + .as("max_version")) .whereColumn(CassandraAspect.URN_COLUMN) .isEqualTo(literal(urn)) .whereColumn(CassandraAspect.ASPECT_COLUMN) @@ -168,21 +178,21 @@ private Map getMaxVersions( .build(); ResultSet rs = _cqlSession.execute(ss); - Map aspectVersions = + Map> aspectVersionRanges = rs.all().stream() .collect( Collectors.toMap( row -> row.getString(CassandraAspect.ASPECT_COLUMN), - row -> row.getLong(CassandraAspect.VERSION_COLUMN))); + row -> Pair.of(row.getLong("min_version"), row.getLong("max_version")))); - // For each requested aspect that didn't come back from DB, add a version -1 + // For each requested aspect that didn't come back from DB, add a version range of (-1, -1) for (String aspect : aspectNames) { - if (!aspectVersions.containsKey(aspect)) { - aspectVersions.put(aspect, -1L); + if (!aspectVersionRanges.containsKey(aspect)) { + aspectVersionRanges.put(aspect, Pair.of(-1L, -1L)); } } - return aspectVersions; + return aspectVersionRanges; } @Override @@ -551,11 +561,12 @@ public Map> getNextVersions(Map> u Map> result = new HashMap<>(); for (Map.Entry> aspectNames : urnAspectMap.entrySet()) { - Map maxVersions = getMaxVersions(aspectNames.getKey(), aspectNames.getValue()); + Map> maxVersions = + getVersionRanges(aspectNames.getKey(), aspectNames.getValue()); Map nextVersions = new HashMap<>(); for (String aspectName : aspectNames.getValue()) { - long latestVersion = maxVersions.get(aspectName); + long latestVersion = maxVersions.get(aspectName).getSecond(); long nextVal = latestVersion < 0 ? ASPECT_LATEST_VERSION : latestVersion + 1L; nextVersions.put(aspectName, nextVal); } diff --git a/metadata-io/src/main/java/com/linkedin/metadata/entity/ebean/EbeanAspectDao.java b/metadata-io/src/main/java/com/linkedin/metadata/entity/ebean/EbeanAspectDao.java index ea580a97c51886..ad8333407a2760 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/entity/ebean/EbeanAspectDao.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/entity/ebean/EbeanAspectDao.java @@ -38,6 +38,8 @@ import io.ebean.Query; import io.ebean.RawSql; import io.ebean.RawSqlBuilder; +import io.ebean.SqlQuery; +import io.ebean.SqlRow; import io.ebean.Transaction; import io.ebean.TxScope; import io.ebean.annotation.TxIsolation; @@ -247,10 +249,18 @@ private void saveEbeanAspect( @Nonnull final EbeanAspectV2 ebeanAspect, final boolean insert) { validateConnection(); - if (insert) { - _server.insert(ebeanAspect, txContext.tx()); + if (txContext != null && txContext.tx() != null) { + if (insert) { + _server.insert(ebeanAspect, txContext.tx()); + } else { + _server.update(ebeanAspect, txContext.tx()); + } } else { - _server.update(ebeanAspect, txContext.tx()); + if (insert) { + _server.insert(ebeanAspect); + } else { + _server.update(ebeanAspect); + } } } @@ -864,20 +874,33 @@ public T runInTransactionWithRetryUnlocked( } @Override - public long getMaxVersion(@Nonnull final String urn, @Nonnull final String aspectName) { + @Nonnull + public Pair getVersionRange( + @Nonnull final String urn, @Nonnull final String aspectName) { validateConnection(); - final List result = - _server - .find(EbeanAspectV2.class) - .where() - .eq(EbeanAspectV2.URN_COLUMN, urn.toString()) - .eq(EbeanAspectV2.ASPECT_COLUMN, aspectName) - .orderBy() - .desc(EbeanAspectV2.VERSION_COLUMN) - .setMaxRows(1) - .findIds(); - return result.isEmpty() ? -1 : result.get(0).getVersion(); + // Use SQL aggregation to get both min and max in a single query + SqlQuery query = + _server.sqlQuery( + "SELECT MIN(version) as min_version, MAX(version) as max_version " + + "FROM metadata_aspect_v2 " + + "WHERE urn = :urn AND aspect = :aspect"); + + query.setParameter("urn", urn); + query.setParameter("aspect", aspectName); + + SqlRow result = query.findOne(); + + if (result == null) { + return Pair.of(-1L, -1L); + } + + return Pair.of(result.getLong("min_version"), result.getLong("max_version")); + } + + @Override + public long getMaxVersion(@Nonnull final String urn, @Nonnull final String aspectName) { + return getVersionRange(urn, aspectName).getSecond(); } /** diff --git a/metadata-io/src/test/java/com/linkedin/metadata/entity/EntityServiceTest.java b/metadata-io/src/test/java/com/linkedin/metadata/entity/EntityServiceTest.java index c00632e5cf5424..6eda210baf7d4a 100644 --- a/metadata-io/src/test/java/com/linkedin/metadata/entity/EntityServiceTest.java +++ b/metadata-io/src/test/java/com/linkedin/metadata/entity/EntityServiceTest.java @@ -84,6 +84,8 @@ import io.datahubproject.metadata.context.OperationContext; import io.datahubproject.test.metadata.context.TestOperationContexts; import jakarta.annotation.Nonnull; +import java.sql.Timestamp; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -2670,6 +2672,109 @@ public void testPatchAddNonExistent() throws Exception { "Expected all tags"); } + @Test + public void testDeleteUrnWithRunIdFilterNonMatch() throws Exception { + Urn entityUrn = UrnUtils.getUrn("urn:li:corpuser:deleteWithFilterNonMatch"); + + // Create aspects with different run IDs + SystemMetadata metadata1 = AspectGenerationUtils.createSystemMetadata(); + metadata1.setRunId("run-123"); + + SystemMetadata metadata2 = AspectGenerationUtils.createSystemMetadata(); + metadata2.setRunId("run-456"); // Different run ID + + String aspectName = AspectGenerationUtils.getAspectName(new CorpUserInfo()); + + // First ingest the aspect that should survive (run-456) + CorpUserInfo writeAspect1 = AspectGenerationUtils.createCorpUserInfo("first@test.com"); + List> firstPair = new ArrayList<>(); + firstPair.add(getAspectRecordPair(writeAspect1, CorpUserInfo.class)); + _entityServiceImpl.ingestAspects(opContext, entityUrn, firstPair, TEST_AUDIT_STAMP, metadata2); + + // Then ingest the aspect that should be deleted (run-123) + CorpUserInfo writeAspect2 = AspectGenerationUtils.createCorpUserInfo("second@test.com"); + List> secondPair = new ArrayList<>(); + secondPair.add(getAspectRecordPair(writeAspect2, CorpUserInfo.class)); + _entityServiceImpl.ingestAspects(opContext, entityUrn, secondPair, TEST_AUDIT_STAMP, metadata1); + + // When we try to delete with runId=run-123, the version with runId=run-456 should survive + RollbackResult result = + _entityServiceImpl.deleteAspectWithoutMCL( + opContext, + entityUrn.toString(), + aspectName, + Collections.singletonMap("runId", "run-123"), + true); + + // The aspect with run-456 should still exist + RecordTemplate survivingAspect = + _entityServiceImpl.getLatestAspect(opContext, entityUrn, aspectName); + assertTrue(DataTemplateUtil.areEqual(writeAspect1, survivingAspect)); + + // Verify the RollbackResult details + assertNotNull(result); + assertEquals(result.getUrn(), entityUrn); + assertEquals(result.getEntityName(), "corpuser"); + assertEquals(result.getAspectName(), aspectName); + } + + @Test + public void testDeleteUrnWithRunIdFilterNonMatchVersionGap() throws Exception { + Urn entityUrn = UrnUtils.getUrn("urn:li:corpuser:deleteWithFilterNonMatch"); + String aspectName = AspectGenerationUtils.getAspectName(new CorpUserInfo()); + + // Metadata that should be preserved (run-456) + SystemMetadata metadata456 = AspectGenerationUtils.createSystemMetadata(); + metadata456.setRunId("run-456"); // Different run ID + CorpUserInfo writeAspect456 = AspectGenerationUtils.createCorpUserInfo("first@test.com"); + List> firstPair = new ArrayList<>(); + firstPair.add(getAspectRecordPair(writeAspect456, CorpUserInfo.class)); + _entityServiceImpl.ingestAspects( + opContext, entityUrn, firstPair, TEST_AUDIT_STAMP, metadata456); + + // Metadata that should be deleted (run-123) + SystemMetadata metadata123 = AspectGenerationUtils.createSystemMetadata(); + metadata123.setRunId("run-123"); + CorpUserInfo writeAspect123 = AspectGenerationUtils.createCorpUserInfo("second@test.com"); + List> secondPair = new ArrayList<>(); + secondPair.add(getAspectRecordPair(writeAspect123, CorpUserInfo.class)); + _entityServiceImpl.ingestAspects( + opContext, entityUrn, secondPair, TEST_AUDIT_STAMP, metadata123); + + // Then insert another run-123 with version gap + _aspectDao.saveAspect( + null, + entityUrn.toString(), + aspectName, + RecordUtils.toJsonString(writeAspect123), + TEST_AUDIT_STAMP.getActor().toString(), + null, + Timestamp.from(Instant.ofEpochMilli(TEST_AUDIT_STAMP.getTime())), + RecordUtils.toJsonString(metadata123), + 10L, + true); + + // When we try to delete with runId=run-123, the version with runId=run-456 should survive + RollbackResult result = + _entityServiceImpl.deleteAspectWithoutMCL( + opContext, + entityUrn.toString(), + aspectName, + Collections.singletonMap("runId", "run-123"), + true); + + // The aspect with run-456 should still exist + RecordTemplate survivingAspect = + _entityServiceImpl.getLatestAspect(opContext, entityUrn, aspectName); + assertTrue(DataTemplateUtil.areEqual(writeAspect456, survivingAspect)); + + // Verify the RollbackResult details + assertNotNull(result); + assertEquals(result.getUrn(), entityUrn); + assertEquals(result.getEntityName(), "corpuser"); + assertEquals(result.getAspectName(), aspectName); + } + @Nonnull protected com.linkedin.entity.Entity createCorpUserEntity(Urn entityUrn, String email) throws Exception { From 96c60580a6f3171314787a65dc072f2debb42771 Mon Sep 17 00:00:00 2001 From: david-leifker <114954101+david-leifker@users.noreply.github.com> Date: Mon, 30 Dec 2024 21:04:17 -0600 Subject: [PATCH 04/10] docs(graphql): create graphql best practices (#12229) --- docs-website/sidebars.js | 5 + docs/api/graphql/graphql-best-practices.md | 1022 ++++++++++++++++++++ docs/api/graphql/how-to-set-up-graphql.md | 27 + 3 files changed, 1054 insertions(+) create mode 100644 docs/api/graphql/graphql-best-practices.md diff --git a/docs-website/sidebars.js b/docs-website/sidebars.js index c18d8671318f64..bcb06affedcff0 100644 --- a/docs-website/sidebars.js +++ b/docs-website/sidebars.js @@ -780,6 +780,11 @@ module.exports = { label: "Getting Started With GraphQL", id: "docs/api/graphql/getting-started", }, + { + type: "doc", + label: "GraphQL Best Practices", + id: "docs/api/graphql/graphql-best-practices", + }, { type: "doc", label: "Access Token Management", diff --git a/docs/api/graphql/graphql-best-practices.md b/docs/api/graphql/graphql-best-practices.md new file mode 100644 index 00000000000000..d4c85d52e29f98 --- /dev/null +++ b/docs/api/graphql/graphql-best-practices.md @@ -0,0 +1,1022 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# GraphQL Best Practices + +## Introduction: + +DataHub’s GraphQL API is designed to power the UI. The following guidelines are written with this use-case in mind. + +## General Best Practices + +### Query Optimizations + +> One of GraphQL's biggest advantages over a traditional REST API is its support for **declarative data fetching**. Each component can (and should) query exactly the fields it requires to render, with no superfluous data sent over the network. If instead your root component executes a single, enormous query to obtain data for all of its children, it might query on behalf of components that *aren't even rendered* given the current state. This can result in a delayed response, and it drastically reduces the likelihood that the query's result can be reused by a **server-side response cache**. [[ref](https://www.apolloGraphQL.com/docs/react/data/operation-best-practices#query-only-the-data-you-need-where-you-need-it)] +> +1. Minimize over-fetching by only requesting data needed to be displayed. +2. Limit result counts and use pagination (additionally see section below on `Deep Pagination`). +3. Avoid deeply nested queries and instead break out queries into separate requests for the nested objects. + +### Client-side Caching + +Clients, such as Apollo Client (javascript, python `apollo-client-python`), offer [client-side caching](https://www.apolloGraphQL.com/docs/react/caching/overview) to prevent requests to the service and are able to understand the content of the GraphQL query. This enables more advanced caching vs HTTP response caching. + +### Reuse Pieces of Query Logic with Fragments + +One powerful feature of GraphQL that we recommend you use is [fragments](https://hygraph.com/learn/GraphQL/fragments). Fragments allow you to define pieces of a query that you can reuse across any client-side query that you define. Basically, you can define a set of fields that you want to query, and reuse it in multiple places. + +This technique makes maintaining your GraphQL queries much more doable. For example, if you want to request a new field for an entity type across many queries, you’re able to update it in one place if you’re leveraging fragments. + +## Search Query Best Practices + +### Deep Pagination: search* vs scroll* APIs + +`search*` APIs such as [`searchAcrossEntities`](https://datahubproject.io/docs/GraphQL/queries/#searchacrossentities) are designed for minimal pagination (< ~50). They do not perform well for deep pagination requests. Use the equivalent `scroll*` APIs such as [`scrollAcrossEntities`](https://datahubproject.io/docs/GraphQL/queries/#scrollacrossentities) when expecting the need to paginate deeply into the result set. + +Note: that it is impossible to use `search*` for paginating beyond 10k results. + +#### Examples + +In the following examples we demonstrate pagination for both `scroll*` and `search*` requests. This particular request is searching for two entities, Datasets and Charts, that +contain `pet` in the entities' name or title. The results will only include the URN for the entities. + + + +Page 1 Request: + +```graphql +{ + scrollAcrossEntities( + input: { + types: [DATASET, CHART] + count: 2 + query: "*" + orFilters: [ + { and: [{ field: "name", condition: CONTAIN, values: ["pet"] }] }, + { and: [{ field: "title", condition: CONTAIN, values: ["pet"] }] } + ] + } + ) { + nextScrollId + searchResults { + entity { + ... on Dataset { + urn + } + ... on Chart { + urn + } + } + } + } +} +``` + +Page 1 Result: + +```json +{ + "data": { + "scrollAcrossEntities": { + "nextScrollId": "eyJzb3J0IjpbMi4wNzk2ODc2LCJ1cm46bGk6ZGF0YXNldDoodXJuOmxpOmRhdGFQbGF0Zm9ybTpzbm93Zmxha2UsbG9uZ190YWlsX2NvbXBhbmlvbnMuYWRvcHRpb24ucGV0X3Byb2ZpbGVzLFBST0QpIl0sInBpdElkIjpudWxsLCJleHBpcmF0aW9uVGltZSI6MH0=", + "searchResults": [ + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:dbt,long_tail_companions.analytics.pet_details,PROD)" + } + }, + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:snowflake,long_tail_companions.adoption.pet_profiles,PROD)" + } + } + ] + } + }, + "extensions": {} +} +``` + +Page 2 Request: + +```graphql +{ + scrollAcrossEntities( + input: { + scrollId: "eyJzb3J0IjpbMi4wNzk2ODc2LCJ1cm46bGk6ZGF0YXNldDoodXJuOmxpOmRhdGFQbGF0Zm9ybTpzbm93Zmxha2UsbG9uZ190YWlsX2NvbXBhbmlvbnMuYWRvcHRpb24ucGV0X3Byb2ZpbGVzLFBST0QpIl0sInBpdElkIjpudWxsLCJleHBpcmF0aW9uVGltZSI6MH0=" + types: [DATASET, CHART] + count: 2 + query: "*" + orFilters: [ + { and: [{ field: "name", condition: CONTAIN, values: ["pet"] }] }, + { and: [{ field: "title", condition: CONTAIN, values: ["pet"] }] } + ] + } + ) { + nextScrollId + searchResults { + entity { + ... on Dataset { + urn + } + ... on Chart { + urn + } + } + } + } +} +``` + +Page 2 Result: + +```json +{ + "data": { + "scrollAcrossEntities": { + "nextScrollId": "eyJzb3J0IjpbMS43MTg3NSwidXJuOmxpOmRhdGFzZXQ6KHVybjpsaTpkYXRhUGxhdGZvcm06c25vd2ZsYWtlLGxvbmdfdGFpbF9jb21wYW5pb25zLmFkb3B0aW9uLnBldHMsUFJPRCkiXSwicGl0SWQiOm51bGwsImV4cGlyYXRpb25UaW1lIjowfQ==", + "searchResults": [ + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:dbt,long_tail_companions.analytics.pet_status_history,PROD)" + } + }, + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:snowflake,long_tail_companions.adoption.pets,PROD)" + } + } + ] + } + }, + "extensions": {} +} +``` + + + +Page 1 Request: + +```graphql +{ + searchAcrossEntities( + input: { + types: [DATASET, CHART] + count: 2, + start: 0 + query: "*" + orFilters: [ + { and: [{ field: "name", condition: CONTAIN, values: ["pet"] }] }, + { and: [{ field: "title", condition: CONTAIN, values: ["pet"] }] } + ] + } + ) { + searchResults { + entity { + ... on Dataset { + urn + } + ... on Chart { + urn + } + } + } + } +} +``` + +Page 1 Response: + +```json +{ + "data": { + "searchAcrossEntities": { + "searchResults": [ + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:dbt,long_tail_companions.analytics.pet_details,PROD)" + } + }, + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:snowflake,long_tail_companions.adoption.pet_profiles,PROD)" + } + } + ] + } + }, + "extensions": {} +} +``` + +Page 2 Request: + +```graphql +{ + searchAcrossEntities( + input: { + types: [DATASET, CHART] + count: 2, + start: 2 + query: "*" + orFilters: [ + { and: [{ field: "name", condition: CONTAIN, values: ["pet"] }] }, + { and: [{ field: "title", condition: CONTAIN, values: ["pet"] }] } + ] + } + ) { + searchResults { + entity { + ... on Dataset { + urn + } + ... on Chart { + urn + } + } + } + } +} +``` + +Page 2 Response: + +```json +{ + "data": { + "searchAcrossEntities": { + "searchResults": [ + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:dbt,long_tail_companions.analytics.pet_status_history,PROD)" + } + }, + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:snowflake,long_tail_companions.adoption.pets,PROD)" + } + } + ] + } + }, + "extensions": {} +} +``` + + + +### SearchFlags: Highlighting and Aggregation + +When performing queries which accept [`searchFlags`](https://datahubproject.io/docs/GraphQL/inputObjects#searchflags) and highlighting and aggregation is not needed, be sure to disable these flags. + +- skipHighlighting: true +- skipAggregates: true + +As a fallback, if only certain fields require highlighting use `customHighlightingFields` to limit highlighting to the specific fields. + + + + +Example for skipping highlighting and aggregates, typically used for scrolling search requests. + +```graphql +{ + scrollAcrossEntities( + input: {types: [DATASET], count: 2, query: "pet", searchFlags: {skipAggregates: true, skipHighlighting: true}} + ) { + searchResults { + entity { + ... on Dataset { + urn + } + } + matchedFields { + name + value + } + } + facets { + displayName + aggregations { + value + count + } + } + } +} +``` + +Response: + +Note that a few `matchedFields` are still returned by default [`urn`, `customProperties`] + +```json +{ + "data": { + "scrollAcrossEntities": { + "searchResults": [ + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:dbt,long_tail_companions.analytics.pet_details,PROD)" + }, + "matchedFields": [ + { + "name": "urn", + "value": "" + }, + { + "name": "customProperties", + "value": "" + } + ] + }, + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:snowflake,long_tail_companions.analytics.pet_details,PROD)" + }, + "matchedFields": [ + { + "name": "urn", + "value": "" + }, + { + "name": "customProperties", + "value": "" + } + ] + } + ], + "facets": [] + } + }, + "extensions": {} +} +``` + + + + + +Custom highlighting can be used for searchAcrossEntities when only a limited number of fields are useful for highlighting. In this example we specifically request highlighting for `description`. + +```graphql +{ + searchAcrossEntities( + input: {types: [DATASET], count: 2, query: "pet", searchFlags: {customHighlightingFields: ["description"]}} + ) { + searchResults { + entity { + ... on Dataset { + urn + } + } + matchedFields { + name + value + } + } + } +} +``` + +Response: + +```json +{ + "data": { + "searchAcrossEntities": { + "searchResults": [ + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:dbt,long_tail_companions.analytics.pet_details,PROD)" + }, + "matchedFields": [ + { + "name": "urn", + "value": "" + }, + { + "name": "customProperties", + "value": "" + }, + { + "name": "description", + "value": "Table with all pet-related details" + } + ] + }, + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:snowflake,long_tail_companions.analytics.pet_details,PROD)" + }, + "matchedFields": [ + { + "name": "urn", + "value": "" + }, + { + "name": "customProperties", + "value": "" + } + ] + } + ] + } + }, + "extensions": {} +} +``` + + + + + +### Aggregation + +When aggregation is required with `searchAcrossEntities`, it is possible to set the `count` to 0 to avoid fetching the top search hits, only returning the aggregations. Alternatively [aggregateAcrossEntities](https://datahubproject.io/docs/GraphQL/queries#aggregateacrossentities) provides counts and can provide faster results from server-side caching. + +Request: + +```graphql +{ + searchAcrossEntities( + input: {types: [DATASET], count: 0, query: "pet", searchFlags: {skipHighlighting: true}} + ) { + searchResults { + entity { + ... on Dataset { + urn + } + } + matchedFields { + name + value + } + } + facets { + displayName + aggregations { + value + count + } + } + } +} +``` + +Response: + +```json +{ + "data": { + "searchAcrossEntities": { + "searchResults": [], + "facets": [ + { + "displayName": "Container", + "aggregations": [ + { + "value": "urn:li:container:b41c14bc5cb3ccfbb0433c8cbdef2992", + "count": 4 + }, + { + "value": "urn:li:container:701919de0ec93cb338fe9bac0b35403c", + "count": 3 + } + ] + }, + { + "displayName": "Sub Type", + "aggregations": [ + { + "value": "table", + "count": 9 + }, + { + "value": "view", + "count": 6 + }, + { + "value": "explore", + "count": 5 + }, + { + "value": "source", + "count": 4 + }, + { + "value": "incremental", + "count": 1 + } + ] + }, + { + "displayName": "Type", + "aggregations": [ + { + "value": "DATASET", + "count": 24 + } + ] + }, + { + "displayName": "Environment", + "aggregations": [ + { + "value": "PROD", + "count": 24 + } + ] + }, + { + "displayName": "Glossary Term", + "aggregations": [ + { + "value": "urn:li:glossaryTerm:Adoption.DaysInStatus", + "count": 1 + }, + { + "value": "urn:li:glossaryTerm:Ecommerce.HighRisk", + "count": 1 + }, + { + "value": "urn:li:glossaryTerm:Classification.Confidential", + "count": 1 + } + ] + }, + { + "displayName": "Domain", + "aggregations": [ + { + "value": "urn:li:domain:094dc54b-0ebc-40a6-a4cf-e1b75e8b8089", + "count": 6 + }, + { + "value": "urn:li:domain:7d64d0fa-66c3-445c-83db-3a324723daf8", + "count": 2 + } + ] + }, + { + "displayName": "Owned By", + "aggregations": [ + { + "value": "urn:li:corpGroup:Adoption", + "count": 5 + }, + { + "value": "urn:li:corpuser:shannon@longtail.com", + "count": 4 + }, + { + "value": "urn:li:corpuser:admin", + "count": 2 + }, + { + "value": "urn:li:corpGroup:Analytics Engineering", + "count": 2 + }, + { + "value": "urn:li:corpuser:avigdor@longtail.com", + "count": 1 + }, + { + "value": "urn:li:corpuser:prentiss@longtail.com", + "count": 1 + }, + { + "value": "urn:li:corpuser:tasha@longtail.com", + "count": 1 + }, + { + "value": "urn:li:corpuser:ricca@longtail.com", + "count": 1 + }, + { + "value": "urn:li:corpuser:emilee@longtail.com", + "count": 1 + } + ] + }, + { + "displayName": "Platform", + "aggregations": [ + { + "value": "urn:li:dataPlatform:looker", + "count": 8 + }, + { + "value": "urn:li:dataPlatform:dbt", + "count": 7 + }, + { + "value": "urn:li:dataPlatform:snowflake", + "count": 7 + }, + { + "value": "urn:li:dataPlatform:s3", + "count": 1 + }, + { + "value": "urn:li:dataPlatform:mongodb", + "count": 1 + } + ] + }, + { + "displayName": "Tag", + "aggregations": [ + { + "value": "urn:li:tag:prod_model", + "count": 3 + }, + { + "value": "urn:li:tag:pii", + "count": 2 + }, + { + "value": "urn:li:tag:business critical", + "count": 2 + }, + { + "value": "urn:li:tag:business_critical", + "count": 2 + }, + { + "value": "urn:li:tag:Tier1", + "count": 1 + }, + { + "value": "urn:li:tag:prod", + "count": 1 + } + ] + }, + { + "displayName": "Type", + "aggregations": [ + { + "value": "DATASET", + "count": 24 + } + ] + } + ] + } + }, + "extensions": {} +} +``` + +### Limit Search Entity Types + +When querying for specific entities, enumerate only the entity types required using `types` , for example [`DATASET` , `CHART`] + +### Limit Results + +Limit search results based on the amount of information being requested. For example, a minimal number of attributes can fetch 1,000 - 2,000 results in a single page, however as the number of attributes increases (especially nested objects) the `count` should be lowered, 20-25 for very complex requests. + +## Lineage Query Best Practices + +There are two primary ways to query lineage: + +### Search Across Lineage + +`searchAcrossLineage` / `scrollAcrossLineage` root query: + +- Recommended for all lineage queries +- Only the shortest path is guaranteed to show up in `paths` +- Supports querying indirect lineage (depth > 1) + - Depending on the fanout of the lineage, 3+ hops may not return data, use 1-hop queries for the fastest response times. + - Specify using a filter with name `"degree"` and values `"1"` , `"2"`, and / or `"3+"` + +The following examples are demonstrated using sample data for `urn:li:dataset:(urn:li:dataPlatform:hive,SampleHiveDataset,PROD)`. + +

+ +

+ + + + +The following example queries show UPSTREAM lineage with progressively higher degrees, first with degree `["1"]` and then `["1","2"]`. + +1-Hop Upstreams: + +Request: + +```graphql +{ + searchAcrossLineage( + input: {urn: "urn:li:dataset:(urn:li:dataPlatform:hive,SampleHiveDataset,PROD)", query: "*", count: 10, start: 0, direction: UPSTREAM, orFilters: [{and: [{field: "degree", condition: EQUAL, values: ["1"]}]}], searchFlags: {skipAggregates: true, skipHighlighting: true}} + ) { + start + count + total + searchResults { + entity { + urn + type + ... on Dataset { + name + } + } + paths { + path { + ... on Dataset { + urn + } + } + } + degree + } + } +} +``` + +Response: + +```json +{ + "data": { + "searchAcrossLineage": { + "start": 0, + "count": 10, + "total": 1, + "searchResults": [ + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)", + "type": "DATASET", + "name": "SampleHdfsDataset" + }, + "paths": [ + { + "path": [ + { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hive,SampleHiveDataset,PROD)" + }, + { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)" + } + ] + } + ], + "degree": 1 + } + ] + } + }, + "extensions": {} +} +``` + + + +1-Hop & 2-Hop Upstreams: + +Request: + +```graphql +{ + searchAcrossLineage( + input: {urn: "urn:li:dataset:(urn:li:dataPlatform:hive,SampleHiveDataset,PROD)", query: "*", count: 10, start: 0, direction: UPSTREAM, orFilters: [{and: [{field: "degree", condition: EQUAL, values: ["1","2"]}]}], searchFlags: {skipAggregates: true, skipHighlighting: true}} + ) { + start + count + total + searchResults { + entity { + urn + type + ... on Dataset { + name + } + } + paths { + path { + ... on Dataset { + urn + } + } + } + degree + } + } +} +``` + +```json +{ + "data": { + "searchAcrossLineage": { + "start": 0, + "count": 10, + "total": 2, + "searchResults": [ + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)", + "type": "DATASET", + "name": "SampleHdfsDataset" + }, + "paths": [ + { + "path": [ + { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hive,SampleHiveDataset,PROD)" + }, + { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)" + } + ] + } + ], + "degree": 1 + }, + { + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:kafka,SampleKafkaDataset,PROD)", + "type": "DATASET", + "name": "SampleKafkaDataset" + }, + "paths": [ + { + "path": [ + { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hive,SampleHiveDataset,PROD)" + }, + { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)" + }, + { + "urn": "urn:li:dataset:(urn:li:dataPlatform:kafka,SampleKafkaDataset,PROD)" + } + ] + } + ], + "degree": 2 + } + ] + } + }, + "extensions": {} +} +``` + + + + +### Lineage Subquery + +The previous query requires a root or starting node in the lineage graph. The following request offers a way to request lineage for multiple nodes at once with a few limitations. + +`lineage` query on `EntityWithRelationship` entities: + +- A more direct reflection of the graph index +- 1-hop lineage only +- Multiple URNs +- Should not be requested too many times in a single request. 20 is a tested limit + +The following examples are based on the sample lineage graph shown here: + +

+ +

+ +Example Request: + +```graphql +query getBulkEntityLineageV2($urns: [String!]! = ["urn:li:dataJob:(urn:li:dataFlow:(airflow,dag_abc,PROD),task_123)", "urn:li:dataJob:(urn:li:dataFlow:(airflow,dag_abc,PROD),task_456)"]) { + entities(urns: $urns) { + urn + type + ... on DataJob { + jobId + dataFlow { + flowId + } + properties { + name + } + upstream: lineage(input: {direction: UPSTREAM, start: 0, count: 10}) { + total + relationships { + type + entity { + urn + type + } + } + } + downstream: lineage(input: {direction: DOWNSTREAM, start: 0, count: 10}) { + total + relationships { + type + entity { + urn + type + } + } + } + } + } +} +``` + +Example Response: + +```json +{ + "data": { + "entities": [ + { + "urn": "urn:li:dataJob:(urn:li:dataFlow:(airflow,dag_abc,PROD),task_123)", + "type": "DATA_JOB", + "jobId": "task_123", + "dataFlow": { + "flowId": "dag_abc" + }, + "properties": { + "name": "User Creations" + }, + "upstream": { + "total": 1, + "relationships": [ + { + "type": "Consumes", + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hive,logging_events,PROD)", + "type": "DATASET" + } + } + ] + }, + "downstream": { + "total": 2, + "relationships": [ + { + "type": "DownstreamOf", + "entity": { + "urn": "urn:li:dataJob:(urn:li:dataFlow:(airflow,dag_abc,PROD),task_456)", + "type": "DATA_JOB" + } + }, + { + "type": "Produces", + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hive,fct_users_created,PROD)", + "type": "DATASET" + } + } + ] + } + }, + { + "urn": "urn:li:dataJob:(urn:li:dataFlow:(airflow,dag_abc,PROD),task_456)", + "type": "DATA_JOB", + "jobId": "task_456", + "dataFlow": { + "flowId": "dag_abc" + }, + "properties": { + "name": "User Deletions" + }, + "upstream": { + "total": 2, + "relationships": [ + { + "type": "DownstreamOf", + "entity": { + "urn": "urn:li:dataJob:(urn:li:dataFlow:(airflow,dag_abc,PROD),task_123)", + "type": "DATA_JOB" + } + }, + { + "type": "Consumes", + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hive,logging_events,PROD)", + "type": "DATASET" + } + } + ] + }, + "downstream": { + "total": 1, + "relationships": [ + { + "type": "Produces", + "entity": { + "urn": "urn:li:dataset:(urn:li:dataPlatform:hive,fct_users_deleted,PROD)", + "type": "DATASET" + } + } + ] + } + } + ] + }, + "extensions": {} +} +``` \ No newline at end of file diff --git a/docs/api/graphql/how-to-set-up-graphql.md b/docs/api/graphql/how-to-set-up-graphql.md index 2be2f935b12b10..8a6db7f6c105a2 100644 --- a/docs/api/graphql/how-to-set-up-graphql.md +++ b/docs/api/graphql/how-to-set-up-graphql.md @@ -1,3 +1,6 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # How To Set Up GraphQL ## Preparing Local Datahub Deployment @@ -29,6 +32,7 @@ DataHub provides a browser-based GraphQL Explorer Tool ([GraphiQL](https://githu This interface allows you to easily craft queries and mutations against real metadata stored in your live DataHub deployment. To experiment with GraphiQL before deploying it in your live DataHub deployment, you can access a demo site provided by DataHub at https://demo.datahubproject.io/api/graphiql. + For instance, you can create a tag by posting the following query: ```json @@ -43,6 +47,29 @@ mutation createTag { For a detailed usage guide, check out [How to use GraphiQL](https://www.gatsbyjs.com/docs/how-to/querying-data/running-queries-with-graphiql/). +To navigate to `GraphiQL` on the demo site or your local instance, select `GraphiQL` from the user profile drop-down menu as +shown below. + + + +

+ +

+![graphiql_link.png](../../../../../Desktop/datahub_graphiql_link.png) +
+ +

+ +

+
+
+ +This link will then display the following interface for exploring GraphQL queries. + +

+ +

+ ### CURL CURL is a command-line tool used for transferring data using various protocols including HTTP, HTTPS, and others. From 7198f711dc3ae580c5b5ca205acd2f5ca6dfddea Mon Sep 17 00:00:00 2001 From: david-leifker <114954101+david-leifker@users.noreply.github.com> Date: Tue, 31 Dec 2024 08:50:44 -0600 Subject: [PATCH 05/10] fix(ci): further consolidate NODE_OPTIONS (#12217) --- .github/workflows/build-and-test.yml | 4 +- .../workflows/contributor-open-pr-comment.yml | 2 +- .github/workflows/docker-unified.yml | 2 - datahub-web-react/build.gradle | 2 +- datahub-web-react/package.json | 12 +- datahub-web-react/src/Mocks.tsx | 1 + datahub-web-react/vite.config.ts | 8 + datahub-web-react/yarn.lock | 141 ++++++++++++++++-- docs/developers.md | 1 + 9 files changed, 147 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 98071b536a336a..784dce0f11b2b5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -109,8 +109,6 @@ jobs: if: ${{ matrix.command == 'frontend' && needs.setup.outputs.frontend_change == 'true' }} run: | ./gradlew :datahub-frontend:build :datahub-web-react:build --parallel - env: - NODE_OPTIONS: "--max-old-space-size=4096" - name: Gradle compile (jdk8) for legacy Spark if: ${{ matrix.command == 'except_metadata_ingestion' && needs.setup.outputs.backend_change == 'true' }} run: | @@ -157,4 +155,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: Event File - path: ${{ github.event_path }} \ No newline at end of file + path: ${{ github.event_path }} diff --git a/.github/workflows/contributor-open-pr-comment.yml b/.github/workflows/contributor-open-pr-comment.yml index 2f700290ee0f28..decc7ab27a411d 100644 --- a/.github/workflows/contributor-open-pr-comment.yml +++ b/.github/workflows/contributor-open-pr-comment.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get and Format Username (PR only) if: github.event_name == 'pull_request' diff --git a/.github/workflows/docker-unified.yml b/.github/workflows/docker-unified.yml index 47c26068347c07..a5200c7e917d81 100644 --- a/.github/workflows/docker-unified.yml +++ b/.github/workflows/docker-unified.yml @@ -445,8 +445,6 @@ jobs: run: | ./gradlew :datahub-frontend:dist -x test -x yarnTest -x yarnLint --parallel mv ./datahub-frontend/build/distributions/datahub-frontend-*.zip datahub-frontend.zip - env: - NODE_OPTIONS: "--max-old-space-size=4096" - name: Build and push uses: ./.github/actions/docker-custom-build-and-push with: diff --git a/datahub-web-react/build.gradle b/datahub-web-react/build.gradle index bf1aa401e3f560..3dad778a2b3038 100644 --- a/datahub-web-react/build.gradle +++ b/datahub-web-react/build.gradle @@ -79,7 +79,7 @@ task yarnServe(type: YarnTask, dependsOn: [yarnInstall, yarnGenerate]) { task yarnTest(type: YarnTask, dependsOn: [yarnInstall, yarnGenerate]) { // Explicitly runs in non-watch mode. - args = ['run', 'test', 'run'] + args = ['run', project.hasProperty('withCoverage') ? 'test-coverage' : 'test', 'run'] } task yarnLint(type: YarnTask, dependsOn: [yarnInstall, yarnGenerate]) { diff --git a/datahub-web-react/package.json b/datahub-web-react/package.json index 2d1d667a89f14a..a608698d7602c4 100644 --- a/datahub-web-react/package.json +++ b/datahub-web-react/package.json @@ -89,10 +89,11 @@ "scripts": { "analyze": "source-map-explorer 'dist/assets/*.js'", "start": "yarn run generate && vite", - "ec2-dev": "yarn run generate && CI=true;export CI;vite", - "build": "yarn run generate && NODE_OPTIONS='--max-old-space-size=4096 --openssl-legacy-provider' CI=false vite build", - "test": "vitest", - "generate": "graphql-codegen --config codegen.yml", + "ec2-dev": "yarn run generate && CI=true vite", + "build": "yarn run generate && CI=false NODE_OPTIONS='--max-old-space-size=5120 --openssl-legacy-provider' vite build", + "test": "NODE_OPTIONS='--max-old-space-size=5120 --openssl-legacy-provider' vitest", + "test-coverage": "yarn test run --coverage", + "generate": "NODE_OPTIONS='--max-old-space-size=5120 --openssl-legacy-provider' graphql-codegen --config codegen.yml", "lint": "eslint . --ext .ts,.tsx --quiet && yarn format-check && yarn type-check", "lint-fix": "eslint '*/**/*.{ts,tsx}' --quiet --fix && yarn format", "format-check": "prettier --check src", @@ -100,7 +101,7 @@ "type-check": "tsc --noEmit", "type-watch": "tsc -w --noEmit", "storybook": "storybook dev -p 6006", - "build-storybook": "storybook build" + "build-storybook": "NODE_OPTIONS='--max-old-space-size=5120 --openssl-legacy-provider' storybook build" }, "browserslist": { "production": [ @@ -135,6 +136,7 @@ "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", "@vitejs/plugin-react": "^4.1.1", + "@vitest/coverage-v8": "^0.34.6", "eslint": "^8.2.0", "eslint-config-airbnb": "19.0.4", "eslint-config-airbnb-typescript": "^17.0.0", diff --git a/datahub-web-react/src/Mocks.tsx b/datahub-web-react/src/Mocks.tsx index 73a789030ce6fb..2da9e733eb4072 100644 --- a/datahub-web-react/src/Mocks.tsx +++ b/datahub-web-react/src/Mocks.tsx @@ -1714,6 +1714,7 @@ export const mlModel = { }, tags: [], properties: { + name: 'trust model', description: 'a ml trust model', date: null, version: '1', diff --git a/datahub-web-react/vite.config.ts b/datahub-web-react/vite.config.ts index 2532b24067754d..c43470dee031a8 100644 --- a/datahub-web-react/vite.config.ts +++ b/datahub-web-react/vite.config.ts @@ -68,6 +68,11 @@ export default defineConfig(({ mode }) => { envPrefix: 'REACT_APP_', build: { outDir: 'dist', + target: 'esnext', + minify: 'esbuild', + reportCompressedSize: false, + // Limit number of worker threads to reduce CPU pressure + workers: 3, // default is number of CPU cores }, server: { open: false, @@ -92,8 +97,11 @@ export default defineConfig(({ mode }) => { css: true, // reporters: ['verbose'], coverage: { + enabled: true, + provider: 'v8', reporter: ['text', 'json', 'html'], include: ['src/**/*'], + reportsDirectory: '../build/coverage-reports/datahub-web-react/', exclude: [], }, }, diff --git a/datahub-web-react/yarn.lock b/datahub-web-react/yarn.lock index dc7260efd183fd..f16e8aa506e2cc 100644 --- a/datahub-web-react/yarn.lock +++ b/datahub-web-react/yarn.lock @@ -20,6 +20,14 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" +"@ampproject/remapping@^2.2.1": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@analytics/amplitude@0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@analytics/amplitude/-/amplitude-0.0.3.tgz#15ccb76094d6f1003979a4f3aa5d3263781bd776" @@ -1017,6 +1025,11 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@ctrl/tinycolor@^3.3.1", "@ctrl/tinycolor@^3.4.0": version "3.4.0" resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz#c3c5ae543c897caa9c2a68630bed355be5f9990f" @@ -1941,6 +1954,11 @@ resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + "@jest/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" @@ -2009,6 +2027,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.18" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" @@ -2017,14 +2043,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - "@linaria/core@3.0.0-beta.13": version "3.0.0-beta.13" resolved "https://registry.yarnpkg.com/@linaria/core/-/core-3.0.0-beta.13.tgz#049c5be5faa67e341e413a0f6b641d5d78d91056" @@ -3974,6 +3992,11 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + "@types/js-cookie@^2.2.6": version "2.2.6" resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.6.tgz#f1a1cb35aff47bc5cfb05cb0c441ca91e914c26f" @@ -4714,6 +4737,23 @@ "@types/babel__core" "^7.20.3" react-refresh "^0.14.0" +"@vitest/coverage-v8@^0.34.6": + version "0.34.6" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-0.34.6.tgz#931d9223fa738474e00c08f52b84e0f39cedb6d1" + integrity sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw== + dependencies: + "@ampproject/remapping" "^2.2.1" + "@bcoe/v8-coverage" "^0.2.3" + istanbul-lib-coverage "^3.2.0" + istanbul-lib-report "^3.0.1" + istanbul-lib-source-maps "^4.0.1" + istanbul-reports "^3.1.5" + magic-string "^0.30.1" + picocolors "^1.0.0" + std-env "^3.3.3" + test-exclude "^6.0.0" + v8-to-istanbul "^9.1.0" + "@vitest/expect@0.34.6": version "0.34.6" resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-0.34.6.tgz#608a7b7a9aa3de0919db99b4cc087340a03ea77e" @@ -7282,6 +7322,18 @@ glob@^7.0.5, glob@^7.1.1, glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -7612,6 +7664,11 @@ html-encoding-sniffer@^3.0.0: dependencies: whatwg-encoding "^2.0.0" +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + html-void-elements@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483" @@ -8154,6 +8211,37 @@ isomorphic.js@^0.2.4: resolved "https://registry.yarnpkg.com/isomorphic.js/-/isomorphic.js-0.2.5.tgz#13eecf36f2dba53e85d355e11bf9d4208c6f7f88" integrity sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.5: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + jake@^10.8.5: version "10.8.7" resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f" @@ -8542,6 +8630,13 @@ make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -8819,7 +8914,7 @@ min-indent@^1.0.0, min-indent@^1.0.1: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@3.0.5, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.2, minimatch@^4.2.3, minimatch@^5.0.1: +minimatch@3.0.5, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2, minimatch@^4.2.3, minimatch@^5.0.1: version "3.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.5.tgz#4da8f1290ee0f0f8e83d60ca69f8f134068604a3" integrity sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw== @@ -10891,6 +10986,11 @@ semver@^7.3.7: dependencies: lru-cache "^6.0.0" +semver@^7.5.3, semver@^7.6.2: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" @@ -10898,11 +10998,6 @@ semver@^7.5.4: dependencies: lru-cache "^6.0.0" -semver@^7.6.2: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - sentence-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" @@ -11381,6 +11476,15 @@ temp@^0.9.4: mkdirp "^0.5.1" rimraf "~2.6.2" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -11873,6 +11977,15 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== +v8-to-istanbul@^9.1.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + value-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" diff --git a/docs/developers.md b/docs/developers.md index 401169490dd4b6..0d398e6232b23d 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -9,6 +9,7 @@ title: "Local Development" - [Java 17 JDK](https://openjdk.org/projects/jdk/17/) - [Python 3.10](https://www.python.org/downloads/release/python-3100/) - [Docker](https://www.docker.com/) +- [Node 22.x](https://nodejs.org/en/about/previous-releases) - [Docker Compose >=2.20](https://docs.docker.com/compose/) - Docker engine with at least 8GB of memory to run tests. From 4ed128cf28513d97961e551b4235ecf50d04955c Mon Sep 17 00:00:00 2001 From: Aseem Bansal Date: Tue, 31 Dec 2024 21:36:25 +0530 Subject: [PATCH 06/10] chore: cleanup extra lines (#12248) --- smoke-test/tests/cypress/integration_test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/smoke-test/tests/cypress/integration_test.py b/smoke-test/tests/cypress/integration_test.py index 33c67a923c278d..fa7274158f9e23 100644 --- a/smoke-test/tests/cypress/integration_test.py +++ b/smoke-test/tests/cypress/integration_test.py @@ -212,9 +212,6 @@ def test_run_cypress(auth_session): else: record_arg = " " - rest_specs = set(os.listdir("tests/cypress/cypress/e2e")) - cypress_suite1_specs = {"mutations", "search", "views"} - rest_specs.difference_update(set(cypress_suite1_specs)) print(f"test strategy is {test_strategy}") test_spec_arg = "" specs_str = ",".join([f"**/{f}" for f in _get_cypress_tests_batch()]) From f5ecee1501e7646f6dc0a5a13202d32c7b096ba8 Mon Sep 17 00:00:00 2001 From: Jay <159848059+jayacryl@users.noreply.github.com> Date: Tue, 31 Dec 2024 17:56:32 -0500 Subject: [PATCH 07/10] fix(docs-site) hero image typo (#12250) --- docs-website/static/img/hero.png | Bin 380503 -> 380547 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs-website/static/img/hero.png b/docs-website/static/img/hero.png index 44b11c2781143f106c6929cc439d5d21feff18ce..a520a6d8a6b6ff8208291bbd79e0f1df58036267 100644 GIT binary patch delta 97725 zcmXV1Wn7f))1|vXx>-b!lJ1s}5>Su^0Ricf=B7hp=`N*|knZm84yj$bbLoBY`M+QH z!@a+2u9-9EoSADrlPoBUEcP`vHZcMMHZdYXdM0_C03Fg8d4Nuc4q}K7Qiu+6tqw|` zEP$D5q2R`Xk>jDO`%(8J8>ZdIKsF{2gQ>Z4R}doRQX~q|G2sF`>4i&>9L#l@G^)7> zv6;-lqf@-D6Ow(46D9svprQRZr!%~+(@t5w$|)$=iArgKeM#yyn^HkpU1{-%*BjUh z70YH%1Tn1DfQ{F9?p9g%WVL~iMXe{A3J}}`)O!Z6Tqq**D*2PPixpzyY)tORoENHz zmubKyudE%?FvDCX)NP5(k(uf;-9q<>Sl;|FAIXZmcSCyhf!S@uv^rW0 z_nIMAMW$;<)uBb~;$bwvoPsEt?%{nsm|2hPDecpCWDkuOI$RMPLPZp*W9X@?418y7 zyev6^E4G9N6X>%2Ok$3AQxsru3eNw5LZoIT-bBKPGbjbp1CGfg7Pdpk>&MIu8Pa+W zFbo!4k{X%O9&*{SMDX8mD1WWbZxO)b7pzG~iII;1(4K3$F?A<3)kgY{K+ zF_IIzWwcMCQtbV$G^ijhC*T7JFvz3DI=+`zvxRSZuMsYPnb($hKZ>k0G0Q02ERD0g zZs0@mE-2n{a%=6~tyC~m^a*uE+{@Fv7W`zSp@FaM4%{l_vGi#fIbc%HzfXSN>!u6S z8OL2G9;Tqt7<8k%zhs?c_V=1A4zc0Fm>{sx-BhGk1VhyXbk2FFMaumfQ15$R*TBV$ zv~{eV6VJ)>iSz z{4?R&_&HDqi-iUWyK)DB95N>|3)ew|N-z&vLHctw zy1ey3vws0!agaauW+F;D6mofo93dp5tR$%tkoYoASvEZH^Hj(-T&UlHW+%LCPpp@@ ziZ>1inVe)rs?V-AghKB81$_~3-fHZxJ`!|BQ*w6(8g5zCWV&!5Hin=l&p?u{l<(rs zY!zyjoj)(d;NUyLr0ZDa892=5QyjyT?=%tJN|D9AND~wJzV;T>i8+#vNpCMV zqM2V>!Ao6OF8cu3L|oVm#}JEu13Ui=n)|AlnKi94WaK?t@X14!AcVm>c+TY}a_*Z) z*tcVYmT7tr2K+(+C}2jNL@KXaW7JK%o~4*0)MNX(>Rb*eloplz@p-GSp0`g0X*Qv6>n5V=1qV&bV?zs1txBNmSq^6RZ?`Xx7ZRXc&cB(l+ zq7FfUtI?|-@3X!_yvZQ3zsn&*WPJDiB49r-lR&T^+6;Y!=kZIrHTsE5YUr*h$Xe z594`728o|tK3k2{+V*?D?`%(hRI*_kW_59ol3uTJ88CDHmyKz1CWi%8-=S=E_j(rRxb z5=fv|x+Tmy%~KJw@aU`rmLuVi>!Vc71{h`>#HHs^ED*^avjz*$cJlg75fA45JD?_ z+tCqn=_wW-^c(s{^Sa6!f#k>4UsIr?((HAIF0ML{J5Fm@w^L`E{Ao6m@-ob+)?$V-6C&7=CvL3LhxweD($%hg{XZuRdK;KithL|1>ZD z-MMGvLV*ePv)UJ5_wDRNma>*uDl!*RZ*QbA|cz=V%hrcHWVNk^u??GQOA z2O;7_hp#PIn?JF`e5IxmF*I$5eQ8(7g0|X>LuY#@L!p=b+xnlarV9%^<&3c$k3FCR zao6r&y@+iWY6SXrGKxfyfo|_~hNDj55T8U0Ga;_P+f+yDo}1PSU`-wI)!DAhyOiz2 zj_}@?iJ*pgvxi)KAMd6_i8w9Vd{ynC_LZTS8x&m?U4s5W<76&>=o*`6O+*8ImHo(9 z24&<8EZ94`EauxxnkW$4KvF4ZoO^7-Om1e8`JRZi;vNl)rufB^K(?wXwH5z9qW{V7 zeP3pWx)4Nm$5Oo&IJ?U?oLourKYo}_ro2&qg)EXYiKA~Ux+A58y^W+&dQ?#8fyxa> zhOcGV^oXvjjmiKk*k*5zNI}%3x5D7ItY(#Z*bN*bs9hZ+M5=FWQ=2`lqkWCFou}wk zDe^@6<^C}^AO^&~d~rHU-j%YtbW{Ic(X)}uoL)@n=8}ooNqBx{nT1XmCuiB4WVObI z*JnJf-!y*q!>%frCO}<`5BvT#Fc$uFv(fFi5jmRf!b~roS&qssNXUoz={3xRqb@9| z$2o-tvmc@)lD!MFX*H!R6UINX5l`oGTfEcs_nh|IwFy}tS*O=coF#v&))R56VVy-D z6T=H1muT_cqtrq#!f!GyACBN$vykCIH&sSPsYkL+c@Htlk%&%NWwmuKQG0)2u+^w_C-)gHytqdXdv(~0yfNi` zd1Hd|I<*E@F+M|OVgBI5UlVQ>#_#y?9B(4fO^vD4?{TD8b_!)F`CL!-xHHeA2;6)+ z2zz9Gb1BeklTz-zdaA`={#K`^=n6X#MS&kpGC9ujP(H2Rj!^qt0vXk(yBlV$XV+z> z>W64SohIDW_%->P+jd7)ZcDE{3L?}%LQZKSF-3*-r5lg#SvN1{MKr@hZpBoun#{T- zz6Ld@h6Q5=SM@1 zauGh$*3@KDZ=dd)0+>M%M)eWSo~=XIW8b<5F$>zS^hDoP&{Ou`=zhdoXkCAy#@Jjj zhuo}vw*F#@*Zp03%6KI^lt$$uYD~X%n8GE6YY-Mys;ZA1`@%kUC`$Z$@n;cF0yEp)%ar)>YaJFN)XaDbVr@6-M~UKB`(kSyDFEg1JXzK)xSSp=%6 z2TCB3!Q1h70Kx^M^NYc`+C$q{F~fY_j0ijkABc7bc}O+;s9c`Liy-l0kr%+urxtFw z`(V{L>+KdaUm1m}z)>wKiC8)eYHWk5v@BiQ9yCA`yCU5%PXgYIw_TB8h?!&!do|wc zjEfe9<0^c+PmPb?SZ^9608E+2?qMs%tjqn%jB9ZP-k)-{;CjDI;Npc%II;OGHi3lr zX_<+Z@Nx~NvXAS{T?T}Ll!nH5{|vD5#FKOp}mT@v0J&$mev)kRUR&T_XwZ=@i$#Ga-3aB^) z{$4)}3m=0tGJ>zyds-YvYD}l+l5GvEQ+{foY#=J91Z$#zfUI?4D)iF~E@29LpG(C9 z1gqMVaEHI^>wxDIX~X77^z-ND(7$E7d95Uz%dObVntWmxuw7Y+QIDY!o{0xH1p7ex zqONF=X_tO9wudN56r)(;^Kf^<@}= zIVBb&54$`7_uc6z+SIE8vrrYoPmSUWp-sB!VCt zIS5kPq0{rmL+IKRySV0(R&K9(pr(|T+H;BMu$a+82NVtE;tWpco6UTf-h~?D5nhANl-D z6~*uUc~pbKo#8#qoqK0hXx)Ag6tQZ7AxUmre{Uu1_M?O@0V=#5F|P7glWtW?b?2@wgsVdWVc^5J5w>MoR5EKqwnG^TBMn+%CG zv*^%^usDAI^*X>M~T?{ENZf;n#$Jk!36@zv)6L`O{IQ~{nxt-eC3I* zMEg{!ho9bQ9|;@(66B<1>*guZqEL#DJI_S5)IDbmzKDt~tFcL12Ni!WcoXjuxUne- z;QTZlM9atuLl?NG>=Y@G{-mkPvwaweb>W&USIEWDoeFaM?EJg%UxYCyOhU34t5(1J z)~Y3E+9Ilv&rFyKuK$$a#?7)q(2c?!h)>{&3tA&aDRQ9ffP0N;dmQOzY`7nbqPU;r zge7&nEmG-T9?K5c87*}xA^eBmy+Yf(g%9mAit6zM|QvY6>(QXS3$og1Zah+d9+ViDK`RGvS9hKpt zEuynCFJ*T$Bd?8JHEGVCUM83qzA>LDB=4-o-9kjL%y_`<;m}86PqqlpT*!~Ot8f%T zsm#mGeW^XdD^c^xELG&qDX^#fmd_Ek?J@8iVATm{io2hwZ9I3EQ}~Z2#*)d&?G>vc z*Q2-GOy6d0gL(FCw)2roOim^lY;(RpT!X_{%D=i+k(|4(6guQOR_CJCmid>5R|M*o4+i-m!I{HBCiTYTUtmU%+?9Hy6J5guLh}&`RSQQjvwHjLWC|PE+a*?oA$C=q}Y8gcGX^ zX){WUCfhX89^a@&y!D>>5t&tU$Vqlu5O`G*8~m)w_CiBiocrY)_De_0P>VuO#Lbvm z9%ig>F6(1DRK4-K5iQ!s5~!*!6QeEe{^}Q+47sh&Fgvb|mgF>37_B{AjsC{tzkLMu z^1?R8uc-rqM$g>&n+)8qNrlW3ZXNjk9Vh}5^tn*b4z=A0Ewn*>=YjCFe>?BvOFgUW zBKO@knnD5FVCf4%Yv>o03`lXTT+~5?KKJ|g1W5*CpLgJy1Lwt9K2P|pOv#+^o3&oG zP?c;7^$?*RzqhpXxQ>QP4?HZ0hCqFuMI9Xo+N6vWuOH~l!~3y}{+M1t@8|LNo4?l| z2H$DLJmqQ8Y2qz>Mso<>V10x4(mM$xg9lI zs;;OHF|*kRSS^Yws$7`NUrX|6x7x0a88|&@?N;%MXmDePK zHJ{cp+_#F!IHDbTC@?gwJI$Xj)CTGE`y{uN4NzR-j~v%c$WLyhfCwZRaZZ~MwK0)i@A8SW0x7vy4Q zGaE6Ng;EN(p_MQEPB#b-Q|{R)ROkslf;j&u+9%4`Qt1-42b+{v_~2Tgd%Ij%(WQM(iBQi&t#&MU zsa=U#Kp5JgLc}jN5=~e{+K0)E3mJnmr2KGtr`jIO)W9H1^O zyJgNK!Wv^*ohK||;H{6w%w~FtBoYdfFbhqo;HfTtLXdIEbu?dNOqR~!*k&B0N``uz zHh)B054!nr>zO~9+R@`?3N0?;_3LJ?8xlG1$ekI}p}qK=_h27OibfQ*i{d|0m4#2R z)!;vzZoX0tNDyUGEBZYh3*vVI-k01D)h_j2k@W|%BsJN-V zdNfq?KiW*M$7ogT$t3`=93Ic{Z^|<{u?_M%YZA!}bHm548&KZYYizRh$k{fjljXfA zq`VE25jABbw_{*pAm?G>;rv6cs=s9+mt~e2q7E&zocp1nUVM{0 zVScrvL|RRWdwbe6$|34vADmD;sX-*{6!UQ?C0SH4N~J+RW}BfSm2#kz*Gw-5de%Ii zLGt(4;Yv}ChrZ^_IyYguW&j_s?7YsH4&1YKb?)t}_utFtb6C`jx2ljrsoWY1au|bJw z=_z>KR%?KtO&-8ux}l9_j*4Z=&D#Deln}M`u$3G`MdSnEuh0S<;83pZ~?^sh=|`$YWYBq5)saH9vj{()E{OZmrCf- zVbx6EU+F7OBYfd%dqs5Q#+rny84mOf3`YJ^7TErB|0Qt3j(}aZvr>h+1ihb{1ref^ zYAT}}HYiQ7R-JI5gLg#ZsD4(eSa~hvG>ED5id_O#nl+~Oo(a{%i81A;B^0DCi8cyJ zw2J?L$^myY;L|Kj`3E%~4sQ>lO_@X_zw;z&=JgxrxXGUdd^bj=_9ynX0h%%oM+DMC z4d}{vpN|zf8)(2Y>$gFZ-PPidirg%`uBU9Qnr|hp{lj#q3Nq3eUnAq5CG0 z-yVCvsg}3a!nW^~&l;aQRZ4bt(ERZVijDxVT%>RUM4+$`<=50aIAmN(x@;(!9c6ho zFc`z3`e7UDRDrIE_85uJbXaLSD%Q zdDam}=GF$y(6_s5@M$Tyre2m!P;#TcV)#jfK7(9f0?LBoGZ1E*XNH80kVk&B2hlGQ zUDW;gpd~dhpwL$S#ge$sC#omYr)lh6;u;$IPs;CNpMB%wkOu*@kk~70i8zdzpP;YA z-@V>2)qicCUMla({Sw?Vo?&R*bR8znqN@+R8wh+gt~Te0Y}@~UsW4YzPA;{W=D{o; zDMO<}+pjQZ;OD#UEulE9!j)_y5@)>_Lh;{@&Q=Gj`>2~4^KW}vVa(r1tbs$m*Xn~YyFqHeJQalqo7X=jdrs?7W zB?w6wXlqccFXhz^`VEVX`=J_{0uqtR5Aq}W9}3L`qe(5^TE2_jk8Ox|1$@?Jr&O7D zB(pEK+zy1uy0<~4_EqsfFB(BXM zV3Q95!kvz0!7#O19|g^!n?)UJ)tBDyZ*?LUNFTWe(FF#}zuG<@s{~)7P#CrR1fqftULQ?7CwwCZ@Ql%N)5(7&sGEvllN0YmtIj;W_tso$YNd zIqyCl3mXt+irGc)=DW6g!lXUUcdeXVyk&7F+Kvu6PFGKaFvs{(@Jvyt5fM{fo1#P^ zUZpgcqA(&prYxJHZ~|lU=<`|P$nYKaESxpZ^UF`xv|_F}e%r(M8wgCi%$*Ulm+E7S zNDfQl#1Q(<+qRcuM)Iyix3{yt7uIbj!I&?ub zeO^NZ{Z>ewNTyBlq;dz&1E)>vsLOGAFl%*5Yg!6dyxXG(gbirx@AB+UdE)t>GPI&s zUwiAyI~;H_*+AYf5xOvOB}bZ({+`e^m>Q_6rgw|Dvn^9-thMGbrziZ-hFBdnx=qM= zBrcNQiZ;*?IFG%DYmw!xO?Q?Y+2HBbue~c%c_e*y@B`{d4Mi=j6?GaF7RT>5M{R4e z)%sZ`qKc0OJU2)3O5OvTOdiC0mkm?9yo<3RtqdiONiuOh(1{uQ#i4hYat6BlS!;3e zf0{z*mBdPZ0L8t<*pe6(#~0r(7<+!i0m36k- zs8NGkX)7;m9Dk!v0l)tOe()#gl%%@r;q19V0wq*3=c>&DmU24~+~2p8_xQaR?LH5R z$$!u;&!5^N>$>4f1V#D+3mL=zLuY?-+6oSmivyq29jP1wm#OL3d&%5zu1yc|Hf(mH zHSBn>I`0c|uoS>tIscYsz)67VGPPkKyx{1^6hPvMk*R+w9EaZ6mX`g8iIo*g5`c}p z#iaQmY6ZdZFAA}JPzRi}JG3n~PPmyErX|v|XFnR;(Ke<@Yjd@L&b3Kb7?_H9H$PFG zH)+Zz=cp9N?W8k`wUY6mh$Y^7lta-YN`|a{#TW9#yKE9tYE2eJpbbcn|H9=~YY9Rn zJW=~BaE7S#ay!#noixK5zxmiK0vH!$DdheKlC>dLN)Z@&JZct&J(90_{YaqmhG@bKtRnYUK{{D&gnrOlUT)sdB6TL@!y zlqS3pp-5MD#qr{2V-UK;IT!**tTu6@?}O7H^jMl^CuM|d)IOzt428Wz=?|_n?quEu zG2$nFAM*T;G0!EVGzUc1W$X=}U%v2E3#J-uREzc0O2C~+v7_h`%O2=oh^fL0BB1RO zx^?fZ1qtM=@6h;s%|aF=FiiTFi<~}}C=_0er_!NJgh`xz*4>7?XXMstQ&KC#3!Y~i zaaWyc`4HqV_Lc6Y193Wu=d#`^L0?~6^CkEKzKuKMT4-YcXpIMwoASagVZLsXxflj9 zPd3KOIR*FE30h4T>PrZD{ya}GE^%!5i7)!bAXA=_#(ydphec@M7@f^L&is%6=$4HW zVwFX!E@eD_-viy(e##%Hxs?t|6gwzny=c8ma-Lh1TzCV_+jv+q&K+ac%CFSU-*)k^ zBdVjMDFbH#(N{FlN8JV;TS@A-jW@#sbL%v#7lD0^(u0dmMANKSxrpV=-8BX*1WjMi zsM6_=>K$&f{!$a-{fyRN_>P9Lg)$fc$-d?)7cM9xmIt5W+R#-^3U8&8&3{U5f$DNC zKW3chOOFZ3G3KgzRjWo+<9@ekE&3NeiH7-J;HJ-Yj|sp2OOdpu_fmWcC!Mhrr4P|< z+MTpc%nK_inTQ1|Fn;W^mHp#ob_003pDsNla6bo8~_Ukvzql=+X_yd8V%gPUqF zo!xkQn*;5t+kLg8>+Z&4;|DE=rB;g7n%5l0@F!lu&iV9)9PiED0Wk+_b2zwYXJfP( z5a=#(w@3P4P(w*GM@)NEsRI-lCNy#-}R!)?Sb;KkH0xgeQ79MR+tY+XE? zn#=0MLyWM1aCQ6e3EV}|Tc4!FuRipBlR@k;^A}pK!w!b@9H^bc1xbDWgfB`S%7#o_fV zi`I@kT#PNAN$Rf$I;3NTF9*#kv%8@iF{15w`dT^l{Cm^4dif_=3csXIB zj}cy=kTbt&Y&d;1A+#Sm6Mj(>f2vhY2>JurD$ND-Z%G!As`8=UZ_(8J*@^eO*s;Ln zyIUmv^0}vEX(|NfmPIOcW!Yxhv6Pbio>7OCud!3|oPDDFN9ryiw+Sy^@0~1s(~*dH z^@%LHCsd5xD1JWCdmr)gyVjB$8YxSiDMNSUO^bovx6H%w9##wfco%Ugo5W3}>&1kR z61x<@#_@1WZ}nee-v>d17aU-A$ukXV%~bU3khh-nEF{3`8P&#iM*9M7&bKAj)25Pk zbk4>bq=hOAm#7P9!gxnn{a;MMwe#NOUAdNfLx&)2`PiS&hYtyOOf(ZuIJm1u#7PX0 zRtR@9w<2RXHd8Tq_Kzq z&wuUR5lM#W5oKdQAlPt^zR!f<30%$HJO5#JNso8>_+apLv>Qh>&x^hwPjJR zGfOn%rOuMP&J&Rh@gNJfXnxrHg~4Cd>_rn?!$B!=Ia*VC%lO>!E>j!w!NL<1enrHO zawdhiF5(BSJ`a=$5yKL1HTr{SfO+otbcxicCVHFQelL|dzStH}V8R%1!UU`kWh%OE zu36gO+BDoBqkpeyhsCLPwtKIs`#*aCvW~yOSVg%UIxL*=5(lnuJpJ)VQz-IT{Ke0l_qV;fDzdQEg)YvVH@J=^enUT9y`;v-P}j(>n~ zUxQ|yN8qzH5Gd;v6C-i%iq41RS~O0k{G!U!iJjq&z0{JyGLdShW{e=)6IBh16)&Ei zEz*qQUPS0@(v5!MYbdayR7!hfgyF171=l&yAXu8c|5dOz$snI(_i>2ghkBVf>1T8O z_vU9cEfT^}Py?kqyXU$?;D{B^u&4ireH=2*eT!O+k9S#qE zVyjga#MB})y7)h8Uq0&qV_d~>zy0Z)ka@$$*5{+l;W3`=(gS+6OamDVYsS1Hbd2Uq zEquA(jeT?txX$yTy?xmltXm#3XQzjiaZY2aBB&1H-qgB?caQY!K~cg(`V6EdhG{C!@eeP~^w9RSPXMoTUij!&@;E?^Am+SYowGup z@2f=Rd(U?w5*$P4Bdkmx!6Ui(3S`FCF8>_WrTbq1KhBnXzkD((bo{NYJ6`I=k3^+> z{@a)Brh&pZ;s(o&2=`y5m2x9fM82=u+m9k+jTR*>2=4vHZlRP5%2eb%I2yYZw4u?4jGgw9Fn)0PnBL5ay=H;!Y zN9zL-b?BVF0blMugz@2fPqL?i&(_+< zi{j~`jU%oFtRBH^#sSq8hYLv`$om5;3{15sc+hypZ@us~lVvmyI5SK4D3~VX-!$S{ z`}#o4vscK6m^Oro%AQ1`C5NQBhZ3XJbUj=a!P&C&_+Jtw z6&ZVB8O+5dXC-YLcLw2$&k<$l7(7)qDD2#xJ}3tN?A_^?_(t3UxwGkbW)ip!3q>I* z6$=Upcg=s)aUW?XWyU(ha9j+_LJNc0hnbH^)A; zf1V$@jeoc@LzKl&oen$Fyp;Uwk}v-9VGE+5-!Cia^rX%I_u13|wm)GE4vXfbg+1HM zn4D{sm;yrLS1CGJQ;XxAr2GEDiuWzGbC)L!MXwyhEF$)$6Jcr1G=N43WPwA5X-TS zI#nC*`0)HKLtNI|_p*8tm#4HIHyiywkr`?>AKXvwcd!ZPhwcR>AAx=skkmM^abXHO zrg7}N9S<{X{`Ms%^4XIZTE9kz)iVk8Uqd^=B3Z-?-+KY}DTa_{k5N>v_)f~15auIx zT)X?Yb4RCf1`(ZhtZGOWZi@SyfPZ7?LdJnRR-09>;F-9>_J#+7+ta`0nl&*ulI&(r zthROrN_Q|lPWug1;|9EzX?In;A=!3FvLKe!j&LHujeqjk{5Z?kAoti*UEkrJwRFNk zqcqj-0UTn8O+(>ByaJse%iuNlO_w?~orw9Z9!C!xJc;Uhaax>0lLOYG|EGVGR-s&@ z&BW{3MTmG&t3&zWl2`FbK8N91=x{?0x)+)b-BEegF< zI;7z8z4AnsWU~(j(YA-fbh!p&oEI}tKqd_wWt>p5zvR-YgD)7`()Mk7y^9w?KrM}V z2O8vS{l0y!!UGkXjxsn3+$rn7iL5LJ$?nMvtMH{cO>jNVP^P*`Nz96Ir(zNe`DS!!&B>jhC@e(>KqDYT8NFA zD2rdO6KNKqOk_6v!jYjGaF5z!Gp(|f3mxREbt;QJ@$ho```Qy#xn$K@p0Po*-}mkp z>|M$0BMGEmYDHD|!htofp~y2AWLINB@t%A9_aKVj1?o8MDvt4`W>p5|me1S+Z-EfbKdQU5Xv zUFQxL;Bohf-Sk~)pO&s#LHSNJsPe|y|4m<_^EwmyR~CeSTU?)H?N=Xe;?9P}zD_I! zafyqgyNf;AHrqY{Ls=Q?!rSkkXLZlqt-Ha*tUhpLqy2q$Nig0AjBe&}coKM@QW_)4 zhFxu&T0S1kIDR;<^ETPcL=|o8Z=ODb%bN+;jawb`a~a%uCSzJyG@NGFB{+7~#+)tu zvesLT#{`8$CZ6a;jKBO0cJ9@a<0ZoJn$++rzn1RySc!|D zXsPp8#IDUzvD=k1Ieh>x2N0$#TF>)Fg|=Wt|DZGJ;Pv>(t1nW%qo zKH1o&UGV~zQ4e&M7)gukEwXqZ$AKSGS7=F?5-td7bSddkB=Pl z(Trt;%)YglP+KBcht7~r`@=2$Ai_pQ`u&LZdi`+ z($viVVv89?I~6f@f87UF${z@Pk7cTy0cQc6-&gaohcidl6vs8PY3awICsj})vYemS zit&9`CGuI~@|UUjaPE)AaA3;r4Ayw##zU6avZ=)E$Lw$t;wR>n^9P$XgSeePP;l?3D1L-tL?Ya^z~2g6Zz&Z>%SVNlxvtp{0U8Ajna3`4aQpJ8L2GA;d*snCvY$*3@k*6pzJ znyqu<@EE?e={lxr6eFRE6v~NRHlp~OA7SpcoblNdHysKd7F=j=*)id{LomolAJ6C9 z7NfHyUzbx+7;Rubn7Sxhz8{6t6o6+v`;>H&J}9eKKg*b4*!=7?=yEdVE~eoy>N*&e?9^x&0D>0zeTA1adz?4{Z6`^1+BC(8-@WaK;>fQI&45Fz%f} zPRP&!w$1=M3&!gH`8RT2dkJ1K& z(Jc{UYF{F>*Rx)DlUDBhGQH}6#r59XfOe2N(Fp$V>WoY7zOVTP-Uy)Q^!+q+96V5g z|K=d5x)WP8nd@s=M&iBy9~PgDLE)SBV+jNsOfZcw8vJ_retiev6vH&~h{sJ!rc%UW zX!O`gIkArriO3RF3sR<>Iv$!gn0umiFuWGKHW$hcQ9|Bp<9+z^@nJ4Z0xhTgDyDMt zc*RpsndEuvy4-%bOAnnW^W<(2zvp7@=E|K8_RZ#*=Ofez*R}M4Z>bGqLwwRR2}4&H zt)J%`9JuNSY*i^B50r2Kk46OPbwCl)VE8A_*YA`Zjht?Wm$&B9eQKZ&LEyE8W8$wU zx-m)&KKIlX6!QKUa%!NutVQ}3#m45E(=WIUy3`DE}nqsGGc)cDNvBp=;}KmufP@ohJ(H)$5R!Dqva zF<%Kw2wnaVg#lTCCzFGnyG^)fwP!$L!5(^2OQRTTHBpM$Ok1Ar%Bgw_SFN)w)hor=S^dCOqb>x zE4DL1&gZSK6&Lbg*dQ=LxRz%t`Z!X#6X)P8#aX>4bGA{Em(D_f2tdV7VUbw!R6xr~_+h)#e zL~V@!{C`Nk{6?ZTJEg(ouLbAx)EG>+uPuCObXZ6UQ_ZKrcR$F25vNP0&dOe#c3v5M zF>U-rzi|_=cJr7#AjhMjhen&OO6pNP`bJOdc(oNd8L4IyL~kwpr<%Iv`Vg5Dumesv z#$JnYdMY?v_$C+mG)l5Ko;G3oi1n# zi6~3baqdgQgvVqywwuF4`ZB+fNn<%{$0w3Xu?X2T=vrc?mR0Befv8Ac$P?+9qZbb z&&7a?$&WO3FsE?lp>zS4$U@0C3Tbn8+<(1M`@k0%wU2P_Q{YE|sQp@tqjetg5e6il zv*|_?mxq_GWW+%LU3W7Tf+{P@#XUAJkxs&oioL5*X)RHyAI>)|U_9cYI?D`^HhI@d z=$7ji5Q6X#p#qm%et=@J`cZ^I&%983ar8E!;EVG+lEYLUL8GOUrMElzJJn~@t;JlZ znd|v3n4rqo2RUVRP`AX*2Dr0%?W&I1Q-sA~J$#t66(bpIrQ~87*QrTol1^!+r2L8Y zqcKST4acU=DvY?yi0=MIwRh^Py|tc8qHFI9uCV%t)1e4MAUDIjY}TAt8<`DZ*z zVir;>4Y=jLxaPt$FEsOZUng|GNiH&z{DWbnbE9DC5a2+&vL^D#&~i9q?O{XgcUOo= zt)9sv?hl*?a-24WDn8<`385JKy^Jdp6;SWQKd!<@84ei-o?>bM=-9LurW(reV0et{ zn7F%O%YKz|hvO!~a&NoWxSQj1ulY{eD)@8@*nJtbe(n^sPA@TlBV$>v?m{QD- zRS=7GI9N<)LRq58ud0>+%7!%zp+p=$s8JW-YJaJ|imfV7DBW}LJ0ZPgb9Lb6J;R+3 zMY#}ZlSO{>^Uhnr7N}r$>Xm7w-SB}ptf|30{R!c%aJQ?UXvfYWbsd|F;)O%bRzNeL)@ln&BLF)V%CUM@cE8Nh_K;+;4(6(kh$RCmRl5=A$ z)JIPE6Q@dhh+(&weOn_F))}ppQ`12Xz;P~gG-J*YVGaqSoFaBh^3rT2GHo>IXjM_N zL>VVjG8`dZ)}GOc?OYim8oqg&`0^f)3n+oZZ#9yv1lVbwTQCL&mpj=V`>M;9FF9fU zY69r)6f%XtMv&RsN_X;H6_mGgR|Ad$LU{~4z}4o_>G;2i?P_bI+x11eF;H>TK%A)= z20R`uud`&d3-b4DOWL{K)+(#%Y0%7xI%0|-MhrW_7JOV}ZKJ8klxEsmB~q|!+M%B> zx@x?&J2WQV&Gw&lz2;JdUbn);`LxpuRx?5lX_`K;TZ(@AEnvY-z8`KTZGmJ&AkV+4 zO1Pi;V)@y)jKok&(O^QY1)OiNbXg$3-PSM6iVStkzfh;klfq`t8t$&5TW#DvF+G@z ziIfwxv_gPI(i(3qCYunyN;|K&60gpC#D~~zES@CrT{5LmcdwQ=p@=L6hF|jx?5d%e zj^@Viez`b_pLunCHl{A+^`sh)F;vs`DwOMAzaRKhgmxmcL+zIV2SO*>;Y(lrF}S;! zQw%1Q9jB(ClmWj8Gf({HYb(4{+RUFHKAhd5`$6)KoGn$r=JVr^Ba%TODa;&(tF<=P z!>e%wpwDMDp}~*+^N%JrSqobiDlU)1M{cF~pmo2k6o8TGsKOvv^5#bM$gk*?nNEfL zgNp3_j{?x97BHm?$Xxd}-X?RA!a{b!K-M|g7>RC!y=3geME0dQ84gdMC(MWqF1mFr zsx)Bg@IlLu&dD7SCZ)*iaQ#1xY|}ZVAN3jQ2TwTWT}jKV&X#+Xl7FTi(;36=KtLb+ zr2J22dUQiNbP0lZkIr7as{60I%UfF#-Un5a?4A}ZJPEBpl;Hr2$V;q8Rt}w_ihN=c zu8S+2=Rx1&^KRBx2y>B2JrD|sw9~gVY4q10@wt@rExvM8?IArrxh>W)!kKS7a^sM` zt8PD)ZYXbzx#@+q<<$}yz8YW>=toe54gfk|G`}(sRN%&Lwhl{Rj7f8-px?MEr zqB!Zy@MQ10TKxG%;Ax~J;9I`xU@L)_idxfIfdov1)2khN>{>D|I`r|r`CPPK_&hNO zD`owOVUta^K#?xCP@8k_bvDcPj4e0XIrAWw(g43vd5tUz-uw!~pkE`E+U_3WucA#g zTD^iU3O>yb9ZoTy>{oq%@H#ft;CiP|(`X^Z5LJNuHYQ#^3m*PEKKS2y(q>wL8glMR zK2STyz3|exc8B2r$Coqkq;?NEFYVt_(EPxhCx0DU#a!OLqKW8>(^{AsS%6ZfT? z^x7R6Of@9E8$;lcpJOt@=x?0dTW8xJbNR#8dob&|dY0q>E+qxu%7=!cS9vG)tTnFLFzo&^@OR*V+ZM=gyQ;zJ z1mk;sQDDSW8V$mYs3&<{F9ANah7T+k8?D=TF*=@TJjnX4EndQvb>pLh=N`qfos=S}f$3&>3*`CD4f7hp^tUF2kngSu}Hepiol z*27_2b4yfn;_+d6UM(j#Va{WKsHMBDEIQs;vFB9)wUv^y)^>=+6UBGyvihJaPpJQXTRr%rylXLJZ?cLf>s3^i zWpGaUFf$F7!{4D+Elk0I2=&=FGrxG|{&1~lBfYv3MvExkrcqq@iRYQgF4puODL18~ zoFM(Jq4g1d;x(rUXh%e5&g3h8+~GhMil_~p#InU7;>q{~)fCAP6jESz{yInB!twLz z1NPW)?YV4x6o!WLsci7#=jW{8Y+dEyosQ4Mu*1B0hp6ha0 z+W4=o7UP-Anjr00$iuT5OO4Z9uHzVKYGqDHRq&`W=&5quN(Jn)AoLNTXWZp$PZQ(X zS3RwY<-P|8jB(-jsy{!jWf`|Mi?24JVC#&~9gsz|JU-{bj1Ybe)P-KG|>I;XDR2rXVJ{_{X{B)dqE?X&Q^Z;Q9Q)DD1mh zCUN}L%VC|^_S{{)*HqKf|3}kT_%*@3Z-XEq9ZGjgNHaz^h_uov-Q6+ihA|pONF&`H zf;7@C-QAtJTTDWo-mp{n|W2P&j+-wxrYN?&A={jkECGKezH!02~TqOy`BI z(OF$ow6_eX=H>(q6$}9 zN{aY7(0mpx(0Oq!YiE&n6zwj6*1RkRyD-zO`l!znirvS^efuuRcwg6&8I!mQMCYyW zylh`_|LkLuFek-@TPMpde(aRHFKLy*7Mjq|EAvjuXu&6|dG$O9Bh}YAnx*#03j<#EYQTv;H$!ds>?~JGuwgwOFXvh7) zK?H#DB#>f|mBjrRK=$E{Hgyz8R7O@Zr_Q4J@S?l}$&GuHZadIad?H>4Kpie8YAvn^ zUgLm#l~tq~zg?iyl%}ojQdl~4tvpp&|0Jre0KIo)LCYuqWh=ki zb1P;itdvZriU@1@6ijlvr~NSvSYvk)nBcNj2kj(5%`*nl2QzOW>!1~)@IHi*^c zj_2Tcrsux0LXxHP2G$A6&n1gHI4Nz0xj)|OeAqI|z=QaJMuI^B@!`IkI?3iAch)2# z8Po^vCcamh{&|isqse^NCrKQ!;)i??**Gg+kt&8{5#pTYy@Lz=6 zQ1h)>UT#-|$c_cjT&?>27L0fn%NR~VYYi3^j})Z!)PD&9%|o&%9#1L0Cc|C$a>Q{@ zpeX)HPc>cn-YL}O{$QuC{Wr993rxE?SF=-mO;9n*0v8Ua|FPWnVA_hD@LKJ}&s&f| zoGV}6bH!uQ_Lq&zV|RG7inseU{6*vAAcfk?>9euU>Lv~7`29ymb4}@(&Ii>J9UEsv z-590Lb7y&#(k$&I9I94L2Tr#|@5^wdWylf@BEyUIQPmR7H4l@IZm0qb_7Ud*J^|$6 ze0|h}eAWgwA4;97Zohm6OPfv8gj*9k7J^gC)zx`tSgWtZX=#o<^lqZlIB`{JNcA|r zj1JME@+yNS&Ng!}07Uc`ahmbk}DI5Kfte>~lmcK*;cRx{4qnjI;tALS@B zXSE{1)*Qmz^yJw#md4z6ieCzL=6WjKJ^>x3cN|fcoQCoHIFt^CnFY|aB0Yw%3{qM7 zpT|N)maX|2!WED8yg3jV+!Zg9C=_GNKfF6mBy|Pt(^&WQ{G6wGnk8Cm_Ftx2XnnZyAR(`;Yv6fFn7PMoU3PrpnZA{Ep$^N|MgJY1N67#XD49t9t@^`T4f1W*w!xQ( zt;oaw1i@hNX>$jAqOG3~TKL+}&Kph0S-&~*pNS`L#|AnMhI`^V(wCX6T!sv7;5shO z#>IR2fWFWoChymgxccT(Z?sGE(I)8>e$_G8KH0Ckr$W<0)V6S9RzN)`A3gc&8^tK% zE=eMOsJZ!^8(UQ`I3m=%xlYivBfJs~TB&TC?w`&OP%0a&6arv`ybq8TET$Onj+r#9 zN;vq~=hEJJ*I~Z%(L4{^r#%euUdBT#$<%ZUXa&5%0L|5PwKOHrT)YQvimK zYEyOJ7jhN13!9C;`&ruU*!Pm=qkxHpFm@nS>@M<4kZMt5LgQlkI8g1pJnZ5#=-*UK z^rkM>7;zG^Yexii`?}VWH5o0cX;;fuitu#;o9y`rGJ{0M8#z(|{oI&Pl*ZEAG>Udu zPbka=PLOoMBO70Z+$^Ed-fdrT8=4W8G@3<(p;TJ(Z zwwF`%9}~Dw`c_-;$J=3`rx}3~G!=i{Lt6LfN2=S&Vteeo7jl>JzOaObc)yI5aerbsVKXfZC zzjmosiLLV--(&ygV+%v^OISC^-|7y=(6Vaftxx#0chKM(G$L>Jzz~-Q9>8<4%K;fO zi*RmM^TOtqcr7=5pYc0+`f>2rQr1x!@%J|gHe^h1oizW^xQrTmZ#e#S_N8d#yRtO~ z_-G%tX%*3JsY~yF?plPc2Ur1OEXCd2V!)os1?CQM_3Hu{v)lkIm8Oq2oQ%RE5-~N^ z)k`%XDNM6vVPpdsK?M!x3~N74n_TbC?#LE?#*86;u{I6jD8H#gjgHzf;(TU&YNe)_ z&}GVCtQH-}Dv(ZmDE$4OR!=2fQT*Dh1Zfk0=>n1j+PO`0MT1DYi%_0X-rg7%4G#9r z@#Rz%P%|xSn z<)SLw0n$rldEI@Fm(Vh1pc!FR)J$neaJOR;?hlNws-iwSz=g~}mSrxvGsXk+dAMrc zkT*>7ejIvYAR8F`Xpf)06no6eZ7AW0R#J2w>qhJ`&Kd;772-ku$Sj4p)((!OYjy}1 zKF$h@@gCF08PJ&^i3P#>yS-~apO=6xqA6YYjkfdKS;9XWfE|fa2g<)q3KYc$ZbZF2 z?6)!~s)vG0ba;h}X0wv|7&B^t0i25ObB?EdWm9!uHw$N()zXRai7em4B%(`>R#Os9 z(?FFHJ3M3*L535lt|4%p1T|_{I1Klg6PcMl-B{0^$T`ksB*>29`?aRJ6N{m&TwJUJ zu*sonn;+g7mw-0m#Dup?!DT88H0njUv(y9&@Yh8{ zrA(_Q7$*fZ$g<8|wt`*s$?(~@9GZZ*_T7ntr--3AP&zQU%a?5+022SDF)H;GG`I1z zIjKrou{v?MYh&Iw0X;IjcYnUsq1?N2DETMzGFg}-V|#q%^K(`H(c0ti%;c#^%Xl64 zTq&rHuWC7NtTmAT)^m&b6aVo{0gBzX1uq{0@&lcx26_lyvfT-((Kz$(QoFOY}DK(y2#pOls!tI)26CPss3|c{oCKX3IkK z?T@t|-}bBjoNm*Iu@1_mXC@{1t_#9tYO#9Q`nbdMCUf(MsrRSXMiuf zFMJhOGgY5aq?T-+5&r!gCfwkHg0y6fXIxQ8!d+(8pBya{DuMY~=R5rr=&teek~z^B z?lqe)wFDlk^08ur+Zinlzs4Z*b#YmbN%E&-`zBIahW(g_!1eYV$y1?4a3;aWGxM{MRRF)xE0h0QxWXH*F_wVAmcwmmstgWY_q@Yoo(sP88B(GHKmVYny_`A>E z>IG0~2R6y`c4$4_XVxbNCHJ_;lmeZusyP}y0^)EwJ|drU9*w8osGkX?YdM`ivtD^J z`45RaSK=t})?0NU)go8(uIe7H+QB5LE;cdLPA?ZZ*hxV)D-Pem&_+oQDsN?{uF!Z@ z+2^tLV2ib4t$Uo~1IJ~~cY;|09X_)VSw+-Z^_~t59!WN>Qnnrt2M%tWPk2*^_lbh* zPaKO{TR5EbTW>t~(+i0!FMUOa5>-U6(q!759)b?+>&2@=cBQgbJWx-;pa8K*Ce@A!f97AB}dQdwr(um zhMhexJv@7g!R36T)t_u_%N5l9)uC)I--kv3eX&&_@)OrnkG;>${G>(CtoUXci|uHq zvsuh~BI{|7!Zv(l1A{h?M+iL^r$r_inkV&r;=s5zVD+*%Hj2WttBroqhAJR9;o@iyis|#BZw&9!5G52%kKbz}jOTQmLiT?^E8#iH~(Y z0SWHnal+TYz|KX!dti(&@L6*ke+0DL2MxxlWMU7PXevymap7VbRyXr3SdFj8;yfO! zVppb~sl-BP$+eGFN$9} zspeUajzb}mSB$bky-hMmC-o#IIe%mmnOgmch7SV-_fxQJ-;!M9D-RKFTSL5{Sj zh-P$htDlC(2owJuU z3zQZe&>q*lD@HFx&(XJZAL?g|^WNj?Y)bC5IwzYog<_`F+odyI|CL%!yRAyn$s%=nv|z2 zjxtP!07XXiLQmw*zcGuB`~pPRFFA%I*QA*}NvZoQ=A1n% z>nRwkPLc?sk0OWUx8AW#3QL;)VWvGUjfkE*F={#tqE4RY0)CIgnk-`I$ZFp3C<5n7{UmQS5K! zcsFj*oqdd?Xew1N;<|7tl3p^S&8LO3*p-WyJ`=!#L_og+Hnxx^@na z0R_C_pAQjpk*2*_NBkf?^6y7dcHaTmS9Z|l$2%|mOJ?|*ZNYYcN+|$m(}*-Y6P817 zWJ>_FHQ;QYNs><*$+77)GmqnOSX_B7F9fNIZWVpol(nl=cAP`jU3-m za}@?>FZ9+`_w#lRC@sT6Ji6DZNeHS07r&qP#YKzK-#3Dlu?9b^%nR$)C}iasvl^&q zgpqAwJ^gM#L3Xvb7@UHlraCP_3F4k$x3O}5m8l%aSoK0q%^3zV3+sZ)Xz9fy7{_;&U zGFQeZzd2v)^)Gqvs~#5%5YAu*laZEz=bn5u-2)mt1eDcM=l$}t&$GHd;mZGhP4zYy zTvP$t=!n`}2R%O-Xq`WU7v&#{yvp-8OcTbAF=kGhc6>-$_Y(;|d9J9nLrKGBn-*Iu zqUC&G^X|?Jko#=F)gKp&vPjX;ZyNx1ZCO1M^pLYk&vz>sa5sXWrOR#$QfZYGiX4E&N@C+ zNFz!_qio%Pz6u;MuK=z9iducLB6d1$l|;REP;Jc%j#3=#fjbkfcF$9-ei9*35V8)` zn~q4KwQZQM;Aa77=6HpOywvV|dEW9~)S(`K$6-$KJ~UM#<~ZwOWKmFsmcbv-O4ejT zI9%55*-_#<#N8V4IQn*f$N;Iu?ZoD0=`sK2NzsKf$XjsTwR^&dw$P}!@#*)I|K_1r zH+)SeZ5J2RMPw~SB~8@+d*6CK9MMP@WoxdpH23cvR5xA_?T!}n7bohmp?f@;;mLa^ z_~hb~1*&}I@S#jcH5?V?0obZ$jZzrMB)~%hq1WJ4X07%_sycw+eErW{0SP(S4cV1s{B zja}rhU$J|_v9|!DMB0HE-B*-Zw4M7wLBzy_d>yv-#fcpiGPlIcfqfL{4>g{o9MxF2 z>if)HfvtA52AhKuH|-`k+aB&ERFyzPaNIKoE;vDOZES*(+YyH?L)vZpIK}D>?>u$s z7DcD*DFzrXT$%;_{z`z9?j5@m9ujc|bJ}aXj!IR&s?7>$jL;js!xumf%$Q*Rm^t_yAU}^tJt$ zJMWF^D}m!y=8k0`CXnQ~ktTRU)jj4FHpb3E(R=1+#~vkp1Nw0Dmmux;kE9%H+I%#X z$v#Tt1;e5PM7?)mxSq1>625GbM60E4FP^;xOaQ^ldXXJmN9~JZqU2vB=++oz2!%I3 zlx$diLSK`sm3C?2Zd}^-d6Ice%LMMlCirx$Iz|ru7_zgVzeU~r*vCU1_xE30(sIqI z)aXmFtcFRPq6Y{G)1?bDdog}I(mJQr%17ga7_)jN$L=l(;{%jdeSk}Bzpg`7BT>@m z?gl3tcHJBm!~;VnADl6z8E5;4b1+l?nP68YlwBCu z5B%`sSKlYwE`^xDh2jSX6i8)Wk}M{mXk%-$2upq{pOdEuda6V{#xc&?@aWodLl2)^ z-mwWmTb^5%hZ#;XYCa+zC}Q0+ov%}(#@XQy@2)OB zc=eA+pivnd+3KRlhVALyzvF(=HOf?mn+#q1&Nj^fIlSYBaPRN>F5_<<4ZhIw+TUO3 z)Oa;rm*tZ25y2E%(7px4%dF-pM3cUAM3a%wJ%*VSgwk|V^Hcbr%Mk!VnJ(qIVKrBd zI!(EiBr!4rh`O%XU+~KW;ae|Rp_6QVf(@tuRoX0{sAU!NfoHowCw`l;I^q|wm3=E6KmV99P>W!q z`f91gjhA-kCIGfr&;ie+ZY`(kecB^)hAk{CB=_`qJxGJ_Xupihjfc5ARlDruq9orh zFU*c6A~|)mm={Fv>LNz1a+k_+$DY~y-WqFRdj=c)s`*)mH4AClynDv7Z_IxxftOpE zz19Tz5Wn7aarIv_ zpeT0Mq(f`OpTjaqO|f%V5t*EAlEJlQ-y{_5IG!su8Bh-x)gHFaHY-%!A!<{XU&#oW zj(*8j?B*`nUp*sy{ijbiSD6&YPrkrsM-5U2N@VH1t1dahOp&?zd0MR)WR5Z{goKmYZ5u7aH0}l8Rxe?nCOv&!)^U8*SaIAl40Q+C}lybmF+4ikrPE zO^Z8L>Ex|KL?QTtWSSyG7I=kZHRNw#oy!h- z2&qL~lkLARx&^*DYjqm>3(r&zchCL^HD?R=4Q8|c z&ZHmtcBzLBSnKaAb16#-IY9jkR0n-^*Z;%($J!Lz^J}umh0o6%ED5X@`KZp27>O^u(ho@!G+U6+bm(n8HxGUwQ5>v~M?9 zH%zf|Bh^!x(hh%SyLSDCaV3b7oxHMw*Kn_PdxQj2YE51xkY>==kyHKendqA}a$|WD zSRV0Em6Azo?kM?Uv@Be3C%on6U!3F>O&vZ52Gz~@=FGafPd(y;vH=B zPX^j}BLo_;c7?Sf(t0Uj5m-djBzk3C`0(`a>FT4Q2 zT2&hrZ&rtC^AczhMe#pk-VD=o`9|M5CHFWTVXWV=PVd|PGz+ZV)M|;30t5#-o#^Q)zPq4P zNevE0^+O@-1uLe)nmZ?oKXgY-8SNMU=~Si8;)BsohcMr1? zi|Kd|($(uhnP>PEwH9mEgtEuBS<5IeEZ16U6BTKSh$D-@fD_(<;X;_g|Bfuu4^hPB z;#4$n`kVIms?cESQG}2oTKAWJ{Ek>uuo#1i^%x4jt>~fTa^_wsj=mx|yB$&i&e~%e zqP!w@6!AJqh1K*RlO@0gh+#oKzuo%r`zOy`Z~y8JM$w^SK-oL7F~b5WaS)@z&c`LEIs(Uk3x-PJDb zf=e~g4iGx?ov3IQp*;!3eHp!LKZ+lOq~fMu)JR&t$TonQOs&SA|MIwU37o8nN_dgm zJ#Pz@GE=5D*#-udku;zGM;SK+IIgaXj42g-L#fnXXNt_ri?{5BzF2R@L0{sd+_Joq zFAur0iR&Z{^qeaCsr4Gm+i2-`w?2jm5sg&%Q~t2ta47F6`8BEJ+V3_l6Bgja_D`M_ zy3|tY2V!iVAs3928H;%6|CdrgvJ<&pm7^A-{eZt&Y~wENRL*zln%8QKwyK^~#dS7t z?=%)vub$TGJmA(scVGR_n=2k~y>Sc@+HGgASnGA(gTDgvC3Ok}vz`Gm%zU=#o_2OE zb1%2dd+t#aaKd7E9G*9!L@jkRq}D&EBKGZ!05up9n(0>NO7jMFty==iVwIoIKb^~% zMC@gkq>$9c#ZZ3yRW{iW;7=vPIn4o05`~yd>_?-O8TluNl_AE1jIKD)m;W}oUp;0J zm%CR{`L=IT*i(iS)@EMKb8BC)&|f7AleSE0d@{)vfEQJDke9%&|MK%cEd!)(FE|E# zndqgIZ(xIRj^&gK5INuEG?No_#M$vF5}r%s!4fWP zF43P^WhH5be-w*91t7FdMmYM6>n~U=E`&Y1V)}f;9>@uA8{N#89-+T7dxEKo&R~Dn z&}!vw8Ham8Nr)xdQYRnN|C{t3?oa-S&m^X8RDWyJRvag2?|+PTm^#rLzKFy4S(s!c zs__}!UH#OZNL-+*NGcZDJ?EFfh(0*FySL&=CH-sn7OqSeyHtraELL9DS6!wsjC15~ zfv+bF28bp5DgqUC(P`*@Sk|7?{hwLGZTjj2#Yn9;3+d&D1^tnTkc^4TC;E%8f5S3IEX;r(AZ+)bEmT3+?~TF&!}KxBrJC$T6LCgQ@yEZuF_n`eW85 zV~$)KKmXQG+9m14;Pulb1We(AMG()zjxWVn>r?77_GZhb$^z349W=gvY!grdaVPEpwgW%$z_&=Ogw6U zZx}KC$=X2J(fp*AY@r~LqP45y!GGeDuKrKcl-gCH%aK=W5slON#w?dCh`On zAjj8OnyZAnudAC+pcDCuI)!%?ig~b&j>Vq`UE{00#t8s`DO@IS7?&&e(`4X!*t1KO z1cPm<3$lbBT** zWcojLuLl$o@@ypor(F()0{^L;omz<(#n*p+0yeW9P=Wgt<27hdGpGp+FK-R7*K)%~ za^7)2!ChKL7bLgR4@j3qzmu9e!dfKk;}outP~qG5un1V&5aCqLp5TDfiJ7lQYZo!E z|H@UD2D%>JVU7BoZZN&w1~0b7Nn~E912!<}eT~F6~IE-4&U9quN=wn!N9Q zjDTU_EmhHj2e$=TwuMm4?vPE%u1P~pHp7)5Rx9@1 z7-YjIm^_zeR^uu+J7E&yqBX_KSlHSaY3J`;IGHiRQfd5mMSn`ZFw0U@#Kj7uhC73a zRkUaf?;i89e4|_qgdeqU^Y`%n+xge&UHVevuoU3o*<=VRsejI_%Rb~k6>I|;k0RqB z3S!M3TZU5Az~n|?)%bMZ_?^)#1!n+mY;(RC!fJ-OPvL}oqJgc*rsz#qFf7>^;jhgl zQC7)c+hiGUw}yrN)y4{kDJ%qK5xdMl>n}o$nAig*E5G_2oN_dpzX-NI)>@`m-RH#@ z+RCu}R~GdC?kzsH|JRET3JKb&35Cyu+V(#AT$PwLA|)OW^Uw9YpYE6BZP<%OW6?Jd zW-qYI?q3CtSEX>h#xxZ7$s3*&oM<^~(B53A8y@}hZ`}C4+yQ=t!*P?WBv-GUmRlQx zW}^!OfmHhd%+Yx-S6GC*&&Fb_Ju!1%50JSus+CpB@@sC`>jbHM%;BceX&)KC(8t6n zvUkl-Y(Jmq`;CPef>ajrUu3-fR~Xy1BFuvvOO_g{ak7Xma;p3997aWhY0YhQe(9e2 zYlAR1|0v{*xOx@{hrBJiG%&^1+tp2lr4|2N zI4r?`WxMMpbU5i<84>L^&~-Jz;Dk$42utRM5!}{_f=bs=qxMThin%7xvXn!!7YyX{;4|6Zr-;FD}5rQ@fH|GquIvxmiYY}-Os6Y3eQ@U zT)kh0W-Y5@hsG^MTBs7vTZ}2>CJ|(!HevGHCCGp#INZGgTgNEL5DftEju zkLzv6O~g*;5KIj2e<@a-yfNr$is*-T=DP>i7-Rl{a&u{Dd0zZ4bt1TC*DXL^o>_v1 z!0e^6i&HuDBh}%>f!7c2-<#kMqTnon?cFzCe`xKy-~zTxIDw(!aF&p)(wvlcF|8Qx zkW79PdRdquT%At+1U1QO<7&;5xzA?EZ_>PsqE+l>f<9nyc1>UQaQEhWBnV5rt;Y{? zADQRh6aM$4_|Kghrj0~;YCtZC__B+pRFAk5S#J;X_W#_02aemxV|;Ik^ZH}zhFIO; zaL(;#T`~P$&oJp9A3gDRKSsm0Krde={w;jJLAUPl@yt;G-^RiviIJo64g%b!~eXzF)y1!KNK(= zDD6AQb559+jBac-vMg;al`xQL5?6qJcs(kgRv$~kas?r}eCIPv39f79BoJ${j^cXM z`}U_ED19wNBV$Gz7WZDSUDJ2<_64d2H_}yB)l~NOC$GqAklA12$wawJyfL}Yrt6Tu zakYXxGu7sP8=~P@udr4h&)ox+F5J)k#NW!69GLTsE@PJUu`@%$#eyxCrncfsvm6Er zhMA7;_6$$NX!v2H{=to6i3{Lg=lj^L9k zvg*o`Gnx?9u;%CQW+t0o?~ImwMPw!Ur3sMv5C(B}?yG{$bwVdHx%`Oyl17lM6wqRqFmHVC!w(Fip_qv+WaYQ00-78Qw^%rBg576}9}==u(d_C(ea4af zcYRQj%V>BPKC8mKTNe9wcn6AZ8cf(Udi7NaKhOyG^l>{;D6qVTpNjF0T6vq8{9dbD z_+0g2%hTG?)URD8Ny&sE8I)M&hX)H-T`H$h3stq~>liUS@A|GMH*HOKg{<8N0%`<| zs|IWcAzSn-eRkksnSY6gF2P-n^F>Fm+*9>;u}4|4Llge|r29*Y6Abq?57-GTzyZId zw;wolo-wzOM|h*Iw-O9kduBgprj#oB_efYP(h7`2CZX7{@n8>VRmfc!55{%{5>>-6 zo3A#PLb^(xp$2GEVWAO2jfk`nnu=!j5RcY0SyLR63~9;)1P4$rGT%j5z^n~WJ;2V0 z*xCz;2a+#PJ@l3I_^(OCfmn9V&e_w|A>mPtKN+ z==Y*{EHfZ78X!bkgWA=DR5u7J`ww*UDW~(Wl!#*P4X|B;O5cQ?d=A-xJm{F4!eA;&(s@n@O_+hevF8 zJ5FGU>dy^ePDwQhvjz7xhVBRo-k0KJye1~2`aN^URqyX)3#601@WW&_F80AnI=+nD{FLTZJASi?Ikm$|6Cs>yVMwtODKs=t z=D#9$2%~n{2W}}Y6vS6`*yQtQm3m`+CZVvXp{ZGfJf!p~MT%Hv3^~tYO>St))Wpyi zSTl8)5a@K;*#YGhi9JU4u&PH}7BrQFC5>HVHl>#%d(z=9htyZ+hE*X0Z?&BjasCzJ zgrqsX4P)<7RcjmBis8B`>cQD8Ea@RrA%_7D$S^`{Ud7Vnf>R(2?PzozZBh&52?Lral!R-X%F(;8kYr^Ch$DnONev2W7Z84TjH-Y5iQ z7w2sKJMOgPc+R!*oQw9^+qpOYxO{ko!F5pd8rNMa027N(a>r(edpQg?`WlN|u|!d9 z$J)U<0xj4KP5sa89agKaxEg}+yKzKKBI*YY>I%x;*Wa#}=88f}4NEu*qgxlL~dpj)Y6wfO(v1D#T<ZAi3Nc*Rqc^ z7;ZL8!hbr2XZkCo2Y@bwbosGTQ`2VX#dsZK&iavRdplMCT6c;oUC6>mFt%M`1Jljh z;EKbc5d*hDR9lubX<~{* zbJ%%fvVLWt08_P|MW{t($Ex7@P?5*bt0y^t&ej%dw5KLINE=}*RDh+K6w|ZDCWJdK zI*a1mmrVtXO_73GsV065kMHD@5_xbT7MZ;K$VO&&W?N881E|uuSiXQmw4|V$s zlhu5^`l~>$`bs>zQfcPy-IQ*L41@J?ABY$m@)Us6K6=bWd8ZEU+!HIZaL=B0C$C#0 zhTp27T__2Z6>u?(3Zh2vz@6n^TuqWsBOe*(!b4F`4nsn5lI^9`49ub1X;T`mqYZ|A zPZZjrz_I5e%AtVZN~Sx7T9@@GUA3CssEW30LHmdlHMh+yj_i12o{%^HL-o*=WkwSa z8;tDx1Wee=Hx(=Z9l~|CDH;2^__E_>kl0oz27=atkZuYT8+~?Q?dpGps$Zq8vH7^% zDUY!1Jezz?*DyLK;VA8ZwB59v8Z8#Jp49vI#3wzVc~_nIYD{pFm^!uc25!MXPu0*? z6>qAJ>%HCnanOgD%pk+9sRAR^fo4lMOecYngc6$AZd-D;dte#`=GyPV*v`X6q`4}P zZ?mVetsAV2*q`%WB|Mx5)h?~@xq%+bqV)d$m`p9Fo@>Wic_r&@vs;zrl!+5-9klrIN3Z zS@M2n5SMVC2=s(a%ac}p%JGuKiK0K}yNo_`&OPKG$J&m)*yI7}j8%Ls14E@l5X#Pz2j917gQw|+Q@?9sS$kI{-|4!z`D)$woi*j_C29I_iylK!EBiPxI-&_p5Z#( z0V7MO_IZswRIrTUfPv!X@KUb$d+#w(cv{#OTC@<^gb#b5FxpOEppf9>FsY!UA$g|v zx%6E901Fmu2S?V({Zs{0-nu-jn#$+DuA(P(|IOwthb5lXJMg7l#=!}?J<*qMShYu$ z-`(-^MoVPw+S(@EiXbd&Q(#V#S4iMQ#MNAB%6)#LQxQcbGX@lav3o zZ|S~A+mN(KT>RQUPCRZ&ljiy(fb1l)dt-XeegyQ3%X(z4fV5_5la{V$?ZcOte~uw? zps;xtg16&Da!B=4c+^H?swf$y+n1-%Q2Rrn#V;ddhjZ;X^{}(_7S}EPer@{^fbY|U z_SepyE*w@ZWbB$w-Glmpo2vjc4%FItac8S7N`qQSM91a7TesL_1qYlA5#I(@eMQp*nGKM2(DwR1zkJ_8G;RstsOlgRc>1fBPgfWReXS(fT~e~LLUUze>pNua zVqj`Kw|qiE7$kglL3K#nW}<1EDP|xcCR8Q2%rap7VWF7={Ch29?D&bXZh1&T;Z>r~ z8yiWkJ;K7@Q5LePT8{!N*zhye8%xsv&|D=NK=x8S?JzQ9{Tw3z41O2M zR6mRdjWuEN(g!iJv@O&R{J#E6Vt8@c$s&jm;u@BFL7pk(gB~-Ck-oBBvR?`MM@{1x zTHLTsVY%Cl+E%6~uhctAf0WM6kMBfeF8ic)n57vC4Dyl3)Gi;16UL-Vg|sI4y7+*0 zN=vanuFu?iv8fS(4d?t}kB+0Jrye6okifRkaFX`=F`qm*q@Tp;%BJ2+Z;IXi0eO_t z0a5Ke9xy$Q(v?D4F$Tgrtvf(>TsPeaH*Pc5e9vq8fRmPn?u$>0NZFeLBbtiLc#M`- z=RX;I%j{$Z4&yg^(NE-8++(dA`{JrnI3=W#(}X#7tqqjNCFDz={9T z6<4k4MWe1jJ`fk^@1ak3=Wmx?LjbD$&}YvkI49M*Us@hp9+NQP`@$tMf&I_ zr0aA+YIP}c%yq|phZn~X+*x=|5)CAovW;$;KnfAy=w|b%@J)y0ayj33luyUAFvQ01 z2lpZU_jcz73Cke zBgZ^OGt^`9V9!6@sLE}=&A$`N*YP&%Kz-M~oQ4_39P&C;lst=sO|b$=9sK;U#(OfQY^28Hq^ z{4NDDld&$z^cVInU6G7RB(?P6YlYHVPFY+5bd${=^fx{R{L1wAx+XK#o*p^LVY}Ig zP*KntqB6;Tkwb>U`^u-QkfVtkm~`Itpn#yv*CF=5;hW|4o&CfW!{C%J8VFr3GRW2}KF;x!IGhw!TRN^Ukpx`*fWhY)b+(!66FX;lhcoG*J2<^B1^^`h&DxF zk@tM^KGqzmn$i^*4>SRqt`gl2au84kqdCsI&gaPvGX}^NXwXFeV3yiO26sf_>w(aG zJp}#xPO_r=ESi{575$EWZ7+cCUwli1K$|7V(;kAOyz&N^y^PS2nrhj`^EvCg0ba_J zcqcsEcxuN5V1$xp73D(S^t$T7Z>CB;r9N{@?+1|Y-3M+Ev z(?=0@0j&SxG9l3EeD!zWQMC&Q5jVYY)92@h6vC{DoG;qjF-bpV-R%C=m+6hP({uQ5 zfcUQ?H=uB^x*P4B-viZlosw9Y*AlIo+Oju{C&~1&3}c;4jV1jsbiOlg{>fo;3?ATh zE4s7fevC3aN)~+ZhnBbPGk884jCae9$RShE3ebH~1Z$>nr%WLALzO4!F;!ZJZuU1*vP2ee zQy;Px5kg5+o&O(6R~Z*Y`?V=WKw3e%S!oHSyIZ9ij|Y~AA?4sMT#^5~%H}rR z8qxmOew6Zi4DCHKkUXxG)wZ>oWzx2V+38(FYo+L zr0y*A;K1TxjRpO`ag^^))|}#(+>cMjqCXR@T?AZEe{jvI2q`FjqfNY>$wgoPeD1Tm zP`dulw*_5u?TIL|8#R@hmRz`@<}t_5gG1=C%4cco&rDd_uF&2Etmn7JScvi{=i4~K zR7v)6P(c&p#Pf#&{QG72&JQ!1?H-#D@!=b#z4CW^QvIhw10cE_L=l3=l3>WH5%ubHH zKg)~NP@uyPHg!*$;&$G%RcZvk-TYTqSbLrCv%V*c`>ALrnQc<R9f8+ZWLc05+P|g1a81x#V9+v**vl_l6;lG6 zLI%!L9;{jI`6B7l3Z?s7K3dQ>QApkT@;?L|Y6L&|8id*%1pVXWX6ZnlUJ;i;8t@gH zlO_&NF0NmdTWfE;iQ$PxGiqL)lcZ-lfA9m|WSp=pK>uX3V@pJzR#um>Q~y>7sKhRL zK>nwV)J^sH`B)cS{CP;Po8T^ftz8h)u43s)%_c3W@hZrWF@FC=UOtTgi7R^>Z$k%i zxxA{&&&$(n)c2RKN%$9@yz_+D>SQ`puX*R#dOe0$S29)&bx7C`#I&(4`dpP%sBARl z1a+o*nr#}zV=59@^uJRBKT*l`%BcxnQLy`+XPiC<$o&wOu^j_$yL>60{@CWBj*B|J z#G&MSY0|az#dbrUuZ2d&b_?;YGlxB~o$iPPa6{*hGd6v?M~GDxz&NJTL{1JA0ca8WCM`QltDX zDHp^}o=;mvFYgwtBiJH@*WwK5fo}o=8F? zR*SWB%u$lN*O|0>=ivPvTwjQ-Gfg{p-oKG26Q|La;-XWhf2_h|bPuQ>dpu4iD{w_$ zz6y`;8~)mOyS8DI@GOSR%oCLz5610Tj_~~$BtIC~K5ceX@MhkJ;}XXox{7cJ`KEAx zx+x;4S5tYsi5}hwD}*haO4x8Ld9Vpzq%dHO{H^z*yU@gN4Vd+NdNu+;Iu;Kn1ZU4U zE;eBNhmAJ|J`x=N0U~wfgOUSWUycx8?-f1aUmqLlF??BxL4bWlwk6*|_%n9pR74_4 zKPJp>&XN{bC%;S!dlhusLRSkTGqFK9k$A7wpDTrmY4VkZUKf{#$F}B9u&L$<`r_p- z1OpTsEn6>$f6wJ;kbMf%jg;Ed_IGC7@w?zzGkT-_y?duy1n~Sa%`RKg;2Z?nLZVYP zw9?z;qK#Bzr&;6MFjqXm&tb?u4Ow~0Bj>^H;E)q)&2@2+@SmWaQTCC!L#0QT5W8RN~R}z*0a;vqE)Ng{aRkez-s)2#&U)N zwnP>3TU?4Y8W_UNo|356`3)m4+Ie@7y9Y(tBRwJEz?&uu7#VsyzQv1YPv1FDa#sh~6tV=4D0h0LeWp}WJ;W>QhiN-17Y@qlP zW}A<-wsI~Gs{#QWk4>PB1<*w*TAN8bcD45aJ6}1CfDgI`)*!EKr;t($Z>D8_&5EQR zdgJvqW(Q*S{^*O{ir-qJ+PEyXeoKprKE;q55?GR4OJuDOwby|)Oeb=8*7v{j&>e`1 zUeE~4*p%k{-n94+yOcXz>*{(e7Ut7Im9zWLXlFjrsc*~KE5));fD|FiDS_*=r9_>H zzVT$`f*9#%;(HM}=HbaO_wHTIv^d!-7Sp;(Ek>lTRV~*WKI@U;$27wIjC>joLZ}(q zNy^bQ{2%dvUQS>ePw1hM|hL!r;TRzN?QjtDQF$&~o)VexLXwoz4ZnbcFa3*A; zj?GFkF1o0PNs{5qoNqqnpilCrr<(9P{m;y2$eU@ozQi2DEfnX(LAdcA(=- zs11qMoEs$TK)sLm=PJuh&)(uPcg?mFTfElMjs1`z6LShb|1bSK|H4%FuPmxd>)Gkl zQD|UgtZR_akjsN`MsCJob(BaL>lYeI*t{2M>+DL0wNFV{tNdqOOx$iZD~eO=a$Q*B?!0QfDM>o9eOo(pMIqbrMxO z=Uq6Qc9^_AXh=q@ITOC{RoKZ~4Lgt?1{9X)ItrHWtmj~~A^431?? z_N<*sCbNf!#X=W4;(Pvj`e9s&0*#=M*}Ry^qQZmN3jFVlmU|ybK6cR4i1!jC<%|nm ziM3@@q}MfBz;@UYSV<(YEqn3tg^?l|mybqLH4 zTPGGA7OX1xhZ&)_jC8O>8+u@i(I0Ul6P-mFC#*{Zp68~InisjyTBjql>@FNh< z*yr6Ja=Sv}2UF~miqV7=AE%hKw=oH=031B0dQFn*Ux^jRtGBO(S4!(wLVu&}8MjE_ zKEyk6;jxGWmsNRD?JfKT*2E_W*?0}Gtcyzs@ss8=aZNW@a2Dp!4z1w0 zf>AMORllGK#rW#XBnA4e4SM2S5M$iMvn`)x;G^1hh8W7hdk?v{=6MY!YI*-z*AZHyU6Q)(-O0QtVLaM;Ma# zJhv5n)>&P@sGIDb8B-Bq>bAZ6y;c080zOETo%f29F2CMVM9M~B5T$1>qmcrB7yf*w zy>w2C$LAX{uAOxAf(%x3G5PxfL?yzIssRFLne8{AMXzF6^`BP>ic?`3(R|_#KZ_hZ zX(FwDN$1*E6e?Pdy)XSd7U!$<%Y!Pik*7krh%^yXT=sd{YcU7r%#EL2?x#^bv|y4Z z@|tu>glsDgv@}xTf0nYc>}3E_|DakZ{>{LF=Qh{~PYZZ7fR_fXRyG90NCq$n1T53T z&(?HzVgpH(2bdIAv zPVO%%A?UiN_a<~3DJOE^EbSgF+NP4OnZHb6uMQl35`zZbRq7e^#uT+_<+<>*zQOvc zKo~F;7_!#6a4ByWhYHXO!{Xi0I0$k9SL2l!KJ6zN2bCvKuBp74a@WX>|#hN@Q2aN?qqtD>e;}+i#Yz3$NDUn-TO*f&T*(X*aKjUaj}}vj;D`s44AY@-Tf0f z>_AjFjl)E-@2`X=jLZcX4n%*#Km0;@r8wKeiAS|v4>9#oL_;Qkp88TJ${vaQ$RQA$ z^JSNcy6e3oDKgPnE%gmLkpj&Y4__ds4{d}tJO}x21_udeXi(r+5 zjwazys{*40=t=3Um)Q{~J#d$G%O4&`tz5X9oM{LIoezHX2)=|)-IISlgv+r;t zC1kd>v!q#4i2a;baafd`3T;yL9+~bqGqXC9xIbGkpm8KCI>A$aE{JDFU)whQC(b3$ z^unk24$M{`(m7!9P}f^-6-&2;>8ViMGPeF!2*4KfR=Ld^u4!=QVD)txA3T=Fi&RWe z4|}UlF);EY4bSXeAxfN7v-S#OD}ke)&p49I!kZyxxWXbChMsT$I=?)$&UTT@;Nnou z4;{Q5s$*@^i8G3SE%HzOB1#_W_mUza_I+CXoag%Qb^^dG6#<{xv)&`Qw= za#bn6?r-Y_SX)0|7VlnTCdf&#&gv(w*73FtkG5WB6p&VMT{o7 zx}2rojLTFFW_|*Pm5tl1ke4Z}bl8);X zz2?Mna`jwj#}O~zM1QslC7w7>i!l9d!Ov7n-8_e$FMr$wDFR;lCCj@o-#3mCH{ zNa>~4JyIBD&brF-**gS_ssElQXEE+vvuJ2Q+evx9n=yFPpkYCelmRvUB>5V4o8&9k zOXY(sol#ydXr#v<)?M|!{E0?kdnC3lTxfeX4;$rou?>9B2NBR(@ zrHc`bi8tl&t9Ip<%8p4ah_tmD641c-?(ePHIdX)s;~#7HV=js*VaO}R^wN?mDeaMr zVu#A5nVo`bkMv#N)`-PM`kM6HZQ8cqN3OS|zKkMRTj>q$QN(<7!M^!1a@iR3P|b1M zy+*ZgjW`YB&p1)dhYG2dXO>UZl&W*)_@%Tu`+9F?uLtqqWqa0a*@-%d=0Lb%iTT-# zklw>$)jPebvd^j{7FnCuL-7fveW^p<#jNaIMQKYq{*8P;W>lfK$#>Q@oS!dt6X(f( zr{y9rP}mpz@4i^Ke4Plic&2w|3JAP*+W%zG{~rqr&5$5&cosca{J!ap(B;h2A$jCj zalmUPr`4e0J!>ng_2xpZYT)yh(&^3GvvB3jC~9C@_A~kC6TIy`*$*ycMK1N5hX=K0 z#ED~YjsKG>W{`%y_L+J9^q{D`)7;jjN%C!6n8sFovIk;Sc0CJlB^0`yF#6LzrXNx&_BxhJ;$WoXd3X?Z|pz8=A2nx1<0(1Cw!E*YOT+g9n zw%z-=0@19F#yR4lW2mjAtnzG5Ba3*tdf*lM&XKw<_Q~#4>~w=`0pNh1H^4MQ!=TbnFKSt>D& zXnV?I>Q+K*C7(&tfSsy^eU{sJUbHy9%5(>5$~abX#-@h>-e(cKeIXd%6zg&y=>38@ zyvs{ih`U|c>XrS(y(VttX-Ju*o7LN)W3HUXNw^3?nrv zZGI=@(>LLOM{TIghvp4z3cN?BuBM$2Rxz&g?eMVAH~nbT3{Y}WYHrG-3>ItnuYX+N zsw^n2X%BC+7Ln3&qiCYwE1R)pFgeO}P35CEv}F;hPE%F&&zNFYJt$@c=QWRY!XFfc zrS!F^ltqu8#LHcY`i~vYDl2DUfJ6XMmQOBckgFl}LS$OC)$D(51jR%&zZui;3`TnA zq4dJ7S^7`Fb)7Q*)zrBcEg4MXp8y3Siveb_6`$F4pt7+1`Wuc%Y=cutH>q8JnItLw zi4WYsY3&GjA!~)}26;0TO#OGerAA5Y&LVE8B0hpVe*LxO^`$Lac|WM>Od|YQ8876& zmcFr`9N*(=a#26Wi9astI<&Rz8zC6K5vNUCJhcKa4_xzW?$gOZu4|Qe4FyDkSX019 zRxrbgBJ6-en+V@R9!jZ&jIC@#Ymv1P3S{H}t}e!;_|ygdk8I<8&tlz|1;xy>4E%{3 z?gm5j=<4k_8hRAltAEc02dDVhCppSg)bcIsJ*Dmac20fIUxUskgT zZW0TMQPuWOukB($5uY3sL*^(rBF~i5o(*sO&0u>IqQ}A zQvur@>-&vge#Qsnann5SBfiiGK5XS5CZEe;8baTNaJ`{NCjn2tkEGB^JQ6=h8p3o! zYAkK|$)QpBb1R|}%ukfks6?Z*xYnIW#=$caL4A=h(`q2lY>^>iw ztT&5iW~nr;J=>5PDc%Vl$-y!sS1um4yiLG4xgM?ii&sk`g+}tcXqU? z@|u5=Y<~sjH$c68aw93bM3u0!_zSb)F<2EMw06~PX}Zl*W{;}U{w8o%MGl~<`f5}0 za$>EHd3@Utp#PFlZ~Kv5lF3(FRHzaudb{yhGRYV|2`|o8yOq=8E_m_7O+-Vna1Y5_ zAVXD6l=Rs>oxjZgUBz7DJhTivKO`ta7TFf|%304pYG{FF3<|G*utf=gvMg=CCxP=j zZ6<{`sMgP^NP(j-gqB&r*FdV`Hi`7t`i86N^Ozb43_v+`lbkx@4RV#|^R8T~I3G!l z-F@D3f*ARno5{B~(lV4!uYikhx+>*?GhQoxLJ_z!~(lVyx;WclNzk%66Tabjg=yV~t0V4Q>dxB~lf@@S$4 zFB{KavNa`f^t7LNO0QP)axfkE+uS?DTg-;^5-*L!78)-rqW@bxH<&s&`#hzWRDRH> zSB}>5OoQKxbU=agRkhno_Qgl>`u32hCkH9M`FMqWz3c{6&}9ZH-nEEg)>P9xxuc|I z#-dA~#|ynqLlOK6KyuJVojC3#9enT&T7-Ss@O&Sa$KB3l@O8Fx2&<>uN2o41P>^u5 zSg!RJ6O4aSK5T&9p(|YLaa2Z;Iv&5}F6L;hZ5*-J_vi{SO;^Ndy+78?5Zc>fQW(i9 zj0cg(hwvGDrS-FL`9__1<@*-f!mg(!tH0jLZ3iQpj2kcj&~MNbOY^;YnhM41;>p_lk+~BCo=Hy z^r1$&Va(MIF>3h&|NmKfDm-|Qmh9$Rj+2mZN-&Ct=*jEm3+Qt&nP7TUDlPwWs>;pU z^B6e**grk>kr-r&D{=D)$&AZb!d-S3KpVCu?HF<7i!}rh7S{jtzTUPQZAJL}6wx1p zMy4@t(i03{4wi+pz0KBi{j&%}mnF0plr}o4hKQB8~d|U|r zypb;&$AbD=CBmOHM&xvZPWy3eT&OTcuBLv_31p~1)CdeL zIIbnIp9!0;1%^egBV@ia(QgGDrPd3Ub$Og7|N8h&8U2hdI9YecpYlX_ZvSl999;@v zp%R(muBX4vN=dHwwMAhDx<7~<#m!3N5MO?-kLz=Rs=o%&F-5w%2Wr{pR`0rf;c?C% zoG*}~jouq?-YZJi*uIOh8@Qv;(U$h0<>1O-UV#2kd1EuLFe}!PMJZGG$t&3uX={Zz zBaF@+xBR#Q`wiTO?VvubGzB)a_RWvU{kZrr_x{J8ddHfOV!Cw=U_3uWp9^BI;81PM z4Pjqs#PEKaXSTx~+d`)oxIVUx7(3$2_-`f0N0TsmnU0)yH_g#g`g9n*ad_Z#zvhR! zdQRvV0PQ(r+0BNBp;Q$PahpOp}qF%CmP(jgZqm%!u)UcVS-p=&V#*b!-KYa ztsg#5*T36%jwu1aLa)Zu>OcCSr`FTOk^8=+Y<}ce-`xlfJ&Zx4M`2vf3Z&0nv_)O_ zjGK~GkC+#He2b=|EGM{@%%onRgA>wg6`fYWgt}Fiv!$M!Oa$YEVfv zL6rk<2N?nkd}8nWrv(}NuZw2oYT!G4uH)NHFnwR#^0re;@%DF>&&jpas7by_-qF6l z;6rz>x>UlTKT~bQAO^#wC#!c43tA^65w;U_f+1SyVVWu?Lx(mCGm3(Pq^wXZAI;%0!!XRq^PZ)utH!ac?}>$n0)t8!@2&HDC0zFqDxVuyo~5B zJWU5Ki?2>HtYvFzx!=9sGH;O|6C_nn-a7W73WRo_Z41`>?&cAG`L7}!pmt3>_^o9a zAm@tNj!htW33_b?wyk$^_9iVW+=~By1engjf#P=sD5;CQl7Mww_}`TM)U_ z)kEJj`|wLHRL;sBfg3Q_mwZ`Zeo5?(eVcgb3;uQ5t{m!F{uQiebdi}0+2Qz*C)CmQ zzECg%$3>#W3tR>|u0E^%Y%&5*;*eK`02C}#bhHpm!h%d%6LIyR)0a5%xXjEo+_Kjz z{8q78YHP=QK$FyPpP5z8a8#Usv%kn%T)_6Ua_qor>4*2{5SH&ojt2s|k#Lt^ZtSWw zoim|r;@9|a5ArRqUHH0vx$JNy2otlfq|{xb4*9~6jF_u){D7WPuvpvZDQn&mVB%$Q zirqz4b1>P_C~{9V;iP8X{N>7QZt@7;Z4qInNCAISZkSl9vyNPIt#W7-AdywAR{Ywg zCqffTZ1#h(M4LF%zjLIN*QmHs&;1S`Tz9~kW8NwW7QV9i_~=`1Vih{-o(i7Lg~F4>Xn?6I?_E`C712S2y9hPo`;p#XGf(h^Xybq0T0sZ!aETG(KUk58(!Xg z`i;oft)6~>9EvD>*Z5|0&A*C4IuC3m`cB|W*1%oMv!6$BzErmL4HSIa0gXi9d_uI)W2nVCNidgnyonBnrh;(58({~i zq_cWKkkuMuE~o0^6h^+YW)e*67j^|uU&KCX9H2R7Lc8N8BlZ|@RF(wZsMOV+& zq(v2TJP$AP{!}(teaW1-e(R{}SVB6M@K@{)S3J!JG zmTeSZ!5qG%La!8R$0<^pY%u>`V(UEY%fu3`S0fjG9=<`&dRAcXocu8G)-7(tpJGk@}5zvGV5uwzG=0IZQe zMH?+49fMob?XS?@QEn+ae7lXEUWhI9WVD`O+mKNlb9_2_E^7#k$T9n-!YeduWWYEV z@iC;-4y#8CncYCtroX+4Y>wy~JqQIdTH|{}=7d1?(Ldh~IL}2Nj(l#rqGixMw+|^w-8uB z6$%7QDpFjJpQ-Lm-F3Gu39F4wkvC{Y$iU^pLk;Z&{@BK|SvP@G7E-XOdVqEoN6YSm zhoedezYSMR@ZR3ul_!5k8daw7lmPkS{S4fmQTfjPUv1D;_<`^L>isM1#8V~7*AH8M z_t%KNDqf)VcFH}ZM>6C%Pl}t*(wC}o<(+BwI69q`=%wXhq}Rb@7lHB4$0#YlXfWx5 zK8H|yYaH!cTK;a|(;qCtzFB~RMBj^|(BAiKWT z-G{$>0y(}+JgI>xZb&082}9@^?A=2n<$O^x_p~_rb=BFHC{nUw?I-jcdnw?ktwLiP zRas(r4u=;C?)Z^2U!n3xOWX%QH#^SUG~Qsj+7QPoZXWsBskeeQVD$9f6)F4mWu1TF z<@+05z*!|T$8&rrVW?(?voD&X_-n@E%ERxm?73<%*-(0(2JitbuQ=()z$9Sh{&OW< zLC>o_=G6JNO8${)*K*RrTbh_*jn9T-akoOY0q_DsCUS-HR|sZB_+%dprE15m~je5a9WYPQ+y)B z9S`GOKNI2>^{I`?FdZTD3E-q&>L%=o{zqIl#QLocVG}vq{FspB zPU1I&(~TYcSbvroko8`PH2R2^lv=B?r%%kzM!tO%#;BW9diWdWOGcF!Vd3WK`Q=B~ z_4jnGr4A-G`kbB2Pl+LOm$&Wnn4aVh&?gms2x<7sc}}IK)p&y8o>6~Vc)CX*twP2fn-}%2n!Tu z(G0o-BFl6aZD0L}qH!AAfzjk0Rh?2fg6Iq%PTVgn2rWne3Q_aX1`1zItd26fwyfM}+dvKY{gpR1w`pAQI=zqA*TV7Zm58>grGUc3< z0{*bGbTfp>myixVV#)@Jk%;o(Clyv7JX5#fs%uL*S`>U+H#47A^>4J9l)g8SyGb~r zi?#kA+4+D2wZxq8aGAO-P!q_dDW{1+(s<=QOSZ$tk$-D@5M}B`=-TDKXO*aB`bSWCSc_T(r;5ETwU)KpKW&LI;(*D{~a#v9@O=z_l6LOeKG5 zX{lPdW?aVhLyr!SgqI!S=zpR!pyZ+-lzfG2A12CA^!`4646Bx>9}&21Xm$f^gAf~Z zf9VP*O++2EGLCto9?j8?)l{a+1$pS?u!l#aZwKQ;C^NcX9MC6CQ@r~ZH_$=&5+a%XZn zeGT&p4q>!vzLDz`@1z>W+%$8R)#x{#VfP68(7wjjk}9#p=iD|MP8a^mU>OBi>tXAq zgSNG7)pmT^IW)jZ-?b^kZM%rm&gO%^n7sBsJ->$Wc*N&KJflm2EB!A(3;4yh3DF8) zuIMR~T!-YCFMnl1-d-t%ZDIUI&cHA_wL3hsBu ze?nUCP@T+s0=Dd#CfH_%mK&5}^Vmr;R}?P!HmZhcnus9U>#rN7^B(ww9JR|oIQW)# z>{t4?pn>3*@~PA6#|VHepuAS8g8^^$FBgd4h#)b7Td`;@8A1vIQ zR9Bx;<4JpB;Q#h(K~;ohF$_t`5h7$^=>wgp;dH~QL$H7U(12Xm$%S$+4?XU{p{=nt zN`)z!gjCQh>YkYY1#4olln4R8e!79Js)MfpjYy$nOK#rYp2AFZf5r>P?#cX)4q;mU z_<^KL$#5C4RE8Hcju z7Y^SofF2ZAbAZ0Qtyef%g&l$sIC#;d>9ApS0=6(q8=O^2Qwbf%D`ag~1r=KqXw_f1 zO)vQ&?05BAh@f%DGw8j%O`(#E;b+2Pdrth>EHk->OMvJP6uYBi856b!P>ZwC(u+ePX>(OeN4&rM^U;)%ntn zq8Ue(z%c+?N@PjYP|GzE){3KwhY6fE*c;~4YPcBreZ<(5YCks5p12ma%r{((;GhnAYi%2FCB;y&2=zw7$5#=(?=!-Pl$&#f zWjFHEjME~rPND`ST90o>$6~bT6RpzL$#+j8fe4mX!phLn#)O9jj^j9$7mil9KHO*^ zNFy3(uTyyu%SDXpQyjCmJT}5qhAonZ) zI#z{i59WChn!~Xs8|u1t{Ld0Eff%~KpuBq>3iXjo&lR%$JPlY>Xu0xYBVWdFmSdZx ze$&-7$%=1%Wt%;^dWYOeY_8uC-E3G0+~a`Y6h;HSdN!{OKE0N*%c}NGB?Q6_K#i!? zlC!tY;sfItfAr3kic_BEW6=- zs2cpiu-)3x%B1_L#>XiXPt05N8hHmN?&b?fr;IKy+;xaqYh0bK$+So%gP4Qp(CDc! zk&!OdLBF(-=kZhtbB7bun-u8!RHouT135(b*Gd|MsPu_2jm zR#uGlQo`gXf90u#BV%^f-NoIRQaL$r^>aI|Y8_UF&JBo$g1@AHpN|}Cc51C6$&V8=Y?K?eErl7mO<$sa0`z zx~LxYa$c>CQ4gxJ3NB_-Q+3> zCGMYmCe!MQA@y}xfjB?*+vlv_w`o1T^Bfo9yo2cUZzBa z-#z7#JOy40i?ahBOHKcH6QLiu?z;+*-&9zwmSy+M2N>!ZhSk)y`3ng%9Hf99zvB*tPA54i^!rYkZ#SBt0wN=hHs%(r&K#_-chIGC+E}WY+TTZb7T=i zJ@{tO<5$OOvYnKShfHWjSK8dS_vtK=RI=h9-*mzLO#2gXEt(%IFx;1g zY&ky*!0QhXSTWBo+(f%6_fX8vnhk#IJjO5@^*tUL0B5S+eJ|rm@8YNh63J}CAsuJ+ zN(BYKLCBs;Wl1wyu{U>IAUVyA>R>}|0CjFE$pn|w3`{kh^GXRqnwCCLqI}R{!=piI zk-x`+tD=CzxtUt)2>4~R#}6{L{1%o*7q0uX-D3?V`{0RJXH&&*<2YuHtmkNa`#YVI z`;WXUAYGwo4SRT)Dq2ow5PHHDMQ24ee8kOb9h$jgyw9ciw6FrpyUFiNFQhN@Z^o9o zWoI%ySw=@NW|6rqV{+^*(eyygxrTL)$%}>i1eYnClRW<5%pZUq}1(U=`WLa?>y&LtK=RiOH z!5~Oy_FlcjKLoCFncv>50zdXttYj%#YU9mIxKtc^rvetV%zK6VxK{HQ#k?;08!i?2 zUDq;#g*<~q0x%H$ec{;W`Z6!JFACZYh%&FWamH`c5lrZlsFT~~4_t4IEZHV+PcyA= zoiXi6Imi=%8&v5;9|mNdT5aN`hx07qDLB72HV)OjaXPoXX~fYO(R1F5d~^Ff_uDOi zFmY0S;p{JX5I&tNa~zZ&UPD<_d`hlq>?W7EVxBzY7PHqP@!mWxFtAnhC0JD*)sA4Oo ziU9bzO3*jDEK*#!WHr;PcbOY;waIV6uqs`X}8 zL#)w1_F)WVyA<-UFqfYZrHoIVFfCVq^a&H>`k`cri$N&`ps(p3tmx@N3O!x(Vd zl)FrlpU}u{SGC%1e#`>~v|^{XT+*}7ripv42UG@i(ce9n4XlJPW3 zNy>9nXLz{p5c`Pv+~n#Nw5?zz<2VVJ4H`j`lIQz!JcT37#Q}pBwzWJ8b&FxQ7z#Yi zZ+Kl56~?R6!wV_ixu&?(1;PFiyG0C}ST7Xvb`+!>#s&fFYF{c|dRS*^W1N=qomD%4$Bj@iD^w_)%7DWMU?9fZq7 zFza?zz}$NW%o+%e2j;w;d3kl25wv+?CQif8)2}d-f#mWqlFy)wR|$5pVjQRgU@PyI zec4(6BGb_aRimUeQ)8SIn6lD=0{o~_K9WJb>}eG^tn zNmJCu?6rYY#64Ed<`E3Z`MAk#b49D&2M74Uz#(KnIN?S6YdydB`Pj2T2bvuW?r%zU zzCh_IUv8(73`?rx5OAI}m?$bSrZr3W$Tfn??LQE_Ii1N^x>Dcs=ITE#7yYVkDz`Er z>*4kE)j9$_vS>2sb)ECDjRke@Y>cjacFv9dP&~D$WQn}M_TKj7Uh_o1=tkIeM4p&WS0f z89$YX)c0KBR>|jo3@ju@6gVd_P5EXf<|EZJF==tcI5u{0S^I_F*i^lPzS-(XXUUSQ zN)l{WATBM*(&MXA%bVR)ZD~(W-mviSLd#7l9+w{PPBHolVYQCZQtPKGJ~GqD7=$E; zVQ=%@KF~hZP%?bfX5m+!eLd65%pLd{pXnz#xZJu}eFH;2OOvzw=TzIKWm+#*$d`H{ zAUDJY%n#<&Z_`g!E&Ehi1Ok~FFoEtTI8e>H2~rlhj16f!o4%q!bBYT6C-EQOB4vn5(~Q+$nNc*)W~Tfa z1=$k+{;3gC;?b#?EBdwleLH}b<0U_>9)!osn$Y;hwJW*2`;Z-?$y!FV`C)GQI0f5$i&vt~vMzrO@8O9o>Y#sQThZzhlCw|q zBht9s3!8kpNM(~fO3a%t+0ozWtPLV>ijlhQ^e-272`pK%*hM&{jL145aKCeRKHhjH z!FcnYtPFoU2vYLFsh^&nx(0d=0W=4%{k2oUEC5~DK00153g_C$iXN00boIu$Gej?F zTp^y2{u$+Qk^lAA4&1`A{QJB~#z!&9lCijDYoKW>DSG^Ede8ZEcjPMy-6AxrUq6Dw zzSgJ*Nx8_(m7OKI*Jlb7p>Wq@8VM(yQ2m`l1+|BV$tIvLrgayz39`!P0jhZUa=n{_ zgK`o)W1vZ!Dme^`KYFZ0oOuypNUkIxj?FWG&+99`?%I@$Iddl`dRcuO7n5VSc9ztr4xiF>ugk#iahRopV?%t5!RWrP-xO>c6pqnF> z&lPygHL+0g`Zm%cPXsV!0^)xS3BjQJU92hZHKH`CM!uZTd4e_$i-s6{-3SRYq-2!d zo#9Huca@T+dQ%?kAtNWYF~)ZkwXxI~WjB%!&f7ivdvja=F#O!|a~&0_WWb7>MG&8( z-NMj^=*F69=4R)HaY?TlSA1tb5Sl3wt&PKhFnd!GxmhXwI~E-(z$^QWX}mYsDk)sy zRcdRhjZu@713~9b!Z+E<2X_KhhCnxgcZ9vh_Nzr#>KxnNBwnP|4CpCaxdgie_z9NK z)JB$Ju+k+o?6XQHX}voOZVehx@++<9*=i)2g`qfs_9#V_YD0Jyk$QfFcL8^o3H9cK z_9|O^(in5H5P+Nmjusk^q8v(;Db!|sL8a1@IeU9=0w-)_T8$NL zp_7hcu=(XjagI}?$NapXw ziAywBT&FH-^Wv4jCA~NHg5K0GM&q|H>g5WtJ`Oj8AjzCdRcpRn9#5BL>U=Z5iYwYd zXdZse0Hss;Qj8IEQ7v@RS-Z$RfA-q#$bwD2KL_xw^U759c+1uGRK#ikXPjp>>{$^A zApy;C5%L`gVL~g4AzwayKVJu5{~0aKvgSpA2@R;V*xBoTknYhayMVpf`8RE3Geg}W z`7sX1KB#XylAWo*bTiSZg?{$YrR6VL7L!Ymu5l}`UJR8lX(DvSQq||qS0x_T7=G_G zA^;f81tRnSQ66y19QG7XxQ0O8dEJR_4e%?gr$%4;tzdrhuW~_&!+w~#@Bw~lJacvR zV~{Aw4HKgrBiZWNw~6w|4L!I)R;~rf5iF6rMSl}A<(GD7#(}!^BJ5zuc_9u2aP+n{L?Jr2G%=z~6j^I~Fv>&VC9>j9Odj;wHzHs%yLF&J}#C z5{jo+Lbs;3ZCDGjxYVT+#Y%iz7RP?x@@FtH_#K(ZE2E6wrw&z8u2ZConRge!1^r8% zYOby?IA1IgNCFBa^vu(`3-b=Sdy*eRCDaDED$a@v{UotaAU5uV@PSe#&fUO%~0G&C8Jci?KD7(t~oE zgvIZ#Ka~}}ffj5)f)*lBW(wtXAxZc5#FCx4Rofq=gqZYAY+C9A4}gHRoVN#Ju@|7 zGA7%$ZEJEBDtXF%qYp9pq5Ric;7!;e_Z zjgs>CSU6orUrRr|H4(mld)R0~i@?tqE_mMAV`W5Y`zu%lmXy2qH-7tv=~ld>qQmnV zN_Z_s+2MpdVv#%|czYQS{P4mt3XzZFli>}^uB$Sy!#b+6GZBJj`0-N6c0(5dVM&x% zS5?KB_MuTWA9|FL$=|t9UH?EiQph{;5~itZ9^ljx`O%k^5rJHYTFG?R3PvO(tkGFw zLT|KzX$yiv=?u)CF3gdtZy z{+zI_OvlhXVK;Hy`2U#&QKE$;)hnhk`SAP9KwB9)&UzP^GI2A9H6s2Ln9dp}V0EHB z6RelwA*1-IP+3=8-S%W%pInR}nv~(}Ql*LJC6omzLx?yc=sW4H5-8o&yqHX;2X}7k z?!I$)JYv#DCKhZr9R)^@8V7`&xX39Mr781{>$r$sIKuM{epog=6xo}^p^=w%jjn<2=S~& z>;OFa6iW`2FRnzBrY30|-0iau)p?$`=?Y`OO!!p?y`#Bw8>(3+c4)%bPPCjKKTF{z zyC!k`%>peApiWkYj*Ce!lVt-1{Y&fdOr0#`%UbE!lw|?&jtob1owd`aisnjn$ubB` zAs4u@TPr3=)CIZ`P)+^4r`i;={)w9C>~%+*731eUot4tj(UFppB2`Wgjzr{Vd&!*1 zQxI2}WW_ii{57(B+S{?Y`~O>2k_0Zy(~@>h&jDAC72nj(l;T^ppF0)?6R#FR8BSk}_7kF9-@L{AP6s!1zX*8^$EtejWC?Ha4@0$Ytz;OLS zzBl!qArvKdSaTuE_P)%14M}B0K0Ol6>Za$2ll^~dNMj{0u9trk8y#vEPt7)p^%|vZ zbe%t5TLP{XS{);Hhdc17vP^~hNl{{*KcU2Bipl+~jnDoLl2n@Y&e}m~k#-YUq#T>L zzjv+wqI!*#^!f-e^p*KxbkBbPkEyf~-xkHdmJac zBN#~grZ9IkVlvsJC_ER$C@2_iZWH4Xr1u(YQ}VR7l8D?NuX|0eug1IsiB?hH$SJkf z|JLm-%DInZ#%H{~YcqOLFI4LO_Ve@m6cPSJY}Wd-O)|wp|xIIwqo`_K0s*Ptw@R; z)oK8p_@IsVmmkkR5F92hZSg7@U-rnC3oK_q%R0uu_nX%F}t4gj}-dXbt=>p z$=r3>Xpq_xKl@)-2je>$o8ZZNRi9Z1ob;V{@MODmp$l))TO7Ccdr3L@e$nzrt&!gB z$Zvq+M_DpTyFOPnp1}Gf)u?q0};Yx2s2yx?we6-fbV(%tjGMgIhEZEcgZ0=h7ER% zbg77s>3=t+<5F9%oHuJYt~*MgQ}@{>1a`uN9HAf~3zXQh%O)Q~b_rMo@&1+aqm6hN zf8%2NLCR0s3>*~-`(L-0QS9tR&7@?L-}Eyrh~i{CN^vhvVHRO`Q4Ht6f8NLS+i$0Y z#;M`^S<7ky_z%A(qGgTE>j>N|B3y%J6iL1oS~ugEVmv0ri$4JJTrU!w7O^~**)7IZp3#6q=kY7Hw)d^EULJoi(MF9@nTxJ z)Uj{02yf&|8P$-PrIQHl^zy}J-{Z_X;s3Y97km6$T)ABN zW1S2oEpOiRl_99czCw82z0-`mfIs;Wuk|N07OZBA7_o)6i| z1T>JZSpX3bnpU9l*Q&pua^ZfCuGCU23nM};qrMg{GZ^0eGOW1zMZ3AFEsV_ekRhRNOS06gH!OUfo6O zNRQINI_H+ZBq6m9!OTI#DahEvIF2aa0GnepBBuH_H_TK1NqQTrCv_WMEi*P#rS$}> zPxkAyxjx;n!my!x@8hVf`PeViAC5O84t)+E?X7)3z|*6P6J+Gv+kM624Kuy_RUoBh zC&nVvY{zs;^l?M$K3#se-JQ__U-e_UO0U{7UXcmN?g{8B;X5;P~?TxR(H!U z%k+h1#>AHqTS%S(x!NEw=et}1qo}coG+NDhG7G5(o8R%pGk_Cm@OMd{`FtNgO>g)& z(5f3+TSC>T7*XBbrZkT-$CL=Zz>G`8-rqQ{>v+(ubq_D~Ck`Ix!+?*_txpai|9PaI zo2J{%#FDM8M%wA@Bq~Sd3R3ySXV;j8a$XayVPtn|mNCgA^N>dn6fXeMqe0QKl|XE= zbl%l|(-DEALyVsj)Ko|+E1tE_*6k?pPkNAKx;GQU((jR0=FAr*;4ZrEGdl@8Eu8Z- z*8nKgg{zCWCrjz3y9kPOc?S_0)thew=ceeSpTzns{g^i3d`JOI%UyIa-R1l z7_vi>p7}+cI%$pD#I=g)z=0y;j**9R>)>%d9MD`c19Y61v-0!O5=;>VrTw73pu+hq zRSs&ZSMrz*MT|I)`3Rf-%4HLzE*sBW6**a1Y3?y*;t8EI;Owb2ADf56O2LOOR$tk* zT7Stg?waORgTL<@6(=p~=<0^;AzmC);;A=EOhJAG3;Q#RT zV-Oa!$abs(ZKqwOlE%daNPO2m@3U=+m7YdCD!D0Ghp;(y(y8P*P@#~kK)LT{rcpG1Nj+3buJEWbPhJX+ zJX|}964z$10zoVY2g#{H{I}wfh?vUcxLhs|zm5A8bv^DO%h@(JZ`9S5Lu7QM{z7a? zB2ZEy^^4VG$2^$n{!p#4)MeD@MeuFTWfcV(8F`v)ylJ=YfMAv3SwQDQJdG6_z9CwjC6F6 zmp?z}GBpBs4a1QPCRKgtGM)P!UkO&D1ZF37VXyf1i^)7j;%8}ap_vZF`5qFodkmO{*#a75Lj!RE|C zBadC^!g16%P z>{`{&MTlFsPrM

X{7}X7I`AKcWITQ4~my>*E=W^C-|1WwZ~E@@s3MI8*K3B#V9TG^%c8m$5WIMXc&HZFS6u`g%$QBMzR+u9tSWi6~jYgAJDqiV{`%oFLVCS3AI ziOsfcL`^?9g6qrIbAi6F-PnMi-xv!^mdhkNuaSdGoQ>eKehM1g4!>K-MX7Dg zV_zPs(4Y}ja7L7+;f**1sO+O;EC_>4=wIEJVc!v!=`H$CqOm;MP)3Diubo{#WzNWl zQ|1a2)W_ZfIy+`7dZYoVf}GU6oWFD$se2a_x8+3IuY;Ofmm8~flq^MEPCZ7fwzIT< zG(TW4n{S>!6mAqh`@((x{8<*xIlPrWvmLBx{aN<=H+l#{t(9@6R%}S{h$=^C0yP6R zms`>?I?ke`c_KD3sAbrWL_mv4;O%yf%Uz#v^x#4oFlod&{y{TSON4VaCy>tGaYW{# z%2vU`+4TpPQ#TR`sWdZ^Ak$S{Y34ms%}EX1cNChTxfxo1V?7|@Ml;G!Nlg)IkSVTT zd@q~Gij&Jz>j9PBMVLa}k!X}Kef|1)G9)R`<}y%yoOW8d8VGhuzx=?bqG<#1HgNfqQhPUN1@5o9+7&q5Gqnu@oBp6qYicguaC103M;#Zv}^;jw$p>jXh&==(f3H5 zxP^9aaNpVp71`Gs!`e<9MvDzwAISg9@-Q%()}g^<8M{JBH^}SJ58r9ycYbEHz0jR7 z99e>MlK3alsu_Q_7RWT&q~*ft4JP?mQ0mxnSsk_^TVf@euOpZ$>i&$iU>B>XxEQcB zl0hpngqbMypiUg4O89ogwUI{B|6plD?S4xbmpU&q5k422{9Tn4yY9Pa8pfD8ZA1EP zcuHE@;JaWGryBI=CCpx;wZB;YGJT7wLcw$<%TrY!MU@m1mqGShLJ_<2-U+?ubA z7xsRbzOVK!qhs-d&Ge1EjhaaGxn?VGAS2)CfE)2*!ZrUo7DoCnbR4S3LbZF#q;e*! z-F}%$qDy@9O6ZZx?ajFZtTF5$)P5SV7kACb3G*Bt`D|P<>32hg&1r$_Wxyr`)#J2i zy*i&{o}vB}!*7(lE3x*V;G5-3aZK)8hn?6l+(#@|Oogw;HDBxf)DL>+|DFV#HJJmD zGL?-DvR1D;|2l-`8*^iT0k!DUtK`b#57x<&ZMF*mDgzb0iPXUwT2`XTliuW{K^Auz5rI9TA+X?Id zXTj;|e>v11Prs8|BW<-|K&0KdW0=n;5S~)o@F5V_K@vqM$r%WPO;fFg+OwqaA@ug; zIdvJVdx<~vvH%n`-2A0v@b_3GMW~2{<0z*3{YX|1iC6HnJO*|pwOFNrxAI&}>|&RG8Gh=UxZg@rqeZXJTy9 zszk!pqV=v8BEV!cbo_BEeAI)0T?Nj|@a)_K{4o`tl=Uaw!>wK2kENTU|K%g0ZbLCv zG6NOJ-7A=?w97-D=kv)raUyPQJg^%5ge$9bl&kY(Y-nVC!YfytmVE`a!SBM6)_~Eb zJ-Pdf+rS!(tW;T;)#aJ6tc_ohPMF>f(5J9pUf z@^a`a9xnbs=Wpoo20~HNzLbotV2VtcLY!qS+YpwA<#1TLQ2E*ey2kI!MmtmE3hB%? z#1!&Yx;>Jrt@|KJ`*2A6S6d`P5K-JX`>Cq+e^1cuAR^~{P88sD6Aoq>8q^Prl3IEy zCjrjtu901p-3hUe9w~v10J)>pzDKTj^i)mzEI2y4hu!zD#GQ=ZGzgSuwijeMKeRZ6o+Dl*3(-2exJoP}0+gBU zDEYy$cmiyJ9bT^a>;2p|XE+%GUZ|eWFS!WJ+}_5J(1`eh>oI%*+auJsh_?p2MRUwd z({?!SpU-T_(Otf_mMSrqs70=gq*6!5#N=DPhLPdp<4Trv;I>xal@#WJY6OofgCN4V zq_GD^G~WvprQNb^u$nT+nz;UT1DIWp12%S^bLr<||GlNF9^7#kNi*2=g@;dy(L{GY z6u6KTYzM1;66srRDjHWT76^V06?nK~@{{{X9m5y)?+QgiPQuI0X5<;|AxiugCt$(2 z;j9+py#zuQBu(!qzP=DK>7x+V$^sP>3Kq-%+}g)xEW+FAUO^z+Uz}(IkSRt4)0Bj~ zW}QwJ7k%5$`S{sjc0sKQuc|GNvx@dC2nc^PbC+~zrTmSBR#hdatdJ+ZOxt;I;J zz@zW@`~5|}{e=w`pLfiYn(?>RvQ9dm(o>SP%TsK=+NSWgKGSlZ+=<6pjuxCF^`lc& zO~IVY@;MnUBl;*wQE6xZ5`5}0=%`cLSE0@RWry#2*iy*R@Zlm6j_C~t^YkP6?^(N` z|1E5IBQXK7I!08`wshexbZR@!olc$SrK4>I#k?j635RXbshVA#h7hnq?%9heMI#Xk zyIA7!YMg^Pv<02?KPlp24Kmtxpm{wIc26ff1+CjR($dyxb^zzbP-8v)UdxJ7b2g&<;K>VHcpw=T}V?~mo24L%(0XY1}2JQvMO z>j}-pG)d&mTlb1iDN*v;^^45PRwq=5xFNoLiG~|*G9C7|3O#CfsD^_ORp~xLpM}i3 zf&I$>JMabqumC&KSR-l$%9#4ASVdIlUz&$b&+VL*186`4t0zV6&DD!U%~d(UkHttj z4FXyuy=Af|6R|(T78b?hWIK!@LecGs@f1oQ#0oULVdhpsL^6W^#AkGrv0|l_==YG8 zFG*_31Gz4TZ$>bj=O%{jS0TnE6F4dP&tS7=789fDwSi!|yOC+%H*cSwU36s8s%5`# zy29nv*lCp5GwN}uo9Z-~uOvUzky23e8VR&wU~Fh+Wo2!? ziRQJx06HG>%F6KH-e{GS(YV~kEZqNHb)>M69oAb8-3hkgHt|2QDe&(j^7(8r{qmSu z=GrZoU+PfY-7dc0S%5z8#^=o*{92qHV3t|;)vR3Wv)t5HblB%4JZ7mOjZg3qVp*QduP{2OV`NNyR6=Zc!%pkCO@; zN#ZDF$NX2W?ZVt-w#<1u3Fs3DI$CC@CJ;i>Wc(Q?eStwmfezuSxh4ykk~IAM1Q}b9 zJjUL9WyE5+%gs-1HHj`}^H!Cw zY1})oB7rbbZK5n>?g1n)X2N68&p|MajP$Q^t2JBE=(LsO{f&Ho`0VSHd7p+a_d3&g zGqD8Vd_m{>YKl?CRfW*?mf<++Nb$e^n@FEH7Du3E7yXnXDrnuIlrifRDF$zIv%lSe z5D1YZ48BA&g4<2As>EiBpOyD8HWAS*ea=dWf|+dRXHO)ebupWIRlZUiZn0i_dwJNs z5O{Zhuf*=(Pwwi8je%I|GUF6@C_KFi!u1V|Z{ml;)O-G7&F2Ae9~GUiN(UHTbc$+r z*?yfAIEB}#Hlh7>`_F85%_+=Eq?6`#J5^BJfIh*=wVH zwRi6G_`28?G3E1)yY%*#;7Ep@=kiZ}9ezXJ&EaN{7zrnh3iU7I5Y@(MnIND4c_Z)m z!$E%N!y(>35f=SnQWwW<0M+jbMrIGP!OWg~WY0}4=Ax*NeoOh837^4tcZF;PJjgd+ z_LPAlGYP6E!+$EXyEGZ=CvI@w(4WE=lQB+0SKvNgIf@)lx|MVAW#9%Ym0d$sfP9f} z(Qd&?WOwOk5}yt6srB&Qj}{`{B#B@WZ?aJPccst*+J$-C%6rQ7Hi{~{iRM#U z%*u6dTtvOr-yav#i?0?J6?bYN)YjZL<%~_VdCS9^a+X9?@OCsx*w<4TvzK}HnSe|3EuObAHdwQ zscL}-yv`Px%T}um_hr!QMTRc1Cb{m=;j`*d2J(9Ik?aPl&RZesSmUvH9kE`r35H6n zo*foSPMM6Pre|`Ay&qOL`!3qg6E!)jzu4esD%HFdO@she2FIWn5H4-#_*#IrZxNly zuKjZ1<(1djWv={xy#^QaqhCv76*Jl4yF-r1jUBJ%<=YMoGS5iuI)y&{OZ_ceO?ss4 z8nMDqa*|0Xcy;tWo`xGomcurJ6DuD^Z`Dol? zu=Ywj1=J~SXVf<&G|IGj-Q)$)TasO(ehCmyGU zUkoPhNEhVa2kvh-#Ad|~_BFxpK6fpD*P^idSij>soJ~ZIOEwjPthM}jA(Y#0lr#gY zHSxP)<=v>Qjvm=+xc8)zziwq=kAH=hU=z4Z1f<(fn^vwO5ybyXgy2*NS-`wJ6KEj} z392j1ZJKd3CmcB@B_e+i@xD|d1*wEz#9us%<9H#?Z6BSU4V>zIc&>RI+B}Y%2?X6J z3Vvne+C|rKUpUsB>H0EoPk^`9u^O95>V6-Q9pkD3W#_f;x@Ld)M)iQ8?=$s@VrUS^ zdt-|59KCHrZM5cxXwCO44)zU}KV1+Dfls7SG<1HmOnBDFZ>vMY6f~k8%w7sACiKF? zZRCTVBIVH)Vb?X^DM4fsSNxUY7pY(VRF2u zfXIU6?8H}(0?S{S%?3W(I)Y8*iO33O^Rg#lA-j9#q$J$Y*))nl2ct|=@+5!|`2!wz z%$g&aCz{i$W1Q zv(I(G*y}!;Mi=(q74dGht)dkybZquMij&>8ZW|0xbpPj>y+n0Wt!%adm-)4yHr@4b zFg$`S5llGHBt^iz1NK*TK%dY@HvOiYom^1C^&rU3xaC-_g$QY5%^mZXJMjwdnEQDh zqu9d|@#}(?)el=MRxO5HB^rZ|+}|k~8B7IcnBj$A6n-^*OV>c!%I zdyFwMHiqw0iBHK$>3#Qswg+Do|DHs!H)jkyvs*blV@opqJQDK)Y9QI2k@xckSsA@4 zZvWDmQo#TCc`o+XCGP`nQu?GfR|x*N@3*Cg9Ys5>Hi@9si#LY3X2<`%OhUp>T28JI z(1ZS39M8yMOx;$n$=F+5ff=-8yqZ^0;at)~E=mYc0(A1V&R**P_xF$6&JYqxlAz98 z4c@DwuBAu;S-|<*vB@nMCpbHTE8bP>8g6B!1yb`Y@^Km*y z4i(fibF?gp-YW{@1@+Ll?s>Yjn;pLBcX@Y5i%U^O|MEI4@)V~XGJ(|9uz#}2Dn=Q^ z8-kYUVM9UGd)Fi%0ZF+%^EPjO{9IB7$K@o70-V$g0&9YKS7*FMS7RZxDH$UR7@5QG zfNe^@-fJ6T`3bC;+5g_+Ywrrp-jnRqMBw4Y%I<}e)t;b6Ks>V4B!kx?g4!d-mH5*39(WF$F%p)2i!Rdc!9gi1JO!ZH@4s&HPGz38AdE+x)fWaq+u( z@3jKZfmTrW(E9zwb~XWQO$wsQYSF`x==TToaqtx!x(mGo%^&ml--KEnEaG$ zqW5vQ6fc0G@V5&nlu7ZmM?SOpU-(@!n8t60_iXA(T-5nJnwUogBNKFfUPmOjPk{mw zAQ^{cM8xp{EDN2Fu)5P#eNucxkefif}wc@#Hp+=;BgL+EfZ&Aq`s)1eDOj+ZY;ulU;&=p+c;CTh{ z{{rkdrFnV0tb^2Uhj{pMY_g{75%g+uQyFPkgQaWH zbnCLQe5gOwhh(@jEX?;loWJzYACHxi*}HPj^2>Fmg==^3Ze}Aj$Prp*fQ4uL4P+(= zSJn3K>r%brS18`rX#5k z;21Biyq0-fb-g1U)^?T@H;`%&5TkkEFv0F_8FlpUs8Sot_aa_#r!yVVWDZHnU?CEv z>xi4#r-7JW5X@7iQ}1DWPlSG<_-ox?BZG11Wn%98>&~_o~C zQ?JZLt1zGY&f{#7^VNWv(S(p=BMUl*G#NQ17u=VY<Cx_Soz}u zmleHwCDjr3X4mhdM!N93wSv?HIJIpGSgjAnx=f_mkzpvg%EIe9rlLuWjre4~__k-*%Z{n^%5L#mRJe49Do3OJd_*86+A3sI&kp&C6BG-Hn^%@^=dz!R{l%*|ra z_jN0EBC?J}?yw{-LLf!qjl3Npm(t?m>@;*s{tNs7F^o!6hS=x5ac3W9G`~*)&&am# z*Bf+ChX-m?Ri>_F`*GI+DcAd@mjC?8-JYB}2Y8KL7|3yLYz5DVupSzx4 z#?#q$vEn3c;B#S)tmw6~2i|G#M8rH}QPXMInV9nvX(?Tsg{eBd`CKrt7+6LduFS4e zHl6<>MWg3|r{?BrUO`SXNoeEEjoR!4enZ76-b}LW?LpNeA?@ad5Ohc5 z0>L#k7CO$8sqWiwSs}kvFT2;93~o{nb2^H7Yj-lT(z?h0(NQ2Qb93`YEn5cNbBMdy z5iVr<@=zcl;ZD{C=8Eu|!Y^yFcpi%|kD7_O(zvE5WhCD^-rSBC&L}&NWM>@%v3X*? z^!lUOJJ>tT6Kfja;cAW=v+eUK7Y23Yx#$6|Q?bVyxKs(D*k#O!$=Q~Rxg7yhb!2*c z5<3+UPQaZAjvvmEN+6RRI~F4=_UL+&^#T`s+!r0kOdHPgrnd-5Dy_5w!$OHkXN5F; zWIANBa2`9Yt-cCaVH#+=hjD;$R_(U2c|RJ*XdSBaWe2O-205~ z9{;S_3le;qZ;ivlnRmB$`+k^-s-TVZUqPLs*W4#AMBw-o946r51YAwY4$YTo@pFND z_Fg8m>G2-X`(?KlgTl)=?TLJ9?uj*eYAR5%!_V6Sbjq6*CZ_5ytSTYQJlqB_BQ!Q* z;oBqFe7Cm(Yi~;geAoR1);e>T^vqp*1B`>u->s%MmxC)eZ0iva^OWhfMurFmsMDvI zj0>Yf6;`sHJS}NR093f(t@1&2+)^bGGdn>`liki5PnesI1y7A6*6lY72 zQJ?gd18Z@K)04HL0zp$n#hLfbBj0}oGu_U+q9h(tx>ZaIV%j_J?*WLPwVmtU>i*Ia z1ugbrI2QfHk#eZTc)irS1(21LF?@5(xdp~gBn}ZcGc8v@`MEigsMiUPmW%K6`onI9 ztcKXw%8PokRY4Zxhk&_OawOflkexIX5nA=-(NgHRDvLoWzbF12FA=C_g&gFu#)n;* zo=6$EEo~{RURpt1rg*zCPKB@V;^Hjy597%~vQmX1)!FbvHQR8TEH9pphdR@#5jrn^ z_kI2QO!y4|svyq*Mz2x{X0o#EItuVVPPOB)yDr{6DZo3e|IQ5*4jeM0NFUUg_mV-# z%i=VC>ApNd!R2{%UAVVu=A(Ced1|>FS3!sYhCz!boG1zHfPDZ!fP$mj>v+Aw;I@cC{@m2RG=DzyxRh#SUF4L8oRF=&WP><-GcX2Kn!X&`#Z?Pg&S79DHY@6YB zuU@WOhtu^uVdU;Sg`DNE!0K?oIw|&%_MPhXK|im6$z)cyN>&~uQz0kZnifs%df!2HI+XIZhOkno1lwYm*$9tr~ z#WbTb#Q56Zpubq?aZyH#9cf*&l55cD0GSlm%{o_FeJaAW|KN3c6OaF_KZ`|M@6W_9 zM&vi$9~ad^oXWL)6EnFdFRRlINj1$2^i;2nE-^dnHxMo;JQds9^it7mopczR3_p6; zK5W=_-}x6GzSK^^yYBhw_ayAA{{I&?0^7K)Ew-&a^N~7wnlQD>*DjrM(g31l^`7+) z@D72!h0>~cm@WHjp;$Z0i299OsKob>sEl>3*e|t7={1rdiD&)_(eQEf@lH0vZu92&HVs7z1sH7a!%8w{x&02$xs0y3Of_jxgA-t z)N~VP-r{Ala6aFCEfh2802n&MhYV6MF*n236{5~|Wgkwc&c@R7rH9(N56DBLpQR7J1$Tsfg;#Mj{IqwF}1^7H00&49F2BZBAJhi$#^$d=$l zcFKf%*3tRwyi3c;SxvZs2e*ji^XCZMvhh2RV zZ}Oc_(G9pg4bF4N_SgZc^Z90-o%&g1b^&vv87@M8g!Rt&Kr6=QZk3R_h(iwejFhjos|xhndO+6t$IaDm|2_Esgo60q3Jg{+t;$*>)vOzZNWxp-D zell}(3=5Jv{rv;fOkWV|n2o7f@>c<0whq90y%hlq3okNsl!H{?(D576nKvG;dS$QH zVMb8Ysba6?jgBp?k*6ut?ruI74@;m=+e6BNcJHW5nZqnK?##wav`C3-0B@nRfkn)e z1L=i@sN?&QSyQgf0MW1OHjNx5y7{CUUVb?ePM^Sv5BbNeJA zMtP?9SU}8XQSwaMgh;ty5B|3ZLY1ue2}NxuLztlr#Bu5WO^?CzV}!&*d-UB8)VFt zZI4G zSP87D-1K+fLEn}cw^169kpi|`EiccV#-6@%?q0wzDcfeNwPQ zuFz}x#@K3%%iz<~80;W;9mZ(rT;I5L)N$d7=IPa2X(5a9+T?3N*F`q?0Yhdswo_r} zb6PnCY|Bzx$!3e24I)^u%*eWv*gR=@#k`AWBB>EL)}0>~QFZ_?Yw8v2pLD5qz&Ovo zWo-q?i*fiB8S#JIY{50fZoBo-EKroPRPgv>CeAQ#{QO)#Hzicbt4d&eO-r4h^qdhG z!@vxloNmV%;PG$;7T=!_Mb0h(?vPgM6}=Ye3WMXL2<8_j2CYIyp-su4XI}WqFGoTOg$_W;;v8(53%B)W52&9_F_Z zE_Gx!br$YPukL+^ExE!eXedL;m{U0|_q!yoEa~!HTEIg_JI4j-Pl@d%w1}nPu7f2wPH5hBf8B0mztlkAf25K^Z=xR;sLfEmP`c zZ(GBbTznCaG$=lO7UYupC|CbI8!R<>B1Ep%TVkf`m#z0vgr&7XNjg@InWC#VvJNHRMQXu(Gz?soh41s~xJWW9ytLj(s84gFxV zs8?g>;o+@*YQOnGhmoqVOt8ZsdT3l6NY*}jzAs%ouMyU+O4FqXM`jtt1)jo#;nahV zt1~iUW(Xb-*-*c;;13fdQ?7Vp@rQFp%rGd$5gls(-1DlY!5QtDi7HD=&5g?93nYM7 zr~wI$1<9n8#9e;gpt;f6*fCTQJmL;MT@?c|LuSb)RW9PRRR;9HXOU=cJ^s?y+ihCL z65aiVLy6c?TE<8bU)?LFfVH>atpc=p?$9m1!`biMHeNMrGwZ|}D{&4{X#Q8!^cQY; z_G?!`Rj*7Wo)Qu!yq`(DhgZ(v^xl5}Vve03J{pZ=1}4JKsM50i*4<$}OXejaHt{xkTCE4F8r^=8}cKPMIDfsa?r4~)*c{nN|0bUW}g(w=#e=ZOr6jF!tO zRvjEX=CBr`l%eH`+E6(@f29^dV0?_SH5Kvl}~9OrZv7yGM~Z_k)UDbJ~3jt>w$ysaDVWejGmG_t9Hkd%b4N z=A<|v%u~s>bS+Hs*z6|<*7AlTCgl6P`H6X|;s;goJ!80+fL2a=0*Swom&R0H64Yn1oTV@TeA z%6zgqLnDk|?Z8MajNlTWnwa%7LCzsx*+h#jdQFHTZ{6>V-VB`rg^MYW%rc5!=8jrIps@=P1xfF`r=+Rv+ha6T|H zGY)bIApb>fP75KW>&FL8db&~yt4D{?r&s9bR~R*Mu*zi6NzYqT9g0Xm^LVhz-LDY* zI6}ItO5y1fyEi!TBE>yOFS2sZ^`-@hZw8$t@EU_M|CoLtmLZB!WQV9aLMX1_& zqcE4&oC2z{_Kty3mrwB4D@fLU5F^9G#+7^L@BCN3c20Rqf$EojJf{0HNn_SYd2r3d z_bcZOlDkJ*Y)aerrO&_Y=x_zT&umqbtfu8*VWNMT22iIz-T__@bf&R2z12?T8fdGwb_kv5uzMC za?0mb`^$#^{b7#i0YPYd2g+y=bCz*nCv7C_z-Q*O9j!%?iZ_r7kw&pWl^!)AI<0I# zRv=nKWh?{^vp=N7uyf zlbX0vle?cuvO=wE-S5V-V;(*hY5S|i&Zm`)TFpHe@n>g8$L1k^LjP6RaM-sJBK)hU zr>%|i4i3P7$fXo)D_Z7_?pDK%eY;-)Qg)8S!SIsqE1#OE53o-r1xsw#1We^Avu|Xp zkOK>i?d@GwEGWIMAsL7&nZkee6 z`-LKeMsxL7a3wmE082OukMYs40Uj7kwLQZOAETg@n%h(c_qL9&X#g|nsEq=QMn0^1 zJ)@B*lhAONP%i{!9(lsdw(f_AuuTlh4mIu3CWE`A8l?ZqW&8sO=%17iPIP##GlJrT z%VZs-rNY}5OZ}*8AH6WS=qou(QOd<+~h@BKN*aN{xJJvd!*kRFR$embvSX|1hzYQ?2vX z9<@!BxBJyfOOgmqfw1Q|PeQW;>hou(9_@`sP~cwqnUhC1a!wfvay5XJ6T}=lN{WxU z{J2T-UscY!jd!hOMesJCa^x(nC^DMaVfLybD6{yJ>+p-N;WTQdgQ#39J5^xJAzfF#`sY(4xf6#gebCUEgNJJI}%Be8tok9Av?aO!P(+>`Zo(y z{J%KdQrr^+Wqv0k*syO!C~Bic4kkr3u2K7p@~%^F0N}_>?mh#%V%9*(^ViJ95!Iuv zb(s%j>$==5{)_i2G3Y||(NrO#>CT(&^4Rm3d^L{+DQPAG!n=JpTD$J^vQtFN2mSwM zr~T`hx4cy`-u1?$3GI=Y`kOs_=-(O^@&nzI666Ze+AzP(h}^-Cr2gEo!R-|F3!lEb z*JcJj@NonJYD%c(@KSoFmmr@#d8U8a_PxKH_r*gm>UVn!ts?kqvBXgf1?SS%Q8hIf z=;t7HWa`eKy7mUf2^+{B_&65@C~F|C@U%wS2DvNe?;7>d$9Rr_A>LWOrK&Wu~#jI z$70s`+FXuFkqdbyXmN+=#b;X}G^lNa$QTEpe*fEQ*-p_oZ02pfCSxCqaJ&h?>+lA$ zX4|H1>#Np$e8{6Y+W{V{9%;zK2z9)5F@w}?^1}ocGRkf3CPkxN8Zf?r``KdlZ{(n4 z7iU;sZ`c`S71h>lwdz~5U#KwL&*-*0ETkjiFGJ^N(#G-xBO?!=3j6$Zz@)PkF}|;| zJ3Wl|fo?Lt5yNs{M1vvY5fw;C;x2#|_y5PzRRBf#eQi-BL|W-iX#}K8SbA9yq#NlL zmX4()q`Ma+rMpYIyOHijy5W2I{l7cI3^UAL_TKlr_ndpqbDn3l#*Yw4Bz%XNTd$vyx9W!o@4^4e&7fGrDy-XQMarZH#4s`2DIqZ*8z%7W# z`t?HoYVB|T>H?!98QzAb>2!X1ZCON%Zuu#U9QNWSipUh1d5pe%7hC(!8l%-^F}R$G zMC4NLT7=)eeIqFOI`rauKe*1Z%E+u2E5kZql$j_KR$*kax|n9IzBu7G_0UY0E-|Re zNO4qSxE8hG({l7-s&AL@JhcL^K;3eW@u>L{>U5a8l;P+W++xe;en|L5L-Kb)>?Yl^ z!$iC{6O#m#A1`Oa`F1yj?D#NM{~DCShU+RaibX!I5R?7HBboS6>fSFN6ET_Ph6^ zYcyAAK1{tPjh9&2l)0(OtJnJX3Kng}JCo)&?iCre>F_%0vPr)6rdH2tzL(+qEhfNT zntgV+1ar*JQ;6{X;U}=PdNr8X)2(5({zL%aa;*<=fwk`VMn9{@>ZC>e*m`b2Ks6nOY1oLn*Lxd6 zJ?aU23*YqTIGstA64S2p@bd*<{-TUkD*Feh&$TvRNjak9g^0JSP>BA{fxiJ9MFay|_jhQ9g7GxlF89=XMx(7^g$*AP; z;qYT0L!{mjg?J;PJRR&sg&!^52pYu2{F;R-ifqLQN$|wMgdNa_+1kLEK6oJq!bqaW zxP5nzjE(wAIL98zPSeSuuW11xHzLTvafI6L8{wKB=adnz%jrtY=GppTSD#)1iIAHM z@*sbT#h+n#PD0@dEHD=_fyP1bH9Iki7{AEU%^c76$`e9)H`&0rw`#J%1 z7{G}s^FSm9X7s*$p%%I&S2i`BmA@%@IQa?SNl46Rd3$k}qUK_Z2 z((t~DA=zRPM1!d}qUdA!!I&^HCcqp~+K?nJL$J=@kP4Z%G zEZjWFV+nN)5yo%4uxGdkyTW{QZ$jQ|GgFZ5(~N9Wc@4o!L&JtlWN0XZSUeG zR^`>5E&ix2iRn(~8#6v4@czNY_w;;BVX{~)xNd9buw-8n(G+eI-&;*_T3@4J#V(qLZ&E^`)5n-3>iF3lW@Vr{@l~oROp(y@NcjmJfhE)g zmaX&u24(>CZ`%^w&d-$6XF9|<4pgo|S%eXic8b#IJC`f{X>ah?pcW%Ry^3&nETs9Q zYvaS8r~Edq_P%@>k3&nnF3+n)KhL|%U#09JK1UdDhlVp|u+kWn;ApnR5Qeo zs-iQth;4!%=xE~D_h6*trEbGuNCs}qX$n#|(q1#A=_X&(6}mSySQ9$>_5ka{tl}|E z&`gY(c23+cP$B)JOkEx#4&6lpuCK7DC=?E_z?GTaMfsQ?-%%-Y#`nzPsApnqGFygm z)EGEQuzhH;!8WdSuXv@9@S`gJt!ID09H7dE4lzARcBX0_myi>6Ml33Ia*kJcOh+kU z|MXedrn?w#VYf+fK)w)byo_#9YW@BYh1-qoHGCO2>jJ@?Z~QqH2YL^E6Il-P%JAk9 zt_|Jy5@xx50)UAN<(Az1VGk9Rf6KnB#2=8Pk6-Wly?g?Mh35PWmDL&92~8*WRHRS1|KZaY7UZ{TV8QU4@$Jr^m5Pxp zynQ+{1EZEWb+1k5WhbKZKvsC5ir7|Dc+!zmx-2mrB?5Z+br$)vb>Tbsb95d;<@?5$q`rBxLy`+MAUJNbabX~zvqvRnIN5R0{sJdWd`~$MnsOq zth5Ep?&eR7xQ_&1U<%oW?331eG@a35Mehkn3S&T6Yf7w&E1Z zz&z{|59u*-zl;)uAAb$e@g96tKr5oLsCj;I0RVlyy*Gm$x8{Rg18$HG*_Vrd86vzA za_V#2h-%J5;UZssO%MNJ!m;KY#XLyus(r(1-i>UmT4ehV7Le+}ix`hrF&-Ok7etS; zJ1=@ayw2|j7KZz0D4Y@}%aLqFSt$`v$boLxsP;#mhUutOaQzGaLQ?NP(HPbrn9S4K zw{!KgIp7v6YAB|s6Dan{G(39xZSp6fE9jinArRhA*IOqhzHISI0Yk}1rs_^w=5{g- z)?}F8>@YIHz+g)fq6vaDEA7fc_xFzjg#wC<0kY~g6iUY+lJ0g)9jY5wcjm{oxKbGu z+4LVdT`9}gN@Jd{243ZCQSDhH>l1Gw(WS~|x$Zmr8V~q1mVe*h zk;eq97yZx0eJ7wgg(#b<)ghV~`4H+Qt$LY1^M|gDJBv0G(3{UhOy=hJ5?q8-1!hUI;Gp5NazUUQ>6TD zU_M2>@1ufp%wWUf$QWzoJ!InP!ODzyRF)GsH}B;>;Gunz8^5%PecMJ@8JbVKJxS~# zH~I~beF!6zXLsyxk2$W-pF4=tvXk93=&)Ox(Tvi3i%|l1j(!HR(3Vlqn1)6q?H61K z{SiM;i8A$GrPku`A;MC>)VW*xy=BY|n`BTZaa8?xT)q?Xm*zVI`X8lNy(Hlv9@!o> zIwgWDIE^=R)(-W}J2Y18P%y@fj@&J^NEo>M1D6eb7*e+z#_HD?bBnwO6z5XfkL1^l z=H?2G=NlT0ha>pH6n-;$U;m!&Sk{8K1G0Y2<02O(qV@X5pbSqnua^B<4}&M7z^Fq* zAsH(F_7e0`BZZ89T!r`E9>#tXCJ6S6foUl$ClXH!VJ}pdZT#EqO$a7uDeqM zzjHh)Vu@IGA0^&$i7|`4BE!6q<1f`}#7Ssb@y#7yj8>ijy_k2BvnQ@bgOE%-CY;HT zg?DSc!?Hj&`czxGEsn`Hc_fD*43icY8FTm;@$?O-S$2J4E+CC_VcyiVrvv5D@~-o~ z_E}(7x3AJyP%G8&2BHfZ2m5!T6Grr{4$@xVzGcnA^f3$Erm@l_QfpkP8$z9>+_8-( zXhP@?^lf?Q@^U{T!xe^A*)1g>LE27EH3m~Zh0mQG4eh#KOqXZ{zQGRQgmES&!6n^I z>3_yD;C^>9!NU}}WuMlm!Yo9Zk(`bo&Pf>V%{AE!nc!ng+ zKuG+byFTO9g8fYuxAqPkU{_J@<@&q$yYG@_KOEaM9Ho~aWgFReHmshVZgl&tj4XM! zcD};mYYY`8s|9-^+}x}hymL^3b7{C7GO{$wS&vEW$lB9vL}d^4CrZ831e1r)=*$Mh zAiWcYopE7=T99CByQ!kuy4lR#+by>f>UFLJj$T8WbWtKDQiMeFU`{9_)lmZ2np&B! zJR#hm9oim{n>|w>oGyN^RIiqUAuH;eV5;fEe0@x+hb4mSGHaU+ZPS&Gt*{NEAsMz{ zKg!M4UJ0ulf7Bz$mt55dGxv>pYES@j!AT+`;Tpmhl3ZU&ZU+DT z;GvuL;Tnc1(a)rS*|)b9g&FRc#c@%`z)+HsCwPj@*O_ITQF?z9xt3S39HVf!$KoH{ zMA9zkaMhV&`_6oS^o=Io$h>yDx#iF6J(h{qt#a`=l`!(I zFOb)fP89HZz|wqegf4w&J?<5)cioSPLwbn70fl+44v74We;jWEoi+EYiFs?yD|wke zb(`2x#or>6kY-wA>pnK+w%hQ1qkgH0ITV^#Jz`rP`kX11KoDm=Vy_+0QNrfKi~Gs) z4VmR6Tn3`@A_VvNZ*cd(1gAOL;}C!;AQ5@&3&XBACpP`{n_W=3>!{D%>fjjRVOE~T z1m-R!1^ww}YfJv~2bE+%V3sGhT)<>%@z;-n9KJG~>WT%vbNLLoCHR)An38w45JWTGDBK+N@!^d}OpCy~dGvYX-RxZ+<`3#?Gptud8`fYRdYFyE4xWY+q=FY77$ z#-HUzZg8NM7v>3df7!qAV-WJQv;UJr1n{rSrjehv#Yluf*K!UzRrV9K zIV8TloUAeuGAQ)qeLK+*?zb!S*6;2S$s&4|b4)P_lY6l12Lj_(@ahY1OIH~zC0M}} zBJY|0g4HutS6ESFq(ry+PTSNj7Z#@wd|SEno#tafG?Ioi8e*OnwL+h$?mS#Y{a|JA zbIy%otn_VKiJ-0BUrJP``-?N&cv!_&edgsAQmdp1)l%_k%PkIc{2x7C#CYCc5fcB5 zy4b4Zem|zFiI@biL9MBrC$#8mRm>PMkvSPEfNR|u#&MSZ!XEUYr`$f$id6RiaU|20 zY-o5c#!%8z%#Kb)#n>+)IYJ=^K^RR4Zs(c&?dkdNA(m}7t%IOPs+(^7uB@UGN6Pzgkt6W(4<#VN zF*%ho;GL)K;l`bHDb z-iFg^ex6arFzE}}4c7kte@5^ll zRnCrtnUz>W=YQwl>{!`KDYz4!XSoEA^MFiSDMb}D8!`5gXJEeyv(P*j7c<0}3ga|L zK5lGx4jNU#^0*C{;>;Hw3)6k4r8T0}#uwFW@Zz(rYEmCI^{@u&v~8B_oet-l0Z^3s zu=>sz_2E!`$mN#yMA$*E6v5YQW=vYDK3co$O)U0)8SzH*%FjtkV*K|))PH28#zTIr zx}NpPV5jqKXu%ju=d&tf}>YT+l{a{gNKW*Qt=7G_U_fzmziN8)QQs zq`rZ8A;$a)Hb%QmKcaViiiuqoM0uZ)9Qu*VA-?-Kww&o`aqSEAI0M2>8M7YL8df)2}~ZknsoIY6ySYAJ$Bq zGb11Bw|eb-%onOBc*137JX&-@uT*7WWTx|3D}wI zYs?YZOxAVM+&89I{q?DTHHFw`5<897Seuez{o96D5HbZNCB6vFpezz0Z9>d&?NK>oPmr(WRF^ZvqkIi36P;OwQV^aXGQ;(5B1!}HJZ8X(q7 z7QBO2XSg}S1OY_vbvKxCKb9#=qUQ}IyPOAQX7`IxJ=rnw1%Wa?XX(V>J|A33Go9P2yNFqCEd-j|Q zX{K1bzVI0Wl$cy>Xyx%zqy=_@)O34cE15rut>J)kJ^uYF+p+Opu;7(bGXGU+Phnhv zP74GQ)u7pRd{Htm5Jk=pJ?$fI_j<-=qhXxM&l|MJlXFHK&k4Q|^gu~0ptz|yL4fcZ zKG2a8#MBA+$A1`bwA>h3s20Ve^-x$61&{Nvg>wE;W=t2n==TFB!{$!MQ<=}=@I#7p zG9i5JDj0KHQAtdG?w=xO%E)4=rTV2Hi*j!Brki`IoT0(zgA*di$;eyIYV@q^^tPF- zVJKid5iR{ucq-{uAfTs=SoLBa-^w9&Jw(K7<{0D-nQvx24Bmo%;!m2V#R^8ehk|Wz zlEmYo_;5WfRrvu}d$0#}5>%`PB&$>bF0hVuN`}cIUA1 zl9NAxtb^Hgs;V9&y2Hi~c8@yATknRx@KT|}?kfeT+hfOR?GvPzi}PlR9&9+gQafp* zLvh>B!r(4XU#N^wze2v^#nz%*T6P{yxMPC&Mc&2y0pY>evWMy4j7`7J6+VDhkUw?L!ni zbfQq&8(t_77XqcYdg;+6-P?mfs|&`>)C!DXf94Igs4W9Dc~3z?~#HHBzFR*kShw-d-cm9M1 zt1(B@=Cz-nGt=efQt@au=(5Cx>PdkHKkj)gnL4DYoF3%a=w(27Stp67{l z|Du+%n=@tuw4$`KDhjZpq5|?cY(Z-{yeEAFFdBI;Nd-c~m^|_0T&p8gxha4(Vw4J& zGE}?Uy!99ARUdR{T7-DSt){z8aHEyKF^3-y(oD4(IA@i*hQ$J_LpG&R(>!-DdQ}~^QOY{~@jQ&o=uhAdrR2ea&l+5E|uOBKStd}$o zyFJ-dqk5lnPJv(Rv{`qf&!Ge=l-p=nIedeK{Fr1o*}FIG!pm8@^8q=!^1Y%K;SX8_ zsuAJ)Hjz+i87e*Aq}{(FF(`?Ev85;v1fZt!($r1EL81?>$)^6gdarwzQjathvN`7{U)<_6!21!)LRZZq z5j;WuhljhJQs5q zag{FNS;+an5Q+X+u(3)QqTWySDc)@J1QrSelQ`N=bH?H#*KJ_}gV|^H!LeYNUhf5c zc7oO6rQ><#}W4TrkiH%{pJlJs%TuIm0{(hZv1%BuS)D3d!Y&(FDf-Q2>Jt9iLt_ z^dCkQwfT4nHa#g;S$WMz=3T)SJn_jE>v2cCE*(zR5?aRZspj#u9CJ~n6E-&R5~5Xd z-DUZa+1L`Ws*hj2dSwt318@?H5f=OLB<^E~Lv7{_gND<@|3GOkSN*6kWe5ydH;DXC z)F88nVL{|-;inlz|CkkBk)X`Hb7sn6LD&3twSn)#Q(i69*awPwaqmf;`NN&` z&E6uQg$~micJ+M*y^S(6LXZN{lI~QvkNgUX&1aD~?tHy%+m*vs_s7y$vU7D?_~MaB z!=+<{Iz)^({gN&_r*RDCV5GqZ?<}Wiea6saDgPFE+9Y53B?Slf3R30o*ilEv6`Z*)L)jiAkc zcEm40#s~43yRvvC(ZdP46)cpa;XMo|g2zHV(p20r&iEkv7#IfNGI?Se3cK{;v@l3| zvK~DSlle{uim&K^Tf|GtW3$Sj;l8C|J-t+zm`Ku73iCv^nLiO1Y~Gdu6ZuA8wiTr@>ZV{% zxNc3&Dmg%{U~esvkYkMZ;>?bR@`2nK{BZoDriMFqz%tU|6Leq!c}|IQK1R@C}*!DFgK4Jfpb~m%0k{z!R}jvWWcU)1aA@yJ=A)rG$Kw zN+I$|JHBp!HNLiy@XkY&fL{1;G5DquI)^)1Y0%aW6N@+P|GxYKUwB_=3)7w852F#8GTE8vYw=WAPHmT0(0BZgcaZOSgupKFn$4 zZOd)k{#&1WQY(RDF>Sk53ErF72}Q=5sasqo@u0WM{ewN(Bg0#UV8933yGe_l$w+ycKB)#*Hv`{1IgK}k#$ZfMIe zaM02;{8b=nBYb{XqwQGTuRK2FdVbSzScSgOSZEPNC^FQej| zP#Xcx=v|M!zD1YQKF^Gp$-wTOvP{@(x;(Ou-GGhzKY#TiF88cJsRiK}(2J{IruwgQ z>GD1*v84`H))5cLU&f2xA@~AH=aj6{kSMhyIr&aaO zDuc5WAL7JaRQei;RQMeRg(mNL?WBVF^A`i!2fG3YhG)fj1Zpb1ig_P-P+C`6_`kN; zJQDU((*cEF!H_{o|KC6MFLz3$>@KFrdxl!C8FF)X^nVf6n=8oH$_=x$?eIz@>3+F8Ju^Xb1AenMlljxy7%#VLJZs>ii;0{m6Uope-#z_y?tU?l^*Yl{U=F!i1=BrlfnClSfK!l|@=jlM%Mj zi*?kzJ#*ck@bo^t@sj-HpLpv>kmY+4@J!h3Hj z*>Cn1B(+PYavo2C%N;(i+^JqhF0j;V6c2ZQFDQR+YAqt0MszYWp;K@F`to27U&z_n znRYtIXw!9P)F7st5=vO%@X$~VLNau7Ly8c(beY__B5q|kdwkM)66aKBT5;BMLzRVf zH#b+JHK=#~o8@vk67gopN@4t(MY}_b8+C~$1pP-*Q2GA+@^bPL6-d&~oT?|~7++V` z9k(?8>%?ueTe`sq4qNy4x5%oJ8!WZsRq+K%^?Cc*aMP=mU-Bss)c+RG+S}<#!h&*k zcq?~C`qw8}WjnVLeazJ?(`1SdCLi#4#8!MiqbY2+=7+m1DoK@=IF;;_{>^ob!<5`L zZet)T0MsJW3Ms7eI?|~ck9h)ZQ{OOWOJqFP$uAmR(dR2e^1A~TOP0h_k;0;(Gf5aW~`8|YUWI`<`4{-U{VuVpkVXO-* zKj7K4uH%8h;UIq#Xa*#QC@Ph^$+9iqP#McPiMu)G)8@(wqu})lwR*M13s2AH;I|c9 zBm_G=uPVf1F*G!toM1KIJnx8rK(iAoR02pnt_0^{uG&7`>=UFVw~;qL8t;6FSNwPa za~x^zwr&Rt219e2g$sGho-$-AL#r*PvoX*zzvvzMUq~zCE@MSW>Qo%u?<#l&NjVGq z&omu{%~os@e&MYh%%U2 zZhzU>KYla`l25}*z04q0%dG-0$_KVr)z*I7hfNQumm5-OmO$d;0JjtKs^74^i};5Qxg2!ljvo&HY$2?WWIg12Ry*@=DiSSx*rsgQ#P+iK8vnMg z>E~wMCn~{3-guOa+xkv&H85q0-pEQ6=46qdz40l#CdDk5oNrDVRe$z<{VVm&I?D)R zcQxsKxOOj&;}U;JaQ6q>@KC6c0_>Kg#XhFrXSeTfW_0^5nCqhuZMA^W#QE(U$BKa~ z+_6P{Git6Zjg2D6jyjWbrPHs-fe0*W z?PjF)I*aFNP3`#euQCR?uO^tC=JAuz2b4fe@^1W=Yu5$$Wu3&dv~U;(fh@*h{@3Wu znQC_(DVsh94gOP?OQ<7HYMl5$XJ2~nNPd3)&bi}!rNe&w1bdwut<&)w{_ag{>5U*n z&za-M;~&s@XW!Y&CZ(EwwfuyVo0mH_vrL+P3mMoglu2gX1A$%Rrc+J@IqVSyyv}VU zmnfSq9c@8sYPCEHHZXWj&Vl5Ueism{tca)IK&q0CB?j0wvYUYi(LY<@&{)6pEojJk zx*1%ua9SR17oI3g6O6KF-Y4xFpqy?u*{bkSXYt2 znI+_)J6NQWpaxK&34x~~y^f_V5%=bNv2XtY%@OSSg5^W<*c$Qjb&WJkE>?98L89iK z`3+sMnTE%KE_3|lYo`BH4ra|t($r~!`i4iwja!2MDpCvT*_K#$y+m^B2RJP_gGkcZ zzdr3i4_z0ur*AnwDPDdo8~>9+xr*Q!T6X&O4{a_t8~U z6dNUN6u{IgyndIf+7mpjK!{21$pH=;XY>Ez_q@kwVg7DoShXL<+u6qYW;>)bx0>Zd z2HT?wg}!G4ZMRp_;p|RmfH*`q--t`MP;1LRywTLubi@%=))%BbF4}>??SYtAjg&(> zulBGB>xf$I2mmt^+n2E97~8;vZ+w(KvcCf&tCj z+|5yP2ZX#|rorK2^~FN`oxk()kOMKu{)}G7n*TFCn5#^W_s?o=6`|t64f!H5O*J(+ zep@ABLAg7c9bTe}s{<5Az7Md7Na-EFxt|`;OJi{GT8Tu{8Ws{-oIwV576u4Ns0T`b z?Clee7t*#QXQXz8=!B35jgS46v9Th%L_MrC3nxOq?pCO_8Li6r(;q(YbNhM7A>Iuh z0C`s6?cgBQ3NIxU?;XAg z`LL)BAfkg-LHSl-`RCvSX^K9;C zho#7~CZ@BhC!8>cOyaZT)X<6UFb}$>U{B6l^-eGOSn$b-i6c;k!^1Dt!zpFZF8l&M zyiF?@PRMuQh{gShqwPCNE5-6l)+UxtXd>EC*4d=yasrnBl?%}@0XEj)9Yx)tUTaf4 z*2?oHMU%C|$ifu2ELp{bmVdT)i;^#+*E>jMKIXielxL-=a^xe;UT*B;QDus0)<6sA z$by^DGuh8+dB2Ci?axV{?-=o10!?yC0RdNf@~ajSwHLH$E5xCk1Rh}E4IEN@v1@+{|fRD+AT z)Jn92YwY=0k#&wyApEBskD6{ZO_@A83eNWSF99!*7u9I=e!meS2)jUAPCEwg1*bs|{1N2tGOAv&2m+9JOUN2o&HZtxMc zdp0-3$w(smy3TAaq_x)gJwXGpg?drc%o~@0FxYpcZ{&Z@LTo7b5)g-ZAFB2THcuB( z`S96fu2>`z;4Izrk|%u%kEA9{F#)})?FWNgj9Uf6!x? zMPZiEpN#YF$`g<9ADXlC<9Eqm_r&N$t%-)I-bvZ}Q2(Z!rg6s+9cQ8n2f@BDFxL#~ zBpiOUuUc||IWP%?amiigfaV%tf>fQ^+wO#`H;(r70|5QWjPpz|>7`bV*{=)_KQ|K{ z3c?R|xPdrrM;_73ANb-8;-Gw7s6-elrIwPZN zET}40HRWGZvWoa6c9Ob0wx44mL~M#LwHFqhsv6$t zoD*id&Ncrxx~HuYHlYiYz=fek#i(O0#yas5^V-UoZB;&AtGRYsC*M zd7J#n8i)O9mYHWAnG9E~wt7O~ye91Q-zFYhH{WWAUzomlp`}VNUg@Xt!Ud_F;V}xm zs6LKPZ*S?H)bEKC36n`4KA0V)Ji9iUe4nAReURfWE4OTwtqC%V{!cxNV#_>^7O@ZI5{;CkgvKgH^UHtDQMTK44+dz1P-2){Kv;KFkr7M zzeN$ZRe^VXgNjZdc;{Zo;V_f-Kuh&ynzi}bn81#SLF@(t`odyctszfim25@wi%3n5 zT$rFUufe+w`D+z^FwQjUbaSsXBm{mb>eP_2yv$NBGjQj3Ve(9V=8ai794~}TGCuKO z@U`B+MetI*jMqd=v*!9QYwg=1YJGCgx6R%KETD)vPPPvg?Fiv$INrq_jOs0OZfr{1?>4RnF($0y#Ci~V z%ojkpDQOpJFKw2Xi?ksDbZV&yKN(6p0J^46LWk8EhkJWXHV?Pet^aYykA17Wxh#?d zzN~m+Yje7Ub?dM|U%?qz9E#zjp@64|=B{;$P)n@qHiLyKv)HQ?6B8v2D?5@{*rUn8VeoyMtBnmB>e`>NMI5f`Xb_tQ)!b~{k@V^hK+q$@(p>8r8$Z$r zDwZpg93f)Rpze?Yr%zOe#5t>}&0M5#Tfez`KH^C*Q^NqZ?p!P_M_quaTlARzY8r!9 z7FjI*-8qZ=%&u99mf`Ew%HF|B_-F-~HYy{UWVzB?SpZfkpeOk0OPAp*Y|lbBaC1o! zHXL;881G|`D)$DYucX^&=%C^()LNxyUbgTb2aXxuM9VVgS+}sOooa~-%g4Au*W4nJ z_3x4K&@bWPVcinE{NavYR^BJH8sjp~+DPXi6rYQ3{GQBL7bDm?JUre#+)cP|Xl$G= zBG`eMz=}_Pn_>3N>uXSc|Av0HrFTz)i@W}1pkkGZ3Bt-%u3vORxQE##_L1K|@aRHc zWj0qLFA-l!hynw5K)Jg5RO41}Kek+K$t%He(pVxd4|nr7%jbNHyix}$ZqwifmaL7r zTQ$cj|8&tn>^ZngTMgRS;smjI%HWql5e1>f=!K3jfAL>qc$R`*{2afbvp-|-a=MWl7n0&4czCe>~~D06F=iffbZ zF@O_azwHa-`yQYw@O^}Hc;PfeE**9vl%Q?@eKv)QVrAB@l9C_u*)f;{`PjyK&mrws zsXO5AHF=E7O5Zu#>VC@iK3sFXFk=G@^Xo|QjN2^&|0fqfr%+|QWx3Vr6J+mgiq3zr z10u7;LZ8XX+O>DsH*HghG-C}Y?Qg+Jd8C}LrbrG)UrvuCH zuLGm3N)#^@lce*zkDO{v^q_=-eaqe{Ppg#Lg&tA}u-9F|;g^@5K#B3k%){K%*%J9P zr%wrm@7b0p42py}h+Zy1kDcaXfjDdGt_TO1`dOG=1t}^OVu!W1j&6s#3f}Rp5*WBm zw4vU2l&pRoU0$60@#N;j_8j>FBOdQEVy0VAjx;2G!=r1{b}qc2r8{(*8}Q5eW9vY( z^zCZg)1!Pk=D_T$ms_FKzp>Le0pOGwkw?TZED!@BYoc5VUY(;xP+{4zEhb7f`DD2ISjKeo>Gos_AJ44mwo6_? zb9L<%n)9?F4WHgk1CM9t&Z92i5ttd?$#s=)>)od+AQu9jk&hZH4FN$4K^*D@n_O5D z&kGwjxzA@|#d~+bw!dxUqHf%B=LQ-cS>zX#BR%v@-$Qs^Ok z$JbhZCgXJMB`~dUp(@|)|91`4)qbu&G+qepuufBl51M&A^r8N@>A<#og^s*Xu5^6K z-hgOWMtC|(T#|Hc!^=fT?u+rS^HsDDWFR`#XXP!5dJ6$5>EgY}p=di?Yc zr>%dDcFeG~?UG8jobDn2x>NkyGZz{#)bBHtr}!wPr{jQL0|OKxt=dq5*3>$|CgRo? zBLdWn%5HUtbP=VgrYg>rCv_en@w9yAn8VLk5@tQYn+;_)*DDx#E8DX%I`l|R#+TYY z`*F_e7Z04X@3kCocx8HJq>j4v>RaE1Yv@=w2iN0(7&p=vj-r3HK%*|!b)Rg+F(HQ* za!cvSzx|E(|BFx&LP(_Od`{-7y1p6i{+=E6sn>d`G>@zO(RYlWG44W*@i5)rfF{RN z4V>Vcl>q1;_dv9l-!U+T`e;T2ukSvf9y99))D~Bw(i(NIoYSv+LV)v$T`kfTPXj6} zqV9-_D>o4ftXb4j;U#j~CM?D^mdDpGwqID5)oQ|bET*0%8jBu%l}TE@WTorDVHIt zj%&3uGcbkw)g^#`$LfE_ntqf4^qItUkx0tDSE4wL{T^bF`tc2>tuc*(LwoS|)H<0{{}B^EQ`w^GCs#)C)FkOZCHm4Ol~PA*uOt2U&sw%H#j6k*y7H?J~Jl1 zcv(d7+2cQtX=DxCBf>&J3-7XI9qq!MF7zGpMM$9Y;#vD<*BH8ysgW5UsWb1SW_+rw z-VfjdFA$zCvr?9PfnV2y9e-oP*@9UFgU=Vh1M@>umISzZgGAdr|x7M?>}8xi@R7fJR5V@ZO)wDy5%Ak+y}- z4t4+v?+61ctG5UUHS(~7#afYuc(kRPJGG{()0t)qdcdZ(a1Dkm{sg!C*M}$WQ|JU3 zrMA87h`a-264eeliy!l`8APq;>hKnnLAm`WSM@Rmr$!EjD$(m_BjO~Ng$faCOpTV` zhGY0ct`8j4R@!c8bN{RbXhgeo)Bk{3E z&wBvBoz@s$psj^k6CP0$#*El<7X}Civ_8zz<7exzzJn|`-P}gNHeg;v&vuU>hYoy| zk25g8fCFuI!^Ozdze9)JKaJsnJWr}4bP*BENFJY9A!93Ld=f)R-Qoq`o?aHF~cf=fwt;}uH((IRiUcFpl)i4 zg1~!Q*#0qSM1XwplWFunYdY2_{dcx}uqYXj(IwP5Sk-squ>xO@NNCwudbSH<|G0g1 z{{=*c8=f1+>^xhMf*CTd6CrYm}{1ppU-m40;bag6z@;@)V{IA+ zD0qGO;ebLIsw<*fQA7IQ_5g|BkYEi?5#b6K6bRa(>o6J*epM$twc#hzM@$zjuoHL4 zP@c7H{A)J)rb8Cn&g%4A7tkY%qvC^RbojsV1S=^~2MVgxqR?G_XZS5@S``@v#hYiB zaXM=e)SbY*@=JX=19tltHm9p_B&|h(o>IYUCr@xH`A_&vv29PeD?8V{!Y!Ii0T)8B ziOFO3e=S{gTvXrFMnM5VDFKmg>6C_*P(WZ&kdOvJq`TwNA>9&7cS?7tAS?|_cXxO0 zeb?{rJ)isM{pXySGxN-ICVnhj+UWYaSno&&v&wildaq>tbW-^T3f^=``9VJbM>O2x zyVI+LNH4Bd4?T0qAg*w(G%iYh0#0Q-*WbK?VTnK2#)@s*JnQa{0~u>lYK5BbYAb%* z0~iS(UFrcn$@R}j?cuDk_O|tCMjYpbo-UW^2TQxbxW-N^!QjN76&qIcEEZ(~eDPEFo3$eJddK`RU zO=GD3c#|w+9>t|K9a`<)dj{N_hWYG2TE;) z`SzRPMVY=axXAIzWE%fe4%c+L+)oF9kpY8wm zxXdqVG=ySO@hBXz2Hys_{j>=Gxddr%TREw>l&$@K{hM6xlGXD*bF z0^dE<{Qcf)Jw}#VVg1kFO)LMom$iRZ1D9iB22lD4pj47G6QVgJFge5nOuYqBnZ)Jm z`H7{RUh2_)=eZll426#mV-x)CM~zN$;+DvjST((C;z<)oloh79bjL&YH*O-5&AiqG zSEpw5JL?h{#Y|29@o@iEH>S)tsx-7`N}bO}S)b-!PC@;IAnH>1wD2nHi(uXThFeEK z?$Jdl(};Cii%S$T;^z`WLGdTdGm7UDTKL;iq%k4JMVDL|V3nYyj6k|}_0jFj`6Bcg zXY3n{aR6oXl3PVt%7Cl0+7aGw9wIl*i?AH{`Lz z#wBXE-*ec6r-$a=nlkIJfkBgPtkS?(tT*-D@FK$ve&xBL^pV~0iB$>xaz=!ww)F(8 z`Rz8DE=sfZ3GA-$GLRI=HE|$hQ~Yw8tW{olRO4Ynp7;@bT)0AU^PzRotv~g`^ZB9{ zmWZCiuA~jBLPxO^d8*Uws{Cz$Gb#=eP<7v*vs#t4*xE+GNWLtmoRWrtzYJ~%s4dt zKL@?;qo%bR@xF+e8;^S%H~Gvtxm#&nWq)lHYqZMxS?HOi%y(X4IL6yp4){sn>d8yE zJrlLj3l>eWP?6?(Al%`mcjUD56ES2__1AW5SI?6=i?)56e_0Wz$PO)Jih^e{3+{?L z+PMf^9(pY-0`qH&z_H+{v90f(YxnsjK_a0fj%f*{h6E``M46VEGBhsK>Ibu}LaP{I zNa=CN7G1WTe&pMifwY9Zu~IUz^G=towI;)x>Hh6k)gTZ{M=9IA%RpT3=ut$Q_6=07 zdf9rNR4-#Kno4uIpCEVC3lP80Kq8r%v#Zi9eta_eiwYOb@x zR_q?yEmD-8PLzNC(!0S$M;EmwQRP57QAQb#B_6Bfe#mbv&`u)rT&0n~^2W`iY4a7w z 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%0ArFY9f1A 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 =#wbo)^Yo|d^EgT}7mR@P_690J`7 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 YS50-W!7YgK9n7aBrzTte>Rs^v0fa-$2LJ#7 From 554a37a5514c9c0afbbea0fdea99244873a38ee4 Mon Sep 17 00:00:00 2001 From: Jonny Dixon <45681293+acrylJonny@users.noreply.github.com> Date: Wed, 1 Jan 2025 09:19:27 +0000 Subject: [PATCH 08/10] fix(ingest/aws_common): update tests execution on EC2 instance (#12252) --- .../tests/unit/test_aws_common.py | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/metadata-ingestion/tests/unit/test_aws_common.py b/metadata-ingestion/tests/unit/test_aws_common.py index 9291fb91134b1c..dd1f06cf9bfd55 100644 --- a/metadata-ingestion/tests/unit/test_aws_common.py +++ b/metadata-ingestion/tests/unit/test_aws_common.py @@ -17,6 +17,14 @@ ) +@pytest.fixture +def mock_disable_ec2_metadata(): + """Disable EC2 metadata detection""" + with patch("requests.put") as mock_put: + mock_put.return_value.status_code = 404 + yield mock_put + + @pytest.fixture def mock_aws_config(): return AwsConnectionConfig( @@ -27,17 +35,19 @@ def mock_aws_config(): class TestAwsCommon: - def test_environment_detection_no_environment(self): + def test_environment_detection_no_environment(self, mock_disable_ec2_metadata): """Test environment detection when no AWS environment is present""" with patch.dict(os.environ, {}, clear=True): assert detect_aws_environment() == AwsEnvironment.UNKNOWN - def test_environment_detection_lambda(self): + def test_environment_detection_lambda(self, mock_disable_ec2_metadata): """Test Lambda environment detection""" with patch.dict(os.environ, {"AWS_LAMBDA_FUNCTION_NAME": "test-function"}): assert detect_aws_environment() == AwsEnvironment.LAMBDA - def test_environment_detection_lambda_cloudformation(self): + def test_environment_detection_lambda_cloudformation( + self, mock_disable_ec2_metadata + ): """Test CloudFormation Lambda environment detection""" with patch.dict( os.environ, @@ -48,7 +58,7 @@ def test_environment_detection_lambda_cloudformation(self): ): assert detect_aws_environment() == AwsEnvironment.CLOUD_FORMATION - def test_environment_detection_eks(self): + def test_environment_detection_eks(self, mock_disable_ec2_metadata): """Test EKS environment detection""" with patch.dict( os.environ, @@ -59,19 +69,19 @@ def test_environment_detection_eks(self): ): assert detect_aws_environment() == AwsEnvironment.EKS - def test_environment_detection_app_runner(self): + def test_environment_detection_app_runner(self, mock_disable_ec2_metadata): """Test App Runner environment detection""" with patch.dict(os.environ, {"AWS_APP_RUNNER_SERVICE_ID": "service-id"}): assert detect_aws_environment() == AwsEnvironment.APP_RUNNER - def test_environment_detection_ecs(self): + def test_environment_detection_ecs(self, mock_disable_ec2_metadata): """Test ECS environment detection""" with patch.dict( os.environ, {"ECS_CONTAINER_METADATA_URI_V4": "http://169.254.170.2/v4"} ): assert detect_aws_environment() == AwsEnvironment.ECS - def test_environment_detection_beanstalk(self): + def test_environment_detection_beanstalk(self, mock_disable_ec2_metadata): """Test Elastic Beanstalk environment detection""" with patch.dict(os.environ, {"ELASTIC_BEANSTALK_ENVIRONMENT_NAME": "my-env"}): assert detect_aws_environment() == AwsEnvironment.BEANSTALK @@ -103,6 +113,7 @@ def test_ec2_metadata_token_failure(self, mock_put): @patch("requests.put") def test_is_running_on_ec2(self, mock_put, mock_get): """Test EC2 instance detection with IMDSv2""" + # Explicitly mock EC2 metadata responses mock_put.return_value.status_code = 200 mock_put.return_value.text = "token123" mock_get.return_value.status_code = 200 @@ -322,7 +333,9 @@ def test_aws_connection_config_validation_error(self): ), ], ) - def test_environment_detection_parametrized(self, env_vars, expected_environment): + def test_environment_detection_parametrized( + self, mock_disable_ec2_metadata, env_vars, expected_environment + ): """Parametrized test for environment detection with different configurations""" with patch.dict(os.environ, env_vars, clear=True): assert detect_aws_environment() == expected_environment From ea249caee1bffadd237ee7031c4502dac0f87af6 Mon Sep 17 00:00:00 2001 From: Aseem Bansal Date: Wed, 1 Jan 2025 16:52:17 +0530 Subject: [PATCH 09/10] fix(ingest): json serializable fix (#12246) --- .../datahub_ingestion_run_summary_provider.py | 45 +++++- .../test_datahub_ingestion_reporter.py | 135 ++++++++++++++++++ 2 files changed, 179 insertions(+), 1 deletion(-) diff --git a/metadata-ingestion/src/datahub/ingestion/reporting/datahub_ingestion_run_summary_provider.py b/metadata-ingestion/src/datahub/ingestion/reporting/datahub_ingestion_run_summary_provider.py index 28def68ccf3f55..c143a8b49f4b7c 100644 --- a/metadata-ingestion/src/datahub/ingestion/reporting/datahub_ingestion_run_summary_provider.py +++ b/metadata-ingestion/src/datahub/ingestion/reporting/datahub_ingestion_run_summary_provider.py @@ -146,12 +146,55 @@ def __init__(self, sink: Sink, report_recipe: bool, ctx: PipelineContext) -> Non aspect_value=source_info_aspect, ) + @staticmethod + def _convert_sets_to_lists(obj: Any) -> Any: + """ + Recursively converts all sets to lists in a Python object. + Works with nested dictionaries, lists, and sets. + + Args: + obj: Any Python object that might contain sets + + Returns: + The object with all sets converted to lists + """ + if isinstance(obj, dict): + return { + key: DatahubIngestionRunSummaryProvider._convert_sets_to_lists(value) + for key, value in obj.items() + } + elif isinstance(obj, list): + return [ + DatahubIngestionRunSummaryProvider._convert_sets_to_lists(element) + for element in obj + ] + elif isinstance(obj, set): + return [ + DatahubIngestionRunSummaryProvider._convert_sets_to_lists(element) + for element in obj + ] + elif isinstance(obj, tuple): + return tuple( + DatahubIngestionRunSummaryProvider._convert_sets_to_lists(element) + for element in obj + ) + else: + return obj + def _get_recipe_to_report(self, ctx: PipelineContext) -> str: assert ctx.pipeline_config if not self.report_recipe or not ctx.pipeline_config.get_raw_dict(): return "" else: - return json.dumps(redact_raw_config(ctx.pipeline_config.get_raw_dict())) + redacted_recipe = redact_raw_config(ctx.pipeline_config.get_raw_dict()) + # This is required otherwise json dumps will fail + # with a TypeError: Object of type set is not JSON serializable + converted_recipe = ( + DatahubIngestionRunSummaryProvider._convert_sets_to_lists( + redacted_recipe + ) + ) + return json.dumps(converted_recipe) def _emit_aspect(self, entity_urn: Urn, aspect_value: _Aspect) -> None: self.sink.write_record_async( diff --git a/metadata-ingestion/tests/unit/reporting/test_datahub_ingestion_reporter.py b/metadata-ingestion/tests/unit/reporting/test_datahub_ingestion_reporter.py index 749ea03a7f20a8..2ab6208e2dcc68 100644 --- a/metadata-ingestion/tests/unit/reporting/test_datahub_ingestion_reporter.py +++ b/metadata-ingestion/tests/unit/reporting/test_datahub_ingestion_reporter.py @@ -1,3 +1,5 @@ +from typing import Any, Dict, List, Set, Tuple, Union + import pytest from datahub.ingestion.reporting.datahub_ingestion_run_summary_provider import ( @@ -50,3 +52,136 @@ def test_default_config(): typed_config = DatahubIngestionRunSummaryProviderConfig.parse_obj({}) assert typed_config.sink is None assert typed_config.report_recipe is True + + +def test_simple_set() -> None: + """Test conversion of a simple set""" + input_data: Set[int] = {1, 2, 3} + expected: List[int] = [1, 2, 3] + result = DatahubIngestionRunSummaryProvider._convert_sets_to_lists(input_data) + assert sorted(result) == sorted(expected) + assert isinstance(result, list) + + +def test_nested_dict_with_sets() -> None: + """Test conversion of nested dictionary containing sets""" + input_data: Dict[str, Union[Set[int], Dict[str, Set[str]]]] = { + "set1": {1, 2, 3}, + "dict1": {"set2": {"a", "b"}}, + } + expected = { + "set1": [1, 2, 3], + "dict1": {"set2": ["a", "b"]}, + } + result = DatahubIngestionRunSummaryProvider._convert_sets_to_lists(input_data) + + def sort_nested_lists(d): + return { + k: ( + sorted(v) + if isinstance(v, list) + else (sort_nested_lists(v) if isinstance(v, dict) else v) + ) + for k, v in d.items() + } + + assert sort_nested_lists(result) == sort_nested_lists(expected) + + +def test_nested_lists_with_sets() -> None: + """Test conversion of nested lists containing sets""" + input_data = [{1, 2}, [{3, 4}, {5, 6}]] + expected = [[1, 2], [[3, 4], [5, 6]]] + result = DatahubIngestionRunSummaryProvider._convert_sets_to_lists(input_data) + assert [ + sorted(x) + if isinstance(x, list) and len(x) > 0 and not isinstance(x[0], list) + else x + for x in result + ] == [ + sorted(x) + if isinstance(x, list) and len(x) > 0 and not isinstance(x[0], list) + else x + for x in expected + ] + + +def test_tuple_with_sets() -> None: + """Test conversion of tuples containing sets""" + input_data = (1, {2, 3}, 4) + expected = (1, [2, 3], 4) + result = DatahubIngestionRunSummaryProvider._convert_sets_to_lists(input_data) + assert (result[0], sorted(result[1]), result[2]) == ( + expected[0], + sorted(expected[1]), + expected[2], + ) + assert isinstance(result, tuple) + + +def test_mixed_nested_structure() -> None: + """Test conversion of a complex nested structure""" + input_data = { + "simple_set": {1, 2, 3}, + "nested_dict": { + "another_set": {"a", "b", "c"}, + "mixed_list": [1, {2, 3}, {"x", "y"}], + }, + "tuple_with_set": (1, {4, 5}, 6), + "list_of_sets": [{1, 2}, {3, 4}], + } + result = DatahubIngestionRunSummaryProvider._convert_sets_to_lists(input_data) + + # Verify structure types + assert isinstance(result["simple_set"], list) + assert isinstance(result["nested_dict"]["another_set"], list) + assert isinstance(result["nested_dict"]["mixed_list"][1], list) + assert isinstance(result["nested_dict"]["mixed_list"][2], list) + assert isinstance(result["tuple_with_set"], tuple) + assert isinstance(result["tuple_with_set"][1], list) + assert isinstance(result["list_of_sets"][0], list) + + +def test_non_set_data() -> None: + """Test that non-set data remains unchanged""" + input_data = { + "string": "hello", + "int": 42, + "float": 3.14, + "bool": True, + "none": None, + "list": [1, 2, 3], + "dict": {"a": 1, "b": 2}, + } + result = DatahubIngestionRunSummaryProvider._convert_sets_to_lists(input_data) + assert result == input_data + + +def test_empty_structures() -> None: + """Test handling of empty structures""" + input_data: Dict[ + str, Union[Set[Any], Dict[Any, Any], List[Any], Tuple[Any, ...]] + ] = {"empty_set": set(), "empty_dict": {}, "empty_list": [], "empty_tuple": ()} + expected: Dict[ + str, Union[List[Any], Dict[Any, Any], List[Any], Tuple[Any, ...]] + ] = {"empty_set": [], "empty_dict": {}, "empty_list": [], "empty_tuple": ()} + result = DatahubIngestionRunSummaryProvider._convert_sets_to_lists(input_data) + assert result == expected + + +def test_json_serializable() -> None: + """Test that the converted structure is JSON serializable""" + import json + + input_data = { + "set": {1, 2, 3}, + "nested": {"set": {"a", "b"}}, + "mixed": [1, {2, 3}, {"x"}], + } + result = DatahubIngestionRunSummaryProvider._convert_sets_to_lists(input_data) + try: + json.dumps(result) + serializable = True + except TypeError: + serializable = False + assert serializable From 67ef55efc7a65485b944722fb4895ea54e644f1d Mon Sep 17 00:00:00 2001 From: Aseem Bansal Date: Thu, 2 Jan 2025 15:11:35 +0530 Subject: [PATCH 10/10] fix(ingest/gc): soft deletion loop fix (#12255) --- .../source/gc/dataprocess_cleanup.py | 8 +- .../source/gc/soft_deleted_entity_cleanup.py | 230 ++++++++++++------ 2 files changed, 163 insertions(+), 75 deletions(-) diff --git a/metadata-ingestion/src/datahub/ingestion/source/gc/dataprocess_cleanup.py b/metadata-ingestion/src/datahub/ingestion/source/gc/dataprocess_cleanup.py index 3f7a1fc453bcdb..64c1a0ad0bfbad 100644 --- a/metadata-ingestion/src/datahub/ingestion/source/gc/dataprocess_cleanup.py +++ b/metadata-ingestion/src/datahub/ingestion/source/gc/dataprocess_cleanup.py @@ -167,7 +167,7 @@ class DataJobEntity: class DataProcessCleanupReport(SourceReport): num_aspects_removed: int = 0 num_aspect_removed_by_type: TopKDict[str, int] = field(default_factory=TopKDict) - sample_removed_aspects_by_type: TopKDict[str, LossyList[str]] = field( + sample_soft_deleted_aspects_by_type: TopKDict[str, LossyList[str]] = field( default_factory=TopKDict ) num_data_flows_found: int = 0 @@ -286,9 +286,9 @@ def delete_entity(self, urn: str, type: str) -> None: self.report.num_aspect_removed_by_type[type] = ( self.report.num_aspect_removed_by_type.get(type, 0) + 1 ) - if type not in self.report.sample_removed_aspects_by_type: - self.report.sample_removed_aspects_by_type[type] = LossyList() - self.report.sample_removed_aspects_by_type[type].append(urn) + if type not in self.report.sample_soft_deleted_aspects_by_type: + self.report.sample_soft_deleted_aspects_by_type[type] = LossyList() + self.report.sample_soft_deleted_aspects_by_type[type].append(urn) if self.dry_run: logger.info( diff --git a/metadata-ingestion/src/datahub/ingestion/source/gc/soft_deleted_entity_cleanup.py b/metadata-ingestion/src/datahub/ingestion/source/gc/soft_deleted_entity_cleanup.py index 93f004ab675edc..4c0355834f9b4f 100644 --- a/metadata-ingestion/src/datahub/ingestion/source/gc/soft_deleted_entity_cleanup.py +++ b/metadata-ingestion/src/datahub/ingestion/source/gc/soft_deleted_entity_cleanup.py @@ -1,9 +1,10 @@ import logging import time -from concurrent.futures import ThreadPoolExecutor, as_completed +from concurrent.futures import FIRST_COMPLETED, Future, ThreadPoolExecutor, wait from dataclasses import dataclass, field from datetime import datetime, timezone -from typing import List, Optional +from threading import Lock +from typing import Dict, Iterable, List, Optional from pydantic import Field @@ -18,12 +19,28 @@ logger = logging.getLogger(__name__) +QUERY_QUERY_ENTITY = """ +query listQueries($input: ScrollAcrossEntitiesInput!) { + scrollAcrossEntities(input: $input) { + nextScrollId + count + searchResults { + entity { + ... on QueryEntity { + urn + } + } + } + } +} +""" + class SoftDeletedEntitiesCleanupConfig(ConfigModel): enabled: bool = Field( default=True, description="Whether to do soft deletion cleanup." ) - retention_days: Optional[int] = Field( + retention_days: int = Field( 10, description="Number of days to retain metadata in DataHub", ) @@ -62,23 +79,30 @@ class SoftDeletedEntitiesCleanupConfig(ConfigModel): default=None, description="Query to filter entities", ) + limit_entities_delete: Optional[int] = Field( 25000, description="Max number of entities to delete." ) - runtime_limit_seconds: Optional[int] = Field( - None, + futures_max_at_time: int = Field( + 1000, description="Max number of futures to have at a time." + ) + + runtime_limit_seconds: int = Field( + 7200, # 2 hours by default description="Runtime limit in seconds", ) @dataclass class SoftDeletedEntitiesReport(SourceReport): - num_soft_deleted_entity_removed: int = 0 - num_soft_deleted_entity_removed_by_type: TopKDict[str, int] = field( - default_factory=TopKDict - ) - sample_soft_deleted_removed_aspects_by_type: TopKDict[str, LossyList[str]] = field( + num_queries_found: int = 0 + num_soft_deleted_entity_processed: int = 0 + num_soft_deleted_retained_due_to_age: int = 0 + num_soft_deleted_entity_removal_started: int = 0 + num_hard_deleted: int = 0 + num_hard_deleted_by_type: TopKDict[str, int] = field(default_factory=TopKDict) + sample_hard_deleted_aspects_by_type: TopKDict[str, LossyList[str]] = field( default_factory=TopKDict ) @@ -103,48 +127,53 @@ def __init__( self.config = config self.report = report self.dry_run = dry_run + self.start_time = 0.0 + self._report_lock: Lock = Lock() + self.last_print_time = 0.0 + + def _increment_retained_count(self) -> None: + """Thread-safe method to update report fields""" + with self._report_lock: + self.report.num_soft_deleted_retained_due_to_age += 1 + + def _increment_removal_started_count(self) -> None: + """Thread-safe method to update report fields""" + with self._report_lock: + self.report.num_soft_deleted_entity_removal_started += 1 + + def _update_report(self, urn: str, entity_type: str) -> None: + """Thread-safe method to update report fields""" + with self._report_lock: + self.report.num_hard_deleted += 1 + + current_count = self.report.num_hard_deleted_by_type.get(entity_type, 0) + self.report.num_hard_deleted_by_type[entity_type] = current_count + 1 + if entity_type not in self.report.sample_hard_deleted_aspects_by_type: + self.report.sample_hard_deleted_aspects_by_type[ + entity_type + ] = LossyList() + self.report.sample_hard_deleted_aspects_by_type[entity_type].append(urn) def delete_entity(self, urn: str) -> None: assert self.ctx.graph entity_urn = Urn.from_string(urn) - self.report.num_soft_deleted_entity_removed += 1 - self.report.num_soft_deleted_entity_removed_by_type[entity_urn.entity_type] = ( - self.report.num_soft_deleted_entity_removed_by_type.get( - entity_urn.entity_type, 0 - ) - + 1 - ) - if ( - entity_urn.entity_type - not in self.report.sample_soft_deleted_removed_aspects_by_type - ): - self.report.sample_soft_deleted_removed_aspects_by_type[ - entity_urn.entity_type - ] = LossyList() - self.report.sample_soft_deleted_removed_aspects_by_type[ - entity_urn.entity_type - ].append(urn) - if self.dry_run: logger.info( f"Dry run is on otherwise it would have deleted {urn} with hard deletion" ) return - + self._increment_removal_started_count() self.ctx.graph.delete_entity(urn=urn, hard=True) self.ctx.graph.delete_references_to_urn( urn=urn, dry_run=False, ) + self._update_report(urn, entity_urn.entity_type) def delete_soft_deleted_entity(self, urn: str) -> None: assert self.ctx.graph - if self.config.retention_days is None: - logger.info("Retention days is not set, skipping soft delete cleanup") - return - retention_time = ( int(datetime.now(timezone.utc).timestamp()) - self.config.retention_days * 24 * 60 * 60 @@ -157,15 +186,85 @@ def delete_soft_deleted_entity(self, urn: str) -> None: ]["created"]["time"] < (retention_time * 1000): logger.debug(f"Hard deleting {urn}") self.delete_entity(urn) + else: + self._increment_retained_count() + + def _print_report(self) -> None: + time_taken = round(time.time() - self.last_print_time, 1) + # Print report every 2 minutes + if time_taken > 120: + self.last_print_time = time.time() + logger.info(f"\n{self.report.as_string()}") + + def _process_futures(self, futures: Dict[Future, str]) -> Dict[Future, str]: + done, not_done = wait(futures, return_when=FIRST_COMPLETED) + futures = {future: urn for future, urn in futures.items() if future in not_done} + + for future in done: + self._print_report() + if future.exception(): + logger.error( + f"Failed to delete entity {futures[future]}: {future.exception()}" + ) + self.report.failure( + f"Failed to delete entity {futures[future]}", + exc=future.exception(), + ) + self.report.num_soft_deleted_entity_processed += 1 + if ( + self.report.num_soft_deleted_entity_processed % self.config.batch_size + == 0 + ): + if self.config.delay: + logger.debug( + f"Sleeping for {self.config.delay} seconds before further processing batch" + ) + time.sleep(self.config.delay) + return futures - def cleanup_soft_deleted_entities(self) -> None: - if not self.config.enabled: - return + def _get_soft_deleted_queries(self) -> Iterable[str]: assert self.ctx.graph - start_time = time.time() - - deleted_count_retention = 0 - urns = self.ctx.graph.get_urns_by_filter( + scroll_id: Optional[str] = None + while True: + try: + result = self.ctx.graph.execute_graphql( + QUERY_QUERY_ENTITY, + { + "input": { + "types": ["QUERY"], + "query": "*", + "scrollId": scroll_id if scroll_id else None, + "count": self.config.batch_size, + "orFilters": [ + { + "and": [ + { + "field": "removed", + "values": ["true"], + "condition": "EQUAL", + } + ] + } + ], + } + }, + ) + except Exception as e: + self.report.failure( + f"While trying to get queries with {scroll_id}", exc=e + ) + break + scroll_across_entities = result.get("scrollAcrossEntities") + if not scroll_across_entities: + break + scroll_id = scroll_across_entities.get("nextScrollId") + self.report.num_queries_found += scroll_across_entities.get("count") + for query in scroll_across_entities.get("searchResults"): + yield query["entity"]["urn"] + + def _get_urns(self) -> Iterable[str]: + assert self.ctx.graph + yield from self.ctx.graph.get_urns_by_filter( entity_types=self.config.entity_types, platform=self.config.platform, env=self.config.env, @@ -173,52 +272,41 @@ def cleanup_soft_deleted_entities(self) -> None: status=RemovedStatusFilter.ONLY_SOFT_DELETED, batch_size=self.config.batch_size, ) + yield from self._get_soft_deleted_queries() + + def cleanup_soft_deleted_entities(self) -> None: + if not self.config.enabled: + return + self.start_time = time.time() - futures = {} + futures: Dict[Future, str] = dict() with ThreadPoolExecutor(max_workers=self.config.max_workers) as executor: - num_urns_submitted = 0 - for urn in urns: - num_urns_submitted += 1 + for urn in self._get_urns(): + self._print_report() + while len(futures) >= self.config.futures_max_at_time: + futures = self._process_futures(futures) if ( self.config.limit_entities_delete - and num_urns_submitted > self.config.limit_entities_delete + and self.report.num_hard_deleted > self.config.limit_entities_delete ): logger.info( - f"Limit of {self.config.limit_entities_delete} entities reached. Stopping" + f"Limit of {self.config.limit_entities_delete} entities reached. Stopped adding more." ) break if ( self.config.runtime_limit_seconds - and time.time() - start_time > self.config.runtime_limit_seconds + and time.time() - self.start_time + > self.config.runtime_limit_seconds ): logger.info( - f"Runtime limit of {self.config.runtime_limit_seconds} seconds reached. Stopping" + f"Runtime limit of {self.config.runtime_limit_seconds} seconds reached. Not submitting more futures." ) break future = executor.submit(self.delete_soft_deleted_entity, urn) futures[future] = urn - if not futures: - return - for future in as_completed(futures): - if future.exception(): - logger.error( - f"Failed to delete entity {futures[future]}: {future.exception()}" - ) - self.report.failure( - f"Failed to delete entity {futures[future]}", - exc=future.exception(), - ) - deleted_count_retention += 1 - - if deleted_count_retention % self.config.batch_size == 0: - logger.info( - f"Processed {deleted_count_retention} soft deleted entity and deleted {self.report.num_soft_deleted_entity_removed} entities so far" - ) - - if self.config.delay: - logger.debug( - f"Sleeping for {self.config.delay} seconds before getting next batch" - ) - time.sleep(self.config.delay) + logger.info(f"Waiting for {len(futures)} futures to complete") + while len(futures) > 0: + self._print_report() + futures = self._process_futures(futures)