From 14abd22ce07345e948eb2be631a51ae3df80607a Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Wed, 13 Nov 2024 18:17:55 +0100 Subject: [PATCH 01/45] feat: add version in header (#1412) * feat: add version in header * fix: PR remarks * fix: missing export * chore: move controller advice * fix: broken IT * fix: duplicate bean * fix: duplicate bean * fix: duplicate bean * chore: additional test --- .../AdminVersionHeaderControllerAdvice.java | 21 +++++++++++++++++++ .../AdminEventStreamsRestControllerTest.java | 11 +++++++++- .../VersionHeaderControllerAdvice.java | 21 +++++++++++++++++++ .../EventStreamControllerTest.java | 16 +++++++++++++- .../rest/treenode/TreeNodeControllerTest.java | 17 ++++++++++++++- .../server/LdesServerIntegrationTest.java | 3 +++ 6 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/versioning/AdminVersionHeaderControllerAdvice.java create mode 100644 ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/versioning/VersionHeaderControllerAdvice.java diff --git a/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/versioning/AdminVersionHeaderControllerAdvice.java b/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/versioning/AdminVersionHeaderControllerAdvice.java new file mode 100644 index 000000000..c695dfc46 --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/versioning/AdminVersionHeaderControllerAdvice.java @@ -0,0 +1,21 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.versioning; + +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.boot.info.BuildProperties; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ModelAttribute; + +@ControllerAdvice +public class AdminVersionHeaderControllerAdvice { + private static final String APP_VERSION_HEADER_KEY = "X-App-Version"; + private final String appVersion; + + public AdminVersionHeaderControllerAdvice(BuildProperties buildProperties) { + this.appVersion = buildProperties.getVersion(); + } + + @ModelAttribute + public void addVersionHeader(HttpServletResponse response) { + response.setHeader(APP_VERSION_HEADER_KEY, appVersion); + } +} diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java index 490257628..68bd4356b 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java @@ -6,6 +6,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.converters.EventStreamHttpConverter; import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.converters.EventStreamListHttpConverter; import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.exceptionhandling.AdminRestResponseEntityExceptionHandler; +import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.versioning.AdminVersionHeaderControllerAdvice; import be.vlaanderen.informatievlaanderen.ldes.server.admin.spi.*; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.HttpModelConverter; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.PrefixAdderImpl; @@ -24,8 +25,11 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; @@ -58,13 +62,16 @@ EventStreamWriter.class, EventStreamReader.class, ViewSpecificationConverter.class, PrefixAdderImpl.class, ValidatorsConfig.class, AdminRestResponseEntityExceptionHandler.class, RetentionModelExtractor.class, CharsetEncodingConfig.class, - FragmentationConfigExtractor.class, PrefixConstructor.class, RdfModelConverter.class}) + FragmentationConfigExtractor.class, PrefixConstructor.class, RdfModelConverter.class, AdminVersionHeaderControllerAdvice.class}) +@Import(BuildProperties.class) class AdminEventStreamsRestControllerTest { private static final String COLLECTION = "name1"; public static final String TIMESTAMP_PATH = "http://purl.org/dc/terms/created"; public static final String VERSION_OF_PATH = "http://purl.org/dc/terms/isVersionOf"; @MockBean private EventStreamService eventStreamService; + @SpyBean + private AdminVersionHeaderControllerAdvice adminVersionHeaderControllerAdvice; @Autowired private MockMvc mockMvc; @@ -124,6 +131,7 @@ void when_StreamsPresent_then_StreamsAreReturned() throws Exception { .andExpect(IsIsomorphic.with(expectedEventStreamsModel)); verify(eventStreamService).retrieveAllEventStreams(); + verify(adminVersionHeaderControllerAdvice).addVersionHeader(any()); } } @@ -149,6 +157,7 @@ void when_StreamPresent_Then_StreamIsReturned() throws Exception { .andExpect(IsIsomorphic.with(model)); verify(eventStreamService).retrieveEventStream(COLLECTION); + verify(adminVersionHeaderControllerAdvice).addVersionHeader(any()); } @Test diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/versioning/VersionHeaderControllerAdvice.java b/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/versioning/VersionHeaderControllerAdvice.java new file mode 100644 index 000000000..28aa26f15 --- /dev/null +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/versioning/VersionHeaderControllerAdvice.java @@ -0,0 +1,21 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.rest.versioning; + +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.boot.info.BuildProperties; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ModelAttribute; + +@ControllerAdvice +public class VersionHeaderControllerAdvice { + private static final String APP_VERSION_HEADER_KEY = "X-App-Version"; + private final String appVersion; + + public VersionHeaderControllerAdvice(BuildProperties buildProperties) { + this.appVersion = buildProperties.getVersion(); + } + + @ModelAttribute + public void addVersionHeader(HttpServletResponse response) { + response.setHeader(APP_VERSION_HEADER_KEY, appVersion); + } +} diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java index fad0329f5..99a86d731 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java @@ -12,6 +12,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.rest.config.RestConfig; import be.vlaanderen.informatievlaanderen.ldes.server.rest.eventstream.converters.EventStreamResponseHttpConverter; import be.vlaanderen.informatievlaanderen.ldes.server.rest.exceptionhandling.RestResponseEntityExceptionHandler; +import be.vlaanderen.informatievlaanderen.ldes.server.rest.versioning.VersionHeaderControllerAdvice; import org.apache.jena.rdf.model.*; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFParser; @@ -26,6 +27,7 @@ import org.junit.jupiter.params.provider.ArgumentsSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; @@ -42,6 +44,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Objects; +import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; @@ -53,6 +56,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest @@ -62,11 +66,12 @@ RestResponseEntityExceptionHandler.class, EventStreamWriter.class, EventStreamReader.class, ViewSpecificationConverter.class, PrefixAdderImpl.class, EventStreamResponseHttpConverter.class, RetentionModelExtractor.class, HttpModelConverter.class, FragmentationConfigExtractor.class, - PrefixConstructor.class, RdfModelConverter.class + PrefixConstructor.class, RdfModelConverter.class, VersionHeaderControllerAdvice.class }) class EventStreamControllerTest { private static final String COLLECTION = "mobility-hindrances"; private static final Integer CONFIGURED_MAX_AGE_MUTABLE = 180; + private static final String VERSION = "4.0.4-SNAPSHOT"; @Autowired private MockMvc mockMvc; @@ -94,6 +99,7 @@ void when_GetRequestOnCollectionName_EventStreamIsReturned(String mediaType, Lan String expectedEtagHeaderValue) throws Exception { ResultActions resultActions = mockMvc.perform(get("/{viewName}", COLLECTION) .accept(mediaType)) + .andExpect(header().string("X-App-Version", VERSION)) .andExpect(status().isOk()); MvcResult result = resultActions.andReturn(); @@ -175,6 +181,7 @@ void should_ReturnDcat_when_Valid() throws Exception { mockMvc.perform(get("/") .accept(MediaType.ALL)) .andExpect(status().isOk()) + .andExpect(header().string("X-App-Version", VERSION)) .andExpect(result -> { String contentAsString = result.getResponse().getContentAsString(); Model actualModel = RDFParser.create().fromString(contentAsString).lang(Lang.TURTLE).toModel(); @@ -203,5 +210,12 @@ public static class EventStreamControllerTestConfiguration { public CachingStrategy cachingStrategy(@Value(HOST_NAME_KEY) String hostName) { return new EtagCachingStrategy(hostName); } + + @Bean + public BuildProperties buildProperties() { + final Properties properties = new Properties(); + properties.put("version", VERSION); + return new BuildProperties(properties); + } } } diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java index bb865639d..5d35f71f6 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java @@ -22,6 +22,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.rest.exceptionhandling.RestResponseEntityExceptionHandler; import be.vlaanderen.informatievlaanderen.ldes.server.rest.treenode.config.TreeViewWebConfig; import be.vlaanderen.informatievlaanderen.ldes.server.rest.treenode.services.*; +import be.vlaanderen.informatievlaanderen.ldes.server.rest.versioning.VersionHeaderControllerAdvice; import org.apache.jena.rdf.model.*; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFParser; @@ -35,6 +36,7 @@ import org.junit.jupiter.params.provider.ArgumentsSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; @@ -54,6 +56,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; @@ -74,7 +77,8 @@ RestConfig.class, TreeViewWebConfig.class, RestResponseEntityExceptionHandler.class, PrefixConstructor.class, RdfModelConverter.class, TreeNodeStreamConverterImpl.class, PrefixAdderImpl.class, - TreeNodeStatementCreatorImpl.class, CharsetEncodingConfig.class}) + TreeNodeStatementCreatorImpl.class, CharsetEncodingConfig.class, VersionHeaderControllerAdvice.class, +}) class TreeNodeControllerTest { private static final String COLLECTION_NAME = "ldes-1"; private static final String FRAGMENTATION_VALUE_1 = "2020-12-28T09:36:09.72Z"; @@ -82,6 +86,7 @@ class TreeNodeControllerTest { private String fullViewName; private static final Integer CONFIGURED_MAX_AGE = 180; private static final Integer CONFIGURED_MAX_AGE_IMMUTABLE = 360; + private static final String VERSION = "4.0.4-SNAPSHOT"; @Autowired private MockMvc mockMvc; @@ -132,6 +137,7 @@ void when_GETRequestIsPerformed_ResponseContainsAnLDesFragment(String mediaType, .andExpect(status().isOk()) .andExpect(header().string("Cache-Control", expectedHeaderValue)) .andExpect(header().string("Etag", "\"" + expectedEtag + "\"")) + .andExpect(header().string("X-App-Version", VERSION)) .andExpect(content().encoding(StandardCharsets.UTF_8)) .andExpect(content().contentTypeCompatibleWith(expectedContentType)) .andReturn(); @@ -170,6 +176,7 @@ void given_MemberWithSpecialChars_when_GetRequestIsPerformed_then_CharsAreRightf .accept(mediaType)) .andExpect(status().isOk()) .andExpect(content().encoding(StandardCharsets.UTF_8)) + .andExpect(header().string("X-App-Version", VERSION)) .andExpect(content().contentTypeCompatibleWith(mediaType)) .andExpect(content().string(containsString("ë"))) .andExpect(content().string(containsString("你好"))) @@ -224,6 +231,7 @@ void when_GETRequestButMissingFragmentExceptionIsThrown_NotFoundIsReturned() thr mockMvc.perform(get("/{collectionName}/{viewName}", COLLECTION_NAME, VIEW_NAME) .accept("application/n-quads")) .andExpect(status().isNotFound()) + .andExpect(header().string("X-App-Version", VERSION)) .andExpect(content().string("Resource of type: fragment with id: bucketDescriptor could not be found.")); } @@ -306,6 +314,13 @@ public TreeNodeConverter ldesFragmentConverter(@Value(HOST_NAME_KEY) String host public CachingStrategy cachingStrategy(@Value(HOST_NAME_KEY) String hostName) { return new EtagCachingStrategy(hostName); } + + @Bean + public BuildProperties buildProperties() { + final Properties properties = new Properties(); + properties.setProperty("version", VERSION); + return new BuildProperties(properties); + } } private static Member createMember() { diff --git a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerIntegrationTest.java b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerIntegrationTest.java index 2ed21783e..44d6816f7 100644 --- a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerIntegrationTest.java +++ b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerIntegrationTest.java @@ -11,10 +11,12 @@ import org.springframework.batch.core.explore.JobExplorer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; @@ -33,6 +35,7 @@ @ActiveProfiles("postgres-test") @ContextConfiguration(classes = {MemberEntityRepository.class, PageRelationPostgresRepository.class, PageRelationEntityRepository.class}) @ComponentScan(value = {"be.vlaanderen.informatievlaanderen.ldes.server"}) +@Import({BuildProperties.class}) @TestPropertySource(properties = { "ldes-server.fragmentation-cron=*/1 * * * * *", "ldes-server.maintenance-cron=*/10 * * * * *", From 5f56f79d3c2ac2df9f061dfcfaada96babdba6e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:06:30 +0100 Subject: [PATCH 02/45] chore(deps): bump rexml from 3.2.5 to 3.3.9 in /docs (#1406) Bumps [rexml](https://github.com/ruby/rexml) from 3.2.5 to 3.3.9. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.2.5...v3.3.9) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 881a4fe10..dce50a8b3 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -59,7 +59,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rexml (3.2.5) + rexml (3.3.9) rouge (3.30.0) rubyzip (2.3.2) safe_yaml (1.0.5) From 54743d879a2625da6f1b59bd6623ce73bd0a28a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:07:19 +0100 Subject: [PATCH 03/45] chore(deps): bump webrick from 1.8.1 to 1.8.2 in /docs (#1397) Bumps [webrick](https://github.com/ruby/webrick) from 1.8.1 to 1.8.2. - [Release notes](https://github.com/ruby/webrick/releases) - [Commits](https://github.com/ruby/webrick/compare/v1.8.1...v1.8.2) --- updated-dependencies: - dependency-name: webrick dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index dce50a8b3..b542a67a0 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -68,7 +68,7 @@ GEM sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - webrick (1.8.1) + webrick (1.8.2) PLATFORMS x64-mingw-ucrt From c74ff1a9cb567b89b266d70b724dfb8fefaf7e2e Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:46:08 +0100 Subject: [PATCH 04/45] chore: cleanup retired linear caching (#1413) --- .../fragmentations/timebased.md | 32 ------------------- .../OpenApiAdminViewsRestController.java | 1 - .../src/main/resources/viewShaclShape.ttl | 11 +------ .../config/TimeBasedProperties.java | 1 - .../TimeBasedRelationsAttributerTest.java | 2 +- 5 files changed, 2 insertions(+), 45 deletions(-) diff --git a/docs/_configuration/fragmentations/timebased.md b/docs/_configuration/fragmentations/timebased.md index 7d3e8d495..ab883af31 100644 --- a/docs/_configuration/fragmentations/timebased.md +++ b/docs/_configuration/fragmentations/timebased.md @@ -17,7 +17,6 @@ Timebased fragmentation will create fragments based on a time selected from the tree:fragmentationStrategy [ a tree:HierarchicalTimeBasedFragmentation ; tree:maxGranularity { Mandatory: defines the depth level of the fragments } ; - tree:linearTimeCachingEnabled { Optional: indicates if fragments should be cached by linear time (true/false) } ; tree:fragmentationPath { Mandatory: defines which property will be used for bucketizing } ; tree:fragmenterSubjectFilter { Optional: regex to filter the subjects matching the fragmentationPath } ; ] . @@ -30,37 +29,6 @@ For maxGranularity the following values are allowed: * minute, * second. -### Linear time caching -This configuration which is off by default makes it possible to activate intelligent caching for time based data. -When you have a data with timestamps that keep increasing and are always current or newer it possible to improve -the caching. **We always assume that future members will have future timestamps.** - -**For example** -timestamp: 21/02/2024 - -Will result in fragments: -- root -- year=2024 -- year=2024&month=02 -- year=2024&month=02&day=21 - -We will assume that no new year will be added to the root until 31/12/2024. -We will assume that no new month will be added to year=2024 until 29/02/2024. -We will assume that no new day will be added to year=2024&month=02 until 21/02/2024 23:59:59. - -When a new day is added later, for example 22/02/2024. All other days and all its pages in year=2024&month=02 will -become immutable. We always assume that future members will have future timestamps. - -The above logic makes the server a lot more efficient for this kind of timebased data. Clients won't have to -keep track of an increasing number of open fragments. - -This optional feature is disabled by default and needs to be activated -by adding `tree:linearTimeCachingEnabled true ;` to the config. - -**Historical data seeding** -This feature will still work when you seed a new server with historical data as long as you ingest the data -in chronological order. This is because fragments do not become immutable until a fragment further in time is added. - ## Algorithm 1. The fragmentationObjects of the member are determined diff --git a/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/OpenApiAdminViewsRestController.java b/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/OpenApiAdminViewsRestController.java index 081a440a7..a8bc8e064 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/OpenApiAdminViewsRestController.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/OpenApiAdminViewsRestController.java @@ -105,7 +105,6 @@ void createView( tree:fragmentationStrategy ([ a tree:HierarchicalTimeBasedFragmentation ; tree:maxGranularity "day" ; - tree:linearTimeCachingEnabled "true" ; tree:fragmentationPath ldes:timestampPath ; ]) ; tree:pageSize "100"^^ ; diff --git a/ldes-server-admin/ldes-server-admin-rest/src/main/resources/viewShaclShape.ttl b/ldes-server-admin/ldes-server-admin-rest/src/main/resources/viewShaclShape.ttl index 96553ed17..40a5fe4bf 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/main/resources/viewShaclShape.ttl +++ b/ldes-server-admin/ldes-server-admin-rest/src/main/resources/viewShaclShape.ttl @@ -47,7 +47,7 @@ tree:HierarchicalTimeBasedFragmentation sh:class: tree:HierarchicalTimeBasedFragmentation ; sh:targetClass tree:HierarchicalTimeBasedFragmentation ; sh:zeroOrOnePath true; - sh:property tree:FragmentationPath, tree:MaxGranularity, tree:LinearTimeCachingEnabled, tree:FragmentSubjectFilter . + sh:property tree:FragmentationPath, tree:MaxGranularity, tree:FragmentSubjectFilter . tree:MaxGranularity a sh:PropertyShape; @@ -59,15 +59,6 @@ tree:MaxGranularity sh:minCount 1 ; sh:maxCount 1 . -tree:LinearTimeCachingEnabled - a sh:PropertyShape; - sh:name "Linear Time Caching Enabled" ; - sh:description "Indicates if fragments should be cached by linear time" ; - sh:path tree:linearTimeCachingEnabled ; - sh:datatype xsd:string ; - sh:minCount 0 ; - sh:maxCount 1 . - tree:FragmentSubjectFilter a sh:PropertyShape; sh:name "Fragment Subject Filter" ; diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/config/TimeBasedProperties.java b/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/config/TimeBasedProperties.java index b2199c443..7e6f989e6 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/config/TimeBasedProperties.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/config/TimeBasedProperties.java @@ -8,6 +8,5 @@ private TimeBasedProperties() { public static final String FRAGMENTATION_PATH = "fragmentationPath"; public static final String MAX_GRANULARITY = "maxGranularity"; public static final String FRAGMENTATION_SUBJECT_FILTER = "fragmentationSubjectFilter"; - public static final String LINEAR_TIME_CACHING_ENABLED = "linearTimeCachingEnabled"; } diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/services/TimeBasedRelationsAttributerTest.java b/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/services/TimeBasedRelationsAttributerTest.java index 72e920aca..a51f7fb77 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/services/TimeBasedRelationsAttributerTest.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/services/TimeBasedRelationsAttributerTest.java @@ -32,7 +32,7 @@ void setUp() { } @Test - void when_RelationNotPresent_AndCachingDisabled_ThenRelationIsAdded_NextUpdateTsIsNotSet_ChildrenStayMutable() { + void when_RelationNotPresent_ThenRelationIsAdded_NextUpdateTsIsNotSet_ChildrenStayMutable() { Bucket child = parentBucket.createChild(monthPair); TreeRelation gteRelation = new TreeRelation( From e45c8c94c1c1129003b605db0cbec803f6e0f7a9 Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:47:02 +0100 Subject: [PATCH 05/45] fix: misplaced version number (#1415) chore: bump zonky embedded db --- ldes-server-infra-postgres/pom.xml | 2 +- ldes-server-integration-test/pom.xml | 2 +- pom.xml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ldes-server-infra-postgres/pom.xml b/ldes-server-infra-postgres/pom.xml index 2e9c0a4b7..02bd3a538 100644 --- a/ldes-server-infra-postgres/pom.xml +++ b/ldes-server-infra-postgres/pom.xml @@ -62,7 +62,7 @@ io.zonky.test embedded-database-spring-test - 2.5.1 + ${zonky.embbeded-db.version} test diff --git a/ldes-server-integration-test/pom.xml b/ldes-server-integration-test/pom.xml index 450f08b1b..b172599da 100644 --- a/ldes-server-integration-test/pom.xml +++ b/ldes-server-integration-test/pom.xml @@ -93,7 +93,7 @@ io.zonky.test embedded-database-spring-test - 2.5.0 + ${zonky.embbeded-db.version} test diff --git a/pom.xml b/pom.xml index cde429ca6..52215c02d 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,7 @@ false 1.4 3.1.0 + 2.5.1 be.vlaanderen.informatievlaanderen.vsds From 99ec6dcb262a1c2299ef96a5f49eeb50ae37eeec Mon Sep 17 00:00:00 2001 From: Jan Robert <15772440+Yalz@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:22:13 +0100 Subject: [PATCH 06/45] feat: kafka in + bump 3.6.0 (#1414) * wip: first setup * feat: working kafka listener * feat: working kafka source in admin * fix: update bean name in tests * feat: working kafka source in admin * feat: add integration test * feat: add integration test * fix test * fix test * chore: add kafka jar * sonar * add assembly * docs: documentation effort * chore: pr remarks * ci: prepare release 3.6.0 --------- Co-authored-by: Yalz # Conflicts: # ldes-server-admin/ldes-server-admin-common/pom.xml # ldes-server-admin/ldes-server-admin-rest/pom.xml # ldes-server-admin/pom.xml # ldes-server-application/pom.xml # ldes-server-domain/pom.xml # ldes-server-fetch/ldes-server-fetch-common/pom.xml # ldes-server-fetch/ldes-server-fetch-rest/pom.xml # ldes-server-fetch/pom.xml # ldes-server-fragmentation/ldes-server-fragmentation-common/pom.xml # ldes-server-fragmentation/ldes-server-fragmentation-geospatial/pom.xml # ldes-server-fragmentation/ldes-server-fragmentation-reference/pom.xml # ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/pom.xml # ldes-server-fragmentation/ldes-server-pagination/pom.xml # ldes-server-fragmentation/pom.xml # ldes-server-infra-postgres/pom.xml # ldes-server-infra-postgres/postgres-admin-repository/pom.xml # ldes-server-infra-postgres/postgres-fetch-repository/pom.xml # ldes-server-infra-postgres/postgres-fragmentation-repository/pom.xml # ldes-server-infra-postgres/postgres-ingest-repository/pom.xml # ldes-server-infra-postgres/postgres-liquibase/pom.xml # ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/master.xml # ldes-server-infra-postgres/postgres-maintenance-repository/pom.xml # ldes-server-infra-postgres/postgres-pagination-repository/pom.xml # ldes-server-ingest/ldes-server-ingest-common/pom.xml # ldes-server-ingest/ldes-server-ingest-rest/pom.xml # ldes-server-ingest/pom.xml # ldes-server-integration-test/pom.xml # ldes-server-maintenance/ldes-server-compaction/pom.xml # ldes-server-maintenance/ldes-server-maintenance-common/pom.xml # ldes-server-maintenance/ldes-server-retention/pom.xml # ldes-server-maintenance/pom.xml # pom.xml --- .github/Dockerfile | 2 + README.md | 25 ++-- content/dependency-graph.dot | 4 + content/ldes-server-graph.png | Bin 47842 -> 47304 bytes docker-compose/kafka/docker-compose.yml | 71 ++++++++++ docs/_configuration/event-stream.md | 4 + docs/_ingest/kafka.md | 70 ++++++++++ .../ldes-server-admin-common/pom.xml | 2 +- .../services/EventSourceServiceImpl.java | 2 +- .../repository/EventStreamRepository.java | 2 +- .../services/EventStreamServiceImpl.java | 20 ++- .../kafkasource/KafkaSourceRepository.java | 10 ++ .../server/admin/spi/EventStreamReader.java | 9 +- .../ldes/server/admin/spi/EventStreamTO.java | 14 ++ .../server/admin/spi/KafkaSourceReader.java | 57 ++++++++ .../src/main/java/module-info.java | 1 + .../services/EventStreamServiceImplTest.java | 3 + .../admin/spi/EventStreamReaderTest.java | 4 +- .../server/admin/spi/EventStreamTOTest.java | 16 +++ .../admin/spi/KafkaSourceReaderTest.java | 57 ++++++++ .../ldes-with-kafkaES-noMime.ttl | 8 ++ .../ldes-with-kafkaES-noTopic.ttl | 8 ++ .../with-kafka-source/ldes-with-kafkaES.ttl | 9 ++ .../ldes-server-admin-rest/pom.xml | 2 +- .../rest/config/SpringIntegrationTest.java | 4 + .../AdminEventStreamsRestControllerTest.java | 2 +- ldes-server-admin/pom.xml | 2 +- ldes-server-application/pom.xml | 17 ++- .../ldes/server/OpenApiConfig.java | 32 +++-- ldes-server-domain/pom.xml | 2 +- .../events/admin/KafkaSourceAddedEvent.java | 6 + .../ldes/server/domain/model/EventSource.java | 19 +-- .../domain/model/KafkaSourceProperties.java | 4 + .../ldes-server-fetch-common/pom.xml | 2 +- .../ldes-server-fetch-rest/pom.xml | 2 +- .../EventStreamControllerTest.java | 2 +- ldes-server-fetch/pom.xml | 2 +- .../ldes-server-fragmentation-common/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../ldes-server-pagination/pom.xml | 2 +- ldes-server-fragmentation/pom.xml | 2 +- ldes-server-infra-postgres/pom.xml | 2 +- .../postgres-admin-repository/pom.xml | 2 +- .../EventSourcePostgresRepository.java | 6 +- .../EventStreamPostgresRepository.java | 5 +- .../eventstream/entity/EventStreamEntity.java | 4 + .../KafkaSourcePostgresRepository.java | 33 +++++ .../kafkasource/entity/KafkaSourceEntity.java | 42 ++++++ .../KafkaSourceEntityRepository.java | 10 ++ .../EventSourcePostgresRepositoryTest.java | 2 +- .../EventStreamPostgresRepositoryTest.java | 3 + .../postgres-fetch-repository/pom.xml | 4 +- .../postgres-fragmentation-repository/pom.xml | 2 +- .../postgres-ingest-repository/pom.xml | 2 +- .../postgres-liquibase/pom.xml | 2 +- .../3_6_0/init-collection_kafka_sources.xml | 28 ++++ .../resources/db/changelog/3_6_0/master.xml | 8 ++ .../main/resources/db/changelog/master.xml | 1 + .../postgres-maintenance-repository/pom.xml | 2 +- .../postgres-pagination-repository/pom.xml | 2 +- .../ldes-server-ingest-common/pom.xml | 2 +- .../ingest}/validators/IngestValidator.java | 2 +- .../BlankNodesValidator.java | 2 +- .../IngestReportValidator.java | 2 +- .../ingestreportvalidator/PathsValidator.java | 2 +- .../ShaclReportManager.java | 2 +- .../MemberIngestValidator.java | 8 +- .../ldes-server-ingest-kafka/pom.xml | 44 ++++++ .../kafka/KafkaListenerContainerManager.java | 89 ++++++++++++ .../ingest/kafka/config/KafkaConfig.java | 21 +++ .../controller/KafkaConsumerController.java | 127 ++++++++++++++++++ .../exception/KafkaConsumerException.java | 8 ++ .../ingest/kafka/listener/IngestListener.java | 41 ++++++ .../kafka/model/KafkaConsumerAssignment.java | 26 ++++ .../kafka/model/KafkaConsumerRequest.java | 4 + .../kafka/model/KafkaConsumerResponse.java | 40 ++++++ .../KafkaConsumerControllerTest.java | 100 ++++++++++++++ .../ldes-server-ingest-rest/pom.xml | 2 +- .../ingest/rest/MemberIngestController.java | 2 +- .../collection/VersionOfPathCollection.java | 32 ----- ...ionRestResponseEntityExceptionHandler.java | 8 -- .../exception/MemberIdNotFoundException.java | 21 --- .../rest/MemberIngestControllerTest.java | 12 +- .../MemberIngestValidatorTest.java | 8 +- ldes-server-ingest/pom.xml | 3 +- ldes-server-integration-test/pom.xml | 36 ++++- .../ldes/server/IngestKafkaSteps.java | 80 +++++++++++ .../server/LdesServerIntegrationTest.java | 19 ++- .../resources/application-postgres-test.yml | 8 ++ .../kafka/event-stream_kafka_jsonld.ttl | 16 +++ .../kafka/event-stream_kafka_nq.ttl | 16 +++ .../kafka/event-stream_kafka_ttl.ttl | 16 +++ .../data/input/members/mob-hind.template.json | 30 +++++ .../data/input/members/mob-hind.template.nq | 4 + .../features/ingest/ingest-kafka.feature | 25 ++++ .../ldes-server-compaction/pom.xml | 2 +- .../ldes-server-maintenance-common/pom.xml | 2 +- .../ldes-server-retention/pom.xml | 2 +- ldes-server-maintenance/pom.xml | 2 +- pom.xml | 5 +- 102 files changed, 1370 insertions(+), 169 deletions(-) create mode 100644 docker-compose/kafka/docker-compose.yml create mode 100644 docs/_ingest/kafka.md create mode 100644 ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/kafkasource/KafkaSourceRepository.java create mode 100644 ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/KafkaSourceReader.java create mode 100644 ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/KafkaSourceReaderTest.java create mode 100644 ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES-noMime.ttl create mode 100644 ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES-noTopic.ttl create mode 100644 ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES.ttl create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/events/admin/KafkaSourceAddedEvent.java create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/model/KafkaSourceProperties.java create mode 100644 ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/KafkaSourcePostgresRepository.java create mode 100644 ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/entity/KafkaSourceEntity.java create mode 100644 ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/repository/KafkaSourceEntityRepository.java create mode 100644 ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/3_6_0/init-collection_kafka_sources.xml create mode 100644 ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/3_6_0/master.xml rename ldes-server-ingest/{ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest => ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest}/validators/IngestValidator.java (62%) rename ldes-server-ingest/{ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest => ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest}/validators/ingestreportvalidator/BlankNodesValidator.java (96%) rename ldes-server-ingest/{ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest => ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest}/validators/ingestreportvalidator/IngestReportValidator.java (73%) rename ldes-server-ingest/{ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest => ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest}/validators/ingestreportvalidator/PathsValidator.java (97%) rename ldes-server-ingest/{ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest => ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest}/validators/ingestreportvalidator/ShaclReportManager.java (93%) rename ldes-server-ingest/{ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest => ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest}/validators/memberingestvalidator/MemberIngestValidator.java (88%) create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/pom.xml create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/KafkaListenerContainerManager.java create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/config/KafkaConfig.java create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerController.java create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/exception/KafkaConsumerException.java create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/listener/IngestListener.java create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerAssignment.java create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerRequest.java create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerResponse.java create mode 100644 ldes-server-ingest/ldes-server-ingest-kafka/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerControllerTest.java delete mode 100644 ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/collection/VersionOfPathCollection.java delete mode 100644 ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/exception/MemberIdNotFoundException.java create mode 100644 ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/IngestKafkaSteps.java create mode 100644 ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_jsonld.ttl create mode 100644 ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_nq.ttl create mode 100644 ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_ttl.ttl create mode 100644 ldes-server-integration-test/src/test/resources/data/input/members/mob-hind.template.json create mode 100644 ldes-server-integration-test/src/test/resources/data/input/members/mob-hind.template.nq create mode 100644 ldes-server-integration-test/src/test/resources/features/ingest/ingest-kafka.feature diff --git a/.github/Dockerfile b/.github/Dockerfile index 91436a344..9f222c04c 100644 --- a/.github/Dockerfile +++ b/.github/Dockerfile @@ -15,6 +15,8 @@ COPY ./ldes-server-ingest/ldes-server-ingest-rest/target/ldes-server-ingest-rest COPY ./ldes-server-fetch/ldes-server-fetch-rest/target/ldes-server-fetch-rest-jar-with-dependencies.jar ./lib/ COPY ./ldes-server-admin/ldes-server-admin-rest/target/ldes-server-admin-rest-jar-with-dependencies.jar ./lib/ +COPY ./ldes-server-ingest/ldes-server-ingest-kafka/target/ldes-server-ingest-kafka-jar-with-dependencies.jar ./lib/ + # Plugin Fragmentations COPY ./ldes-server-fragmentation/ldes-server-fragmentation-geospatial/target/ldes-server-fragmentation-geospatial-jar-with-dependencies.jar ./lib/ COPY ./ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/target/ldes-server-fragmentation-timebased-hierarchical-jar-with-dependencies.jar ./lib/ diff --git a/README.md b/README.md index 34749faa0..69103ce10 100644 --- a/README.md +++ b/README.md @@ -52,18 +52,19 @@ Each maven profile represents a different functionality of the LDES server that The default exported image contains all the profiles, but a custom image can be created with only the needed dependencies. -| Profile | Dependencies | Description | -|----------------------------|--------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------| -| `fragmentation` | `postgres-pagination-repository` | Allows basic fragmentation (pagination) | -| `maintenance` | `postgres-maintenance-repository` | Allows the LDES server to perform maintenance operations on its Event Streams and Members: compaction, retention, deletion. | -| **Interfaces** | | | -| `http-admin` | `ldes-server-admin-rest`,`postgres-admin-repository`* | Gives access to REST API to create and manage Event Streams and Views. | -| `http-ingest` | `ldes-server-ingest-rest`,`postgres-ingest-repository` | Gives access to REST API to ingest members into the LDES. | -| `http-fetch` | `ldes-server-fetch-rest`,`postgres-fetch-repository` | Gives access to REST API to fetch Event Streams, its Views and pages. | -| **Plugin Fragmentations** | | | -| `fragmentation-timebased` | `ldes-server-fragmentation-timebased-hierarchical` | Allows fragmentation in based on a timebased property. | -| `fragmentation-geospatial` | `ldes-server-fragmentation-geospatial` | Allows fragmentation in based on a geospatial property. | -| `fragmentation-reference` | `ldes-server-fragmentation-reference` | Allows fragmentation in based on a textual property. | +| Profile | Dependencies | Description | +|----------------------------|---------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------| +| `fragmentation` | `postgres-pagination-repository` | Allows basic fragmentation (pagination) | +| `maintenance` | `postgres-maintenance-repository` | Allows the LDES server to perform maintenance operations on its Event Streams and Members: compaction, retention, deletion. | +| **Interfaces** | | | +| `http-admin` | `ldes-server-admin-rest`,`postgres-admin-repository`* | Gives access to REST API to create and manage Event Streams and Views. | +| `http-ingest` | `ldes-server-ingest-rest`,`postgres-ingest-repository` | Gives access to REST API to ingest members into the LDES. | +| `kafka-ingest` | `ldes-server-ingest-kafka`,`postgres-ingest-repository` | Allows Kafka member ingestion into the LDES. | +| `http-fetch` | `ldes-server-fetch-rest`,`postgres-fetch-repository` | Gives access to REST API to fetch Event Streams, its Views and pages. | +| **Plugin Fragmentations** | | | +| `fragmentation-timebased` | `ldes-server-fragmentation-timebased-hierarchical` | Allows fragmentation in based on a timebased property. | +| `fragmentation-geospatial` | `ldes-server-fragmentation-geospatial` | Allows fragmentation in based on a geospatial property. | +| `fragmentation-reference` | `ldes-server-fragmentation-reference` | Allows fragmentation in based on a textual property. | *: The `postgres-admin-repository`, as shown by the dependency graph, will be loaded in by the other above-mentioned functionality profiles. diff --git a/content/dependency-graph.dot b/content/dependency-graph.dot index e7a0e1f7e..6b49bdb30 100644 --- a/content/dependency-graph.dot +++ b/content/dependency-graph.dot @@ -14,6 +14,7 @@ digraph "ldes-server" { "be.vlaanderen.informatievlaanderen.vsds:ldes-server-ingest-common:jar:compile"[label=] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fetch-rest:jar:compile"[label=, fillcolor="#87CEFA", style="filled"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fetch-common:jar:compile"[label=] + "be.vlaanderen.informatievlaanderen.vsds:ldes-server-ingest-kafka:jar:compile"[label=, fillcolor="#87CEFA", style="filled"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-retention:jar:compile"[label=] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-maintenance-common:jar:compile"[label=] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-compaction:jar:compile"[label=] @@ -33,6 +34,7 @@ digraph "ldes-server" { "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fragmentation-reference:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fragmentation-common:jar:compile" "be.vlaanderen.informatievlaanderen.vsds:ldes-server-admin-rest:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-admin-common:jar:compile" "be.vlaanderen.informatievlaanderen.vsds:ldes-server-ingest-rest:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-ingest-common:jar:compile" + "be.vlaanderen.informatievlaanderen.vsds:ldes-server-ingest-kafka:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-ingest-common:jar:compile" "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fetch-rest:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fetch-common:jar:compile" "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fetch-rest:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-admin-common:jar:compile" "be.vlaanderen.informatievlaanderen.vsds:ldes-server-retention:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-maintenance-common:jar:compile" @@ -52,6 +54,7 @@ digraph "ldes-server" { "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:postgres-liquibase:jar:compile" [label="Database Changes"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-ingest-rest:jar:compile" [label="Ingest REST API"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:postgres-ingest-repository:jar:compile" [label="Ingest Implementation"] + "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-ingest-kafka:jar:compile" [label="Ingest Kafka"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fetch-rest:jar:compile" [label="Fetch REST API"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:postgres-fetch-repository:jar:compile" [label="Fetch Implementation"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:postgres-pagination-repository:jar:compile" [label="Basic Fragmentation Implementation"] @@ -60,4 +63,5 @@ digraph "ldes-server" { "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-fragmentation-reference:jar:compile" [label="Plugin Fragmentation"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:ldes-server-admin-rest:jar:compile" [label="Admin REST API"] "be.vlaanderen.informatievlaanderen.vsds:ldes-server-application:jar:compile" -> "be.vlaanderen.informatievlaanderen.vsds:postgres-maintenance-repository:jar:compile" [label="Maintenance Implementation"] + } \ No newline at end of file diff --git a/content/ldes-server-graph.png b/content/ldes-server-graph.png index 8ea0f4d5c806f5f755b6b2b2ea116b947cf620f5..70238a1b32b47bc65327d435b43aa96df17a4f8a 100644 GIT binary patch literal 47304 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

o8EBvx+{SCpb@;AkW(PIqkgN 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

e@sYF3=f`xfld$Irp-FxaHnc zu%zuWfGqJe3FgV>M6JiJaodaWkn8ig-Z?#P9ZPU_*a<=B4As8sGs1jme`zCHR$e`c z26!^=1mN?x09(cyyg#uc0^laPEtrd14MBXlbr;0xqd{gY8YJ1y|ta?8aMO z+`&}Y>y!+{8;?#pQpd*DbYmf#0Cq@8&R z5kPjsr43}P_5{KxKBzs93Z@11*UZxAlBdDpv@onhN__Bph!oORnQ*TA+8KU}s1u@? z-9&(WNeto+|Av_OUYzdjHA6u$K=)$!wDqnP;>t1t{01_#b7vtr8vq(Vg_0?x>-+yv zPhl5*0Ug}s&&Bo)$f81T;pYq!Ma_56*=Ld8ymhE50cxf{wpsvLwz!>s~ZonZ?lkf-doG;JjT}_uHe|BPyjZ+ zp0W8`dHo>Fe?fPZ^`?~$i00=UjOT5zS`#?@ZyyfzE${M(1|8`(oNP$3k zmjWIWB`ztPG0-Ly&UKM{gFr?cKV=ih;356?z)j|Li`P&2ci`N)#pbdQIFlf}S`?&f zfO@Q-cV{6Gl8ovt3kONgdD>s|fe(SVD0@pUDWr;mrqC%A zS55{I^u9#0ka^AF2Kaia03by`I9r=MDdXju&uvq;SiV z**>B9zkbql(u@B4@BjJzKO^uzBk(^X@c(iI^ry~4jt9~%P&rd(H^7gYinel)^9Hvj+t literal 47842 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 Mt0q$^WgPUs0CW;b@Bjb+ diff --git a/docker-compose/kafka/docker-compose.yml b/docker-compose/kafka/docker-compose.yml new file mode 100644 index 000000000..97385ae8d --- /dev/null +++ b/docker-compose/kafka/docker-compose.yml @@ -0,0 +1,71 @@ +version: "3.3" +services: + ldes-server: + container_name: basic_ldes-server + image: ldes/ldes-server + environment: + - SPRING_CONFIG_LOCATION=/config/ + - PYROSCOPE_CONFIGURATION_FILE=/config/pyroscope.properties + volumes: + - ./docker-compose/server.config.yml:/config/application.yml:ro + - ./docker-compose/pyroscope.properties:/config/pyroscope.properties:ro + ports: + - "8080:8080" + - "8087:8087" + - "8088:8088" + - "8089:8089" + networks: + - ldes + depends_on: + - postgres + postgres: + container_name: ldes-postgres + image: postgres:14-alpine + ports: + - 5432:5432 + environment: + - POSTGRES_PASSWORD=admin + - POSTGRES_USER=admin + - POSTGRES_DB=test + networks: + - ldes + pyroscope: + image: grafana/pyroscope:latest + ports: + - 4040:4040 + networks: + - ldes + + zookeeper: + image: zookeeper:3.7.0 + ports: + - "2181:2181" + + kafka: + image: confluentinc/cp-kafka:7.3.2 + ports: + - "9092:9092" + - "29092:29092" + depends_on: + - zookeeper + environment: + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_LISTENERS: INTERNAL://:9092,EXTERNAL://0.0.0.0:29092 + KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:9092,EXTERNAL://localhost:29092 + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT + KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL + ALLOW_PLAINTEXT_LISTENER: 'yes' + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + + kafka-ui: + image: provectuslabs/kafka-ui:latest + depends_on: + - kafka + ports: + - "9200:8080" + environment: + KAFKA_CLUSTERS_0_NAME: local + KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 + KAFKA_CLUSTERS_0_ZOOKEEPER: zookeeper:2181 +networks: + ldes: \ No newline at end of file diff --git a/docs/_configuration/event-stream.md b/docs/_configuration/event-stream.md index 6b3fe92f6..044144c48 100644 --- a/docs/_configuration/event-stream.md +++ b/docs/_configuration/event-stream.md @@ -64,6 +64,10 @@ server:generic-eventstream a ldes:EventStream ; genericES:shape a sh:NodeShape . ```` +## Configuring an Event Stream with a Kafka source + +To configure an Event Stream that ingests members from a Kafka topic, please visit the [Kafka Ingest documentation](../ingest/kafka). + ## Configuring a SHACL Shape [SHACL (Shapes Constraint Language)](https://www.w3.org./TR/shacl/) is a standard for validating RDF data and ensuring diff --git a/docs/_ingest/kafka.md b/docs/_ingest/kafka.md new file mode 100644 index 000000000..4c9bf7e57 --- /dev/null +++ b/docs/_ingest/kafka.md @@ -0,0 +1,70 @@ +--- +layout: default +title: Ingest Members With Kafka +nav_order: 0 +--- + +# Ingest Members With Kafka + +Ingesting members into an Event Stream without too much overhead? +That's now possible via ingestion over Apache Kafka. + +## Getting Started + +To get started with ingesting members via Kafka, you need to have the following: +* Kafka consumer configuration (in the Application Properties) +* Event Stream configuration pointing to a Kafka topic (in the Admin API) + +### Application Properties + +The Kafka consumer configuration can be set in the `application.properties` file. + +The most basic properties that are needed are: +````yaml +spring.kafka.consumer.bootstrap-servers=localhost:9092 +spring.kafka.consumer.group-id=my-group +```` + +To guarantee that the Kafka consumer will always read from the beginning of the topic, you can add the following property: +````yaml +spring.kafka.consumer.auto-offset-reset=earliest +```` + +For more advanced options to configure advanced Kafka connections, please refer to the [Spring Kafka documentation](https://docs.spring.io/spring-boot/appendix/application-properties/index.html). + +### Event Stream Configuration + +To configure a new Event Stream that uses Kafka as the ingestion method, +you need to create an Event Stream configuration that points to a Kafka topic. \ +This can be done by adding a `https://w3id.org/ldes#KafkaEventStream` object to the Event Stream configuration. + +This object should contain the following properties: +* `ldes:topic` - The Kafka topic to which the members should be ingested. +* `ldes:mimeType` - The mime type in which the data of your topic will be. This is used to parse your member to a model. \ + This can be `application/ld+json`, `application/json`, `text/turtle`, ... \ + All members in your topic need to therefor be in one mime type. + +#### Example + +Creating a generic Event Stream named "event-stream" that uses Kafka as the ingestion method. + +````turtle +@prefix ldes: . +@prefix dcterms: . +@prefix prov: . +@prefix tree: . +@prefix sh: . +@prefix server: . +@prefix xsd: . +@prefix event-stream: . + +server:event-stream a ldes:EventStream ; + ldes:timestampPath dcterms:created ; + ldes:versionOfPath dcterms:isVersionOf ; + tree:shape [ a sh:NodeShape ] ; + ldes:kafkaSource [ + ldes:topic "testTopic" ; + ldes:mimeType "application/n-quads" ; + ] . + +```` \ No newline at end of file diff --git a/ldes-server-admin/ldes-server-admin-common/pom.xml b/ldes-server-admin/ldes-server-admin-common/pom.xml index a1d84bffb..d579b5247 100644 --- a/ldes-server-admin/ldes-server-admin-common/pom.xml +++ b/ldes-server-admin/ldes-server-admin-common/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-admin - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-admin-common diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceServiceImpl.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceServiceImpl.java index 7ab31b5bd..d41d5ce1a 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceServiceImpl.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceServiceImpl.java @@ -44,6 +44,6 @@ public void initViews() { repository .getAllEventSources() .forEach(eventSource -> eventPublisher - .publishEvent(new DeletionPolicyChangedEvent(eventSource.getCollectionName(), eventSource.getRetentionPolicies()))); + .publishEvent(new DeletionPolicyChangedEvent(eventSource.collectionName(), eventSource.retentionPolicies()))); } } diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/repository/EventStreamRepository.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/repository/EventStreamRepository.java index ef9f344e0..aa48159fa 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/repository/EventStreamRepository.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/repository/EventStreamRepository.java @@ -15,7 +15,7 @@ public interface EventStreamRepository { Optional retrieveEventStreamTO(String collectionName); - void saveEventStream(EventStreamTO eventStreamTO); + Integer saveEventStream(EventStreamTO eventStreamTO); int deleteEventStream(String collectionName); diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java index 6e2bc0896..9cf6cbd64 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java @@ -3,11 +3,13 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.dcat.dcatserver.services.DcatServerService; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventsource.services.EventSourceService; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.repository.EventStreamRepository; +import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.kafkasource.KafkaSourceRepository; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.view.service.ViewValidator; import be.vlaanderen.informatievlaanderen.ldes.server.admin.spi.EventStreamTO; import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.*; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; import org.apache.jena.rdf.model.Model; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationEventPublisher; @@ -15,20 +17,23 @@ import org.springframework.stereotype.Service; import java.util.List; +import java.util.Optional; @Service public class EventStreamServiceImpl implements EventStreamService { public static final String RESOURCE_TYPE = "eventstream"; private final EventStreamRepository eventStreamRepository; + private final KafkaSourceRepository kafkaSourceRepository; private final DcatServerService dcatServerService; private final EventSourceService eventSourceService; private final ApplicationEventPublisher eventPublisher; private final ViewValidator viewValidator; - public EventStreamServiceImpl(EventStreamRepository eventStreamRepository, + public EventStreamServiceImpl(EventStreamRepository eventStreamRepository, KafkaSourceRepository kafkaSourceRepository, DcatServerService dcatServerService, EventSourceService eventSourceService, ApplicationEventPublisher eventPublisher, ViewValidator viewValidator) { this.eventStreamRepository = eventStreamRepository; + this.kafkaSourceRepository = kafkaSourceRepository; this.dcatServerService = dcatServerService; this.eventSourceService = eventSourceService; this.eventPublisher = eventPublisher; @@ -60,8 +65,9 @@ public EventStreamTO createEventStream(EventStreamTO eventStreamTO) { checkCollectionDoesNotYetExist(eventStreamTO.getCollection()); eventStreamTO.getViews().forEach(viewValidator::validateView); - eventStreamRepository.saveEventStream(eventStreamTO); + var eventStreamId = eventStreamRepository.saveEventStream(eventStreamTO); publishEventStreamTOCreatedEvents(eventStreamTO); + publishKafkaSource(eventStreamTO.getKafkaSourceProperties(), eventStreamId); return eventStreamTO; } @@ -105,6 +111,9 @@ public void initEventStream() { eventStreamRepository.retrieveAllEventStreams().stream() .map(EventStreamCreatedEvent::new) .forEach(eventPublisher::publishEvent); + kafkaSourceRepository.getAll().stream() + .map(KafkaSourceAddedEvent::new) + .forEach(eventPublisher::publishEvent); } private void publishEventStreamTOCreatedEvents(EventStreamTO eventStreamTO) { @@ -113,4 +122,11 @@ private void publishEventStreamTOCreatedEvents(EventStreamTO eventStreamTO) { eventPublisher.publishEvent(new DeletionPolicyChangedEvent(eventStreamTO.getCollection(), eventStreamTO.getEventSourceRetentionPolicies())); } + private void publishKafkaSource(Optional kafkaSourceProperties, Integer eventStreamId) { + if (kafkaSourceProperties.isPresent()) { + kafkaSourceRepository.save(kafkaSourceProperties.get(), eventStreamId); + eventPublisher.publishEvent(new KafkaSourceAddedEvent(kafkaSourceProperties.get())); + } + } + } diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/kafkasource/KafkaSourceRepository.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/kafkasource/KafkaSourceRepository.java new file mode 100644 index 000000000..213d21deb --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/kafkasource/KafkaSourceRepository.java @@ -0,0 +1,10 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.kafkasource; + +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; + +import java.util.List; + +public interface KafkaSourceRepository { + void save(KafkaSourceProperties kafkaSource, Integer eventStreamId); + List getAll(); +} diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReader.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReader.java index ea35f30d2..372102b9d 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReader.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReader.java @@ -1,6 +1,7 @@ package be.vlaanderen.informatievlaanderen.ldes.server.admin.spi; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.exceptions.MissingStatementException; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; import org.apache.jena.rdf.model.*; import org.springframework.stereotype.Component; @@ -18,15 +19,20 @@ public class EventStreamReader { private final ViewSpecificationConverter viewSpecificationConverter; private final RetentionModelExtractor retentionModelExtractor; + private final KafkaSourceReader kafkaSourceReader; - public EventStreamReader(ViewSpecificationConverter viewSpecificationConverter, RetentionModelExtractor retentionModelExtractor) { + public EventStreamReader(ViewSpecificationConverter viewSpecificationConverter, RetentionModelExtractor retentionModelExtractor, KafkaSourceReader kafkaSourceReader) { this.viewSpecificationConverter = viewSpecificationConverter; this.retentionModelExtractor = retentionModelExtractor; + this.kafkaSourceReader = kafkaSourceReader; } public EventStreamTO read(Model model) { final String collection = getIdentifier(model, createResource(EVENT_STREAM_TYPE)).map(Resource::getLocalName) .orElseThrow(() -> new MissingStatementException("Not blank node with type " + EVENT_STREAM_TYPE)); + + final KafkaSourceProperties kafkaSourceProperties = kafkaSourceReader.readKafkaSourceProperties(collection, model); + return new EventStreamTO.Builder() .withCollection(collection) .withTimestampPath(getResource(model, LDES_TIMESTAMP_PATH).orElse(null)) @@ -36,6 +42,7 @@ public EventStreamTO read(Model model) { .withViews(getViews(model, collection)) .withShacl(getShaclFromModel(model)) .withEventSourceRetentionPolicies(getEventSourceRetentionPolicies(model)) + .withKafkaSourceProperties(kafkaSourceProperties) .build(); } diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamTO.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamTO.java index 739364a16..0aa8c3f0a 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamTO.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamTO.java @@ -3,6 +3,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.dcat.dcatdataset.entities.DcatDataset; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.exceptions.InvalidSkolemisationDomainException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.VersionCreationProperties; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; import org.apache.jena.rdf.model.Model; @@ -10,6 +11,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -18,6 +20,7 @@ public class EventStreamTO { private final String timestampPath; private final String versionOfPath; private final VersionCreationProperties versionCreationProperties; + private final Optional kafkaSourceProperties; private final boolean closed; private final String skolemizationDomain; private final List views; @@ -36,6 +39,7 @@ private EventStreamTO(Builder builder) { shacl = builder.shacl; eventSourceRetentionPolicies = builder.eventSourceRetentionPolicies; dcatDataset = builder.dcatDataset != null ? builder.dcatDataset : new DcatDataset(builder.collection); + kafkaSourceProperties = Optional.ofNullable(builder.kafkaSourceProperties); } public String getCollection() { @@ -58,6 +62,10 @@ public boolean isVersionCreationEnabled() { return versionCreationProperties.isVersionCreationEnabled(); } + public Optional getKafkaSourceProperties() { + return kafkaSourceProperties; + } + public boolean isClosed() { return closed; } @@ -114,6 +122,7 @@ public static final class Builder { private String timestampPath; private String versionOfPath; private VersionCreationProperties versionCreationProperties = VersionCreationProperties.disabled(); + private KafkaSourceProperties kafkaSourceProperties; private boolean closed = false; private String skolemizationDomain; private List views = List.of(); @@ -146,6 +155,11 @@ public Builder withVersionOfPath(String val) { return this; } + public Builder withKafkaSourceProperties(KafkaSourceProperties val) { + kafkaSourceProperties = val; + return this; + } + public Builder withVersionDelimiter(String val) { versionCreationProperties = VersionCreationProperties.ofNullableDelimiter(val); return this; diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/KafkaSourceReader.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/KafkaSourceReader.java new file mode 100644 index 000000000..e511ba6f2 --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/KafkaSourceReader.java @@ -0,0 +1,57 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.admin.spi; + +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; +import org.apache.jena.rdf.model.Model; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.stereotype.Component; + +import java.util.NoSuchElementException; + +import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.RdfConstants.LDES; +import static org.apache.jena.rdf.model.ResourceFactory.createProperty; + +@Component +public class KafkaSourceReader { + private static final String KAFKA_SOURCE = "kafkaSource"; + private static final String KAFKA_BEAN = "kafkaListenerContainerManager"; + private static final String KAFKA_TOPIC = "topic"; + private static final String KAFKA_MIME_TYPE = "mimeType"; + private final DefaultListableBeanFactory beanFactory; + + public KafkaSourceReader(DefaultListableBeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + public KafkaSourceProperties readKafkaSourceProperties(String collection, Model model) { + + var kafkaSourceStmts = model.listObjectsOfProperty(null, createProperty(LDES, KAFKA_SOURCE)); + if (!kafkaSourceStmts.hasNext()) { + return null; + } + + checkKafkaIngestModuleEnabled(); + + try { + var kafkaSource = kafkaSourceStmts.next(); + String topic = model.listObjectsOfProperty(kafkaSource.asResource(), createProperty(LDES, KAFKA_TOPIC)) + .next() + .asLiteral() + .getString(); + String mimeType = model.listObjectsOfProperty(kafkaSource.asResource(), createProperty(LDES, KAFKA_MIME_TYPE)) + .next() + .asLiteral() + .getString(); + + return new KafkaSourceProperties(collection, topic, mimeType); + } + catch (NoSuchElementException e) { + throw new IllegalArgumentException("KafkaSource properties are missing"); + } + } + + private void checkKafkaIngestModuleEnabled() { + if (!beanFactory.containsBean(KAFKA_BEAN)) { + throw new IllegalStateException("Kafka Ingest module is not enabled"); + } + } +} diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/module-info.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/module-info.java index 832f2ac6e..5a8da5214 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/module-info.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/module-info.java @@ -12,6 +12,7 @@ exports be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.exceptions; exports be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.repository; exports be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.services; + exports be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.kafkasource; exports be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.shacl.entities; exports be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.shacl.repository; exports be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.shacl.services; diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java index b86af5422..70680b417 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java @@ -5,6 +5,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.dcat.dcatserver.services.DcatServerService; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventsource.services.EventSourceService; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.repository.EventStreamRepository; +import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.kafkasource.KafkaSourceRepository; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.shacl.services.ShaclShapeService; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.view.exception.DuplicateRetentionException; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.view.service.ViewValidator; @@ -56,6 +57,8 @@ class EventStreamServiceImplTest { @Mock private EventStreamRepository eventStreamRepository; @Mock + private KafkaSourceRepository kafkaSourceRepository; + @Mock private ApplicationEventPublisher eventPublisher; @Captor ArgumentCaptor deletedEventArgumentCaptor; diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReaderTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReaderTest.java index 19b40e0de..3b3e0b3aa 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReaderTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReaderTest.java @@ -22,6 +22,7 @@ import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class EventStreamReaderTest { public static final String TIMESTAMP_PATH = "http://purl.org/dc/terms/created"; @@ -36,7 +37,8 @@ void setUp() { RetentionModelExtractor retentionModelExtractor = new RetentionModelExtractor(); ViewSpecificationConverter viewSpecificationConverter = new ViewSpecificationConverter(retentionModelExtractor, new FragmentationConfigExtractor(), prefixConstructor); - eventStreamReader = new EventStreamReader(viewSpecificationConverter, retentionModelExtractor); + KafkaSourceReader kafkaSourceReader = mock(KafkaSourceReader.class); + eventStreamReader = new EventStreamReader(viewSpecificationConverter, retentionModelExtractor, kafkaSourceReader); shacl = RDFDataMgr.loadModel("shacl/collection-shape.ttl"); } diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamTOTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamTOTest.java index 142d2ed73..44a8a482a 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamTOTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamTOTest.java @@ -4,6 +4,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.exceptions.InvalidSkolemisationDomainException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.RdfConstants; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; import org.apache.jena.rdf.model.ModelFactory; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtensionContext; @@ -19,6 +20,8 @@ import static org.apache.jena.rdf.model.ResourceFactory.createResource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; class EventStreamTOTest { private static final String COLLECTION = "collection"; @@ -65,6 +68,19 @@ void test_invalid_skolem_domain() { .hasMessage("Invalid Skolemisation Domain. Should be URI. Provided skolemizationDomain : example.com"); } + @Test + void test_kafka_props() { + var eventStreamTO = getBaseBuilder() + .withKafkaSourceProperties(new KafkaSourceProperties("collection", "topic", "mimeType")) + .build(); + + assertTrue(eventStreamTO.getKafkaSourceProperties().isPresent()); + var kafkaSourceProperties = eventStreamTO.getKafkaSourceProperties().get(); + assertEquals("collection", kafkaSourceProperties.collection()); + assertEquals("topic", kafkaSourceProperties.topic()); + assertEquals("mimeType", kafkaSourceProperties.mimeType()); + } + static class EventStreamResponseArgumentsProvider implements ArgumentsProvider { @Override diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/KafkaSourceReaderTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/KafkaSourceReaderTest.java new file mode 100644 index 000000000..718803608 --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/KafkaSourceReaderTest.java @@ -0,0 +1,57 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.admin.spi; + +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.riot.RDFDataMgr; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; + +import static org.junit.jupiter.api.Assertions.*; + +class KafkaSourceReaderTest { + + private KafkaSourceReader kafkaSourceReader; + private DefaultListableBeanFactory beanFactory; + + @BeforeEach + void setup() { + beanFactory = new DefaultListableBeanFactory(); + kafkaSourceReader = new KafkaSourceReader(beanFactory); + } + + @Test + void readKafkaSourceProperties_NoKafkaSourcePresent() { + KafkaSourceProperties kafkaSourceProperties = kafkaSourceReader.readKafkaSourceProperties("collection", ModelFactory.createDefaultModel()); + assertNull(kafkaSourceProperties); + } + + @Test + void readKafkaSourceProperties_KafkaIngestNotEnabled() { + final Model eventStreamModel = RDFDataMgr.loadModel("eventstream/streams/with-kafka-source/ldes-with-kafkaES.ttl"); + assertThrows(IllegalStateException.class, ()-> kafkaSourceReader.readKafkaSourceProperties("collection", eventStreamModel)); + } + + @Test + void readKafkaSourceProperties_KafkaIngestEnabled() { + beanFactory.registerSingleton("kafkaListenerContainerManager", Object.class); + final Model eventStreamModel = RDFDataMgr.loadModel("eventstream/streams/with-kafka-source/ldes-with-kafkaES.ttl"); + KafkaSourceProperties kafkaSourceProperties = kafkaSourceReader.readKafkaSourceProperties("collection", eventStreamModel); + assertNotNull(kafkaSourceProperties); + assertEquals("testTopic", kafkaSourceProperties.topic()); + assertEquals("application/n-quads", kafkaSourceProperties.mimeType()); + assertEquals("collection", kafkaSourceProperties.collection()); + } + + @ParameterizedTest() + @ValueSource(strings = {"ldes-with-kafkaES-noTopic.ttl", "ldes-with-kafkaES-noMime.ttl"}) + void readKafkaSourceProperties_PropertyMissing(String fileName) { + beanFactory.registerSingleton("kafkaListenerContainerManager", Object.class); + final Model eventStreamModel = RDFDataMgr.loadModel("eventstream/streams/with-kafka-source/" + fileName); + assertThrows(IllegalArgumentException.class, ()-> kafkaSourceReader.readKafkaSourceProperties("collection", eventStreamModel)); + } + +} \ No newline at end of file diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES-noMime.ttl b/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES-noMime.ttl new file mode 100644 index 000000000..652fee544 --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES-noMime.ttl @@ -0,0 +1,8 @@ +@prefix ns0: . +@prefix dc: . + + + a ; + ns0:timestampPath dc:created ; + ns0:versionOfPath dc:isVersionOf ; + ns0:kafkaSource [ ns0:topic "testTopic" ] . \ No newline at end of file diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES-noTopic.ttl b/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES-noTopic.ttl new file mode 100644 index 000000000..0d6155e7c --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES-noTopic.ttl @@ -0,0 +1,8 @@ +@prefix ns0: . +@prefix dc: . + + + a ; + ns0:timestampPath dc:created ; + ns0:versionOfPath dc:isVersionOf ; + ns0:kafkaSource [ ns0:mimeType "application/n-quads" ] . \ No newline at end of file diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES.ttl b/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES.ttl new file mode 100644 index 000000000..6939939f6 --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-common/src/test/resources/eventstream/streams/with-kafka-source/ldes-with-kafkaES.ttl @@ -0,0 +1,9 @@ +@prefix ns0: . +@prefix dc: . + + + a ; + ns0:timestampPath dc:created ; + ns0:versionOfPath dc:isVersionOf ; + ns0:kafkaSource [ ns0:topic "testTopic" ; + ns0:mimeType "application/n-quads" ] . \ No newline at end of file diff --git a/ldes-server-admin/ldes-server-admin-rest/pom.xml b/ldes-server-admin/ldes-server-admin-rest/pom.xml index 8929f5575..fbea691f5 100644 --- a/ldes-server-admin/ldes-server-admin-rest/pom.xml +++ b/ldes-server-admin/ldes-server-admin-rest/pom.xml @@ -5,7 +5,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-admin - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/config/SpringIntegrationTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/config/SpringIntegrationTest.java index f773dee87..c4a75dedf 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/config/SpringIntegrationTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/config/SpringIntegrationTest.java @@ -5,6 +5,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventsource.repository.EventSourceRepository; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventsource.services.EventSourceServiceImpl; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream.repository.EventStreamRepository; +import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.kafkasource.KafkaSourceRepository; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.shacl.repository.ShaclShapeRepository; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.view.repository.DcatViewRepository; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.view.repository.ViewRepository; @@ -76,6 +77,9 @@ public class SpringIntegrationTest { @MockBean protected ShaclShapeRepository shaclShapeRepository; + @MockBean + protected KafkaSourceRepository kafkaSourceRepository; + @Autowired protected ApplicationEventPublisher eventPublisher; diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java index 68bd4356b..61f532d08 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java @@ -59,7 +59,7 @@ @ActiveProfiles({"test", "rest"}) @ContextConfiguration(classes = {AdminEventStreamsRestController.class, HttpModelConverter.class, EventStreamListHttpConverter.class, EventStreamHttpConverter.class, - EventStreamWriter.class, EventStreamReader.class, + EventStreamWriter.class, EventStreamReader.class, KafkaSourceReader.class, ViewSpecificationConverter.class, PrefixAdderImpl.class, ValidatorsConfig.class, AdminRestResponseEntityExceptionHandler.class, RetentionModelExtractor.class, CharsetEncodingConfig.class, FragmentationConfigExtractor.class, PrefixConstructor.class, RdfModelConverter.class, AdminVersionHeaderControllerAdvice.class}) diff --git a/ldes-server-admin/pom.xml b/ldes-server-admin/pom.xml index b6ac09590..ad947b9d7 100644 --- a/ldes-server-admin/pom.xml +++ b/ldes-server-admin/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT pom diff --git a/ldes-server-application/pom.xml b/ldes-server-application/pom.xml index 0b72dc1d2..8fcbaccce 100644 --- a/ldes-server-application/pom.xml +++ b/ldes-server-application/pom.xml @@ -5,7 +5,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-application @@ -125,6 +125,21 @@ + + kafka-ingest + + + be.vlaanderen.informatievlaanderen.vsds + ldes-server-ingest-kafka + ${project.version} + + + be.vlaanderen.informatievlaanderen.vsds + postgres-ingest-repository + ${project.version} + + + http-fetch diff --git a/ldes-server-application/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/OpenApiConfig.java b/ldes-server-application/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/OpenApiConfig.java index 42ace0fec..e1fa690c8 100644 --- a/ldes-server-application/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/OpenApiConfig.java +++ b/ldes-server-application/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/OpenApiConfig.java @@ -2,38 +2,50 @@ import io.swagger.v3.oas.models.info.Info; import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.boot.info.BuildProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class OpenApiConfig { - private static final String VERSION = "3.1.0"; - + private static final String ADMIN_PACKAGE = "be.vlaanderen.informatievlaanderen.ldes.server.admin.rest"; + private static final String KAFKA_DEBUG_PACKAGE = "be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka"; @Bean - public GroupedOpenApi adminGroup() { - String[] packages = {"be.vlaanderen.informatievlaanderen.ldes.server.admin.rest"}; + public GroupedOpenApi adminGroup(BuildProperties buildProperties) { return GroupedOpenApi.builder() .group("admin") .addOpenApiCustomizer(openApi -> openApi.info(new Info() .title("LDES Server Admin API") - .version(VERSION) + .version(buildProperties.getVersion()) .description("This API makes it possible to manage an LDES Server") )) - .packagesToScan(packages) + .packagesToScan(ADMIN_PACKAGE) + .build(); + } + + @Bean + public GroupedOpenApi kafkaDebugGroup(BuildProperties buildProperties) { + return GroupedOpenApi.builder() + .group("kafka-debug") + .addOpenApiCustomizer(openApi -> openApi.info(new Info() + .title("LDES Server Kafka Debug API") + .version(buildProperties.getVersion()) + .description("Purely meant as a developer debugging tool") + )) + .packagesToScan(KAFKA_DEBUG_PACKAGE) .build(); } @Bean - public GroupedOpenApi defaultGroup() { - String[] packages = {"be.vlaanderen.informatievlaanderen.ldes.server.admin.rest"}; + public GroupedOpenApi defaultGroup(BuildProperties buildProperties) { return GroupedOpenApi.builder() .group("base") .addOpenApiCustomizer(openApi -> openApi.info(new Info() .title("Ingest and Fetch endpoints") - .version(VERSION) + .version(buildProperties.getVersion()) .description("These API endpoints are available to ingest and fetch linked data") )) - .packagesToExclude(packages) + .packagesToExclude(ADMIN_PACKAGE, KAFKA_DEBUG_PACKAGE) .build(); } } diff --git a/ldes-server-domain/pom.xml b/ldes-server-domain/pom.xml index f2ca7aa03..954451851 100644 --- a/ldes-server-domain/pom.xml +++ b/ldes-server-domain/pom.xml @@ -5,7 +5,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-domain diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/events/admin/KafkaSourceAddedEvent.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/events/admin/KafkaSourceAddedEvent.java new file mode 100644 index 000000000..13ba088f3 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/events/admin/KafkaSourceAddedEvent.java @@ -0,0 +1,6 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin; + +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; + +public record KafkaSourceAddedEvent(KafkaSourceProperties kafkaSource) { +} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/model/EventSource.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/model/EventSource.java index ca0cd91c6..4a0ceb315 100644 --- a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/model/EventSource.java +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/model/EventSource.java @@ -5,22 +5,7 @@ import java.util.List; import java.util.Objects; -public class EventSource { - private final String collectionName; - private final List retentionPolicies; - - public EventSource(String collectionName, List retentionPolicies) { - this.collectionName = collectionName; - this.retentionPolicies = retentionPolicies; - } - - public String getCollectionName() { - return collectionName; - } - - public List getRetentionPolicies() { - return retentionPolicies; - } +public record EventSource(String collectionName, List retentionPolicies) { @Override public boolean equals(Object o) { @@ -29,7 +14,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; EventSource eventSource = (EventSource) o; - return collectionName.equals(eventSource.getCollectionName()); + return collectionName.equals(eventSource.collectionName()); } @Override diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/model/KafkaSourceProperties.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/model/KafkaSourceProperties.java new file mode 100644 index 000000000..81cb50cd9 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/model/KafkaSourceProperties.java @@ -0,0 +1,4 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.model; + +public record KafkaSourceProperties (String collection, String topic, String mimeType) { +} diff --git a/ldes-server-fetch/ldes-server-fetch-common/pom.xml b/ldes-server-fetch/ldes-server-fetch-common/pom.xml index 99b82fb99..5562679dd 100644 --- a/ldes-server-fetch/ldes-server-fetch-common/pom.xml +++ b/ldes-server-fetch/ldes-server-fetch-common/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-fetch - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-fetch-common diff --git a/ldes-server-fetch/ldes-server-fetch-rest/pom.xml b/ldes-server-fetch/ldes-server-fetch-rest/pom.xml index 518b0f521..97350ec92 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/pom.xml +++ b/ldes-server-fetch/ldes-server-fetch-rest/pom.xml @@ -5,7 +5,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-fetch - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-fetch-rest diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java index 99a86d731..4f1e83922 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java @@ -63,7 +63,7 @@ @ActiveProfiles({"test", "rest"}) @Import({EventStreamControllerTest.EventStreamControllerTestConfiguration.class}) @ContextConfiguration(classes = {EventStreamController.class, RestConfig.class, - RestResponseEntityExceptionHandler.class, EventStreamWriter.class, EventStreamReader.class, + RestResponseEntityExceptionHandler.class, EventStreamWriter.class, EventStreamReader.class, KafkaSourceReader.class, ViewSpecificationConverter.class, PrefixAdderImpl.class, EventStreamResponseHttpConverter.class, RetentionModelExtractor.class, HttpModelConverter.class, FragmentationConfigExtractor.class, PrefixConstructor.class, RdfModelConverter.class, VersionHeaderControllerAdvice.class diff --git a/ldes-server-fetch/pom.xml b/ldes-server-fetch/pom.xml index 850d69f57..f58a4b0de 100644 --- a/ldes-server-fetch/pom.xml +++ b/ldes-server-fetch/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT pom ldes-server-fetch diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/pom.xml b/ldes-server-fragmentation/ldes-server-fragmentation-common/pom.xml index a926b66d4..bccd16d10 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/pom.xml +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/pom.xml @@ -5,7 +5,7 @@ ldes-server-fragmentation be.vlaanderen.informatievlaanderen.vsds - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT 4.0.0 diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-geospatial/pom.xml b/ldes-server-fragmentation/ldes-server-fragmentation-geospatial/pom.xml index 1d2506e79..4ca2f0d30 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-geospatial/pom.xml +++ b/ldes-server-fragmentation/ldes-server-fragmentation-geospatial/pom.xml @@ -3,7 +3,7 @@ ldes-server-fragmentation be.vlaanderen.informatievlaanderen.vsds - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT 4.0.0 diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-reference/pom.xml b/ldes-server-fragmentation/ldes-server-fragmentation-reference/pom.xml index 419863959..83509025a 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-reference/pom.xml +++ b/ldes-server-fragmentation/ldes-server-fragmentation-reference/pom.xml @@ -5,7 +5,7 @@ ldes-server-fragmentation be.vlaanderen.informatievlaanderen.vsds - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT 4.0.0 jar diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/pom.xml b/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/pom.xml index 5b5e65c6e..21dc3cd05 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/pom.xml +++ b/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-fragmentation - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-fragmentation-timebased-hierarchical diff --git a/ldes-server-fragmentation/ldes-server-pagination/pom.xml b/ldes-server-fragmentation/ldes-server-pagination/pom.xml index 43f1b4533..1a988d21c 100644 --- a/ldes-server-fragmentation/ldes-server-pagination/pom.xml +++ b/ldes-server-fragmentation/ldes-server-pagination/pom.xml @@ -6,7 +6,7 @@ ldes-server-fragmentation be.vlaanderen.informatievlaanderen.vsds - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-pagination diff --git a/ldes-server-fragmentation/pom.xml b/ldes-server-fragmentation/pom.xml index a4a7a0dd3..d3937ff53 100644 --- a/ldes-server-fragmentation/pom.xml +++ b/ldes-server-fragmentation/pom.xml @@ -5,7 +5,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-fragmentation diff --git a/ldes-server-infra-postgres/pom.xml b/ldes-server-infra-postgres/pom.xml index 02bd3a538..cb0cf250e 100644 --- a/ldes-server-infra-postgres/pom.xml +++ b/ldes-server-infra-postgres/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT pom diff --git a/ldes-server-infra-postgres/postgres-admin-repository/pom.xml b/ldes-server-infra-postgres/postgres-admin-repository/pom.xml index cab76b36b..69714d21c 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/pom.xml +++ b/ldes-server-infra-postgres/postgres-admin-repository/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-infra-postgres - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT postgres-admin-repository diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventsource/EventSourcePostgresRepository.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventsource/EventSourcePostgresRepository.java index e429b519f..e1b945875 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventsource/EventSourcePostgresRepository.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventsource/EventSourcePostgresRepository.java @@ -23,10 +23,10 @@ public EventSourcePostgresRepository(EventSourceEntityRepository eventSourceEnti @Override public void saveEventSource(EventSource eventSource) { - eventSourceEntityRepository.findByCollectionName(eventSource.getCollectionName()) - .or(() -> eventStreamEntityRepository.findByName(eventSource.getCollectionName()).map(EventSourceEntity::new)) + eventSourceEntityRepository.findByCollectionName(eventSource.collectionName()) + .or(() -> eventStreamEntityRepository.findByName(eventSource.collectionName()).map(EventSourceEntity::new)) .ifPresent(eventSourceEntity -> { - eventSourceEntity.setRetentionPolicies(eventSource.getRetentionPolicies()); + eventSourceEntity.setRetentionPolicies(eventSource.retentionPolicies()); eventSourceEntityRepository.save(eventSourceEntity); }); } diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/EventStreamPostgresRepository.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/EventStreamPostgresRepository.java index 44b610f5f..4b60dcb99 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/EventStreamPostgresRepository.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/EventStreamPostgresRepository.java @@ -47,8 +47,9 @@ public Optional retrieveEventStreamTO(String collectionName) { @Override @Transactional - public void saveEventStream(EventStreamTO eventStreamTO) { - repository.save(EventStreamMapper.toEntity(eventStreamTO)); + public Integer saveEventStream(EventStreamTO eventStreamTO) { + var es = repository.save(EventStreamMapper.toEntity(eventStreamTO)); + return es.getId(); } @Override diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/entity/EventStreamEntity.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/entity/EventStreamEntity.java index a6c8cb6da..e9c8f2cc1 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/entity/EventStreamEntity.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/entity/EventStreamEntity.java @@ -115,4 +115,8 @@ public void setShaclShapeEntity(ShaclShapeEntity shaclShapeEntity) { public void setEventSourceEntity(EventSourceEntity eventSourceEntity) { this.eventSourceEntity = eventSourceEntity; } + + public void setId(Integer id) { + this.id = id; + } } diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/KafkaSourcePostgresRepository.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/KafkaSourcePostgresRepository.java new file mode 100644 index 000000000..01622a36f --- /dev/null +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/KafkaSourcePostgresRepository.java @@ -0,0 +1,33 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.admin.postgres.kafkasource; + +import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.kafkasource.KafkaSourceRepository; +import be.vlaanderen.informatievlaanderen.ldes.server.admin.postgres.kafkasource.entity.KafkaSourceEntity; +import be.vlaanderen.informatievlaanderen.ldes.server.admin.postgres.kafkasource.repository.KafkaSourceEntityRepository; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.KafkaSourceProperties; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class KafkaSourcePostgresRepository implements KafkaSourceRepository { + private final KafkaSourceEntityRepository repository; + + public KafkaSourcePostgresRepository(KafkaSourceEntityRepository repository) { + this.repository = repository; + } + + @Override + public void save(KafkaSourceProperties kafkaSource, Integer eventStreamId) { + repository.save(new KafkaSourceEntity(eventStreamId, kafkaSource.collection(), kafkaSource.topic(), kafkaSource.mimeType())); + } + + @Override + public List getAll() { + return repository.findAll().stream() + .map(kafkaSourceEntity -> + new KafkaSourceProperties(kafkaSourceEntity.getCollection(), + kafkaSourceEntity.getTopic(), + kafkaSourceEntity.getMimeType())) + .toList(); + } +} diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/entity/KafkaSourceEntity.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/entity/KafkaSourceEntity.java new file mode 100644 index 000000000..f44f2dbaa --- /dev/null +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/entity/KafkaSourceEntity.java @@ -0,0 +1,42 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.admin.postgres.kafkasource.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "collection_kafka_sources") +public class KafkaSourceEntity { + @Id + @Column(name = "collection_id") + private Integer collectionId; + @Column(name = "collection") + private String collection; + @Column(name = "topic") + private String topic; + @Column(name = "mime_type") + private String mimeType; + + public KafkaSourceEntity() { + } + + public KafkaSourceEntity(Integer collectionId, String collection, String topic, String mimeType) { + this.collectionId = collectionId; + this.collection = collection; + this.topic = topic; + this.mimeType = mimeType; + } + + public String getCollection() { + return collection; + } + + public String getTopic() { + return topic; + } + + public String getMimeType() { + return mimeType; + } +} diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/repository/KafkaSourceEntityRepository.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/repository/KafkaSourceEntityRepository.java new file mode 100644 index 000000000..d6b0b0815 --- /dev/null +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/repository/KafkaSourceEntityRepository.java @@ -0,0 +1,10 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.admin.postgres.kafkasource.repository; + +import be.vlaanderen.informatievlaanderen.ldes.server.admin.postgres.kafkasource.entity.KafkaSourceEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface KafkaSourceEntityRepository extends JpaRepository { + +} diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventsource/EventSourcePostgresRepositoryTest.java b/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventsource/EventSourcePostgresRepositoryTest.java index b24e5428b..2684c4f5f 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventsource/EventSourcePostgresRepositoryTest.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventsource/EventSourcePostgresRepositoryTest.java @@ -68,7 +68,7 @@ void given_MultipleEventSources_when_GetAllEventSources_then_ReturnList() { final var result = eventSourcePostgresRepository.getAllEventSources(); assertThat(result) - .map(EventSource::getCollectionName) + .map(EventSource::collectionName) .containsExactlyInAnyOrder(COLLECTION_NAME, otherCollectionName); } diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/EventStreamPostgresRepositoryTest.java b/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/EventStreamPostgresRepositoryTest.java index a5d40906f..b3c1127aa 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/EventStreamPostgresRepositoryTest.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/eventstream/EventStreamPostgresRepositoryTest.java @@ -23,6 +23,7 @@ import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.assertArg; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -179,6 +180,7 @@ void when_emptyDbQueried_then_returnEmptyOptional() { @Test void test_insertion() { final EventStreamEntity expectedEntity = createEventStreamEntity(COLLECTION_NAME); + when(eventStreamEntityRepository.save(any())).thenReturn(expectedEntity); repository.saveEventStream(EVENT_STREAM_TO); @@ -204,6 +206,7 @@ private static EventStreamEntity createEventStreamEntity(String collection) { false, SKOLEMIZATION_DOMAIN ); + eventStreamEntity.setId(1); eventStreamEntity.setShaclShapeEntity(new ShaclShapeEntity(eventStreamEntity, ModelFactory.createDefaultModel())); eventStreamEntity.setViews(List.of()); eventStreamEntity.setEventSourceEntity(new EventSourceEntity(eventStreamEntity, List.of())); diff --git a/ldes-server-infra-postgres/postgres-fetch-repository/pom.xml b/ldes-server-infra-postgres/postgres-fetch-repository/pom.xml index 5e5b85d10..f7ce9c3eb 100644 --- a/ldes-server-infra-postgres/postgres-fetch-repository/pom.xml +++ b/ldes-server-infra-postgres/postgres-fetch-repository/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-infra-postgres - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT postgres-fetch-repository @@ -20,7 +20,7 @@ be.vlaanderen.informatievlaanderen.vsds postgres-admin-repository - 3.5.1-SNAPSHOT + ${project.version} compile diff --git a/ldes-server-infra-postgres/postgres-fragmentation-repository/pom.xml b/ldes-server-infra-postgres/postgres-fragmentation-repository/pom.xml index 5103afc4f..4d37d69d7 100644 --- a/ldes-server-infra-postgres/postgres-fragmentation-repository/pom.xml +++ b/ldes-server-infra-postgres/postgres-fragmentation-repository/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-infra-postgres - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT postgres-fragmentation-repository diff --git a/ldes-server-infra-postgres/postgres-ingest-repository/pom.xml b/ldes-server-infra-postgres/postgres-ingest-repository/pom.xml index 383ab1b29..f060934c2 100644 --- a/ldes-server-infra-postgres/postgres-ingest-repository/pom.xml +++ b/ldes-server-infra-postgres/postgres-ingest-repository/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-infra-postgres - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT postgres-ingest-repository diff --git a/ldes-server-infra-postgres/postgres-liquibase/pom.xml b/ldes-server-infra-postgres/postgres-liquibase/pom.xml index 7cc5be1a2..7f9c8544a 100644 --- a/ldes-server-infra-postgres/postgres-liquibase/pom.xml +++ b/ldes-server-infra-postgres/postgres-liquibase/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-infra-postgres - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT postgres-liquibase diff --git a/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/3_6_0/init-collection_kafka_sources.xml b/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/3_6_0/init-collection_kafka_sources.xml new file mode 100644 index 000000000..24da24e44 --- /dev/null +++ b/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/3_6_0/init-collection_kafka_sources.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/3_6_0/master.xml b/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/3_6_0/master.xml new file mode 100644 index 000000000..e460f8ee1 --- /dev/null +++ b/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/3_6_0/master.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/master.xml b/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/master.xml index 2d30cd23f..a46826b4d 100644 --- a/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/master.xml +++ b/ldes-server-infra-postgres/postgres-liquibase/src/main/resources/db/changelog/master.xml @@ -11,5 +11,6 @@ + \ No newline at end of file diff --git a/ldes-server-infra-postgres/postgres-maintenance-repository/pom.xml b/ldes-server-infra-postgres/postgres-maintenance-repository/pom.xml index ba68aae4a..2febcae19 100644 --- a/ldes-server-infra-postgres/postgres-maintenance-repository/pom.xml +++ b/ldes-server-infra-postgres/postgres-maintenance-repository/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-infra-postgres - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT postgres-maintenance-repository diff --git a/ldes-server-infra-postgres/postgres-pagination-repository/pom.xml b/ldes-server-infra-postgres/postgres-pagination-repository/pom.xml index ad4f7219b..0da9b5435 100644 --- a/ldes-server-infra-postgres/postgres-pagination-repository/pom.xml +++ b/ldes-server-infra-postgres/postgres-pagination-repository/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-infra-postgres - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT postgres-pagination-repository diff --git a/ldes-server-ingest/ldes-server-ingest-common/pom.xml b/ldes-server-ingest/ldes-server-ingest-common/pom.xml index cef44080b..fe859def3 100644 --- a/ldes-server-ingest/ldes-server-ingest-common/pom.xml +++ b/ldes-server-ingest/ldes-server-ingest-common/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-ingest - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-ingest-common diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/IngestValidator.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/IngestValidator.java similarity index 62% rename from ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/IngestValidator.java rename to ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/IngestValidator.java index 7284f1d44..3250cd271 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/IngestValidator.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/IngestValidator.java @@ -1,4 +1,4 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators; +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators; import org.apache.jena.rdf.model.Model; diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/BlankNodesValidator.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/BlankNodesValidator.java similarity index 96% rename from ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/BlankNodesValidator.java rename to ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/BlankNodesValidator.java index 5c5b7569a..9adcbaed8 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/BlankNodesValidator.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/BlankNodesValidator.java @@ -1,4 +1,4 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator; +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import org.apache.jena.rdf.model.Model; diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/IngestReportValidator.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/IngestReportValidator.java similarity index 73% rename from ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/IngestReportValidator.java rename to ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/IngestReportValidator.java index c1ea43f9a..bce036caa 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/IngestReportValidator.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/IngestReportValidator.java @@ -1,4 +1,4 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator; +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import org.apache.jena.rdf.model.Model; diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/PathsValidator.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java similarity index 97% rename from ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/PathsValidator.java rename to ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java index 5c47edfbf..981301b9d 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/PathsValidator.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java @@ -1,4 +1,4 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator; +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import org.apache.jena.datatypes.RDFDatatype; diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/ShaclReportManager.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/ShaclReportManager.java similarity index 93% rename from ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/ShaclReportManager.java rename to ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/ShaclReportManager.java index 7b93d5059..b10afb748 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/ingestreportvalidator/ShaclReportManager.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/ShaclReportManager.java @@ -1,4 +1,4 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator; +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator; import org.apache.jena.graph.NodeFactory; import org.apache.jena.rdf.model.Resource; diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidator.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/memberingestvalidator/MemberIngestValidator.java similarity index 88% rename from ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidator.java rename to ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/memberingestvalidator/MemberIngestValidator.java index 4e9d98c73..e4246cc4f 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidator.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/memberingestvalidator/MemberIngestValidator.java @@ -1,4 +1,4 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.memberingestvalidator; +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.memberingestvalidator; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.RdfModelConverter; import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.EventStreamClosedEvent; @@ -6,9 +6,9 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.EventStreamDeletedEvent; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.ShaclValidationException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.IngestValidator; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator.IngestReportValidator; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator.ShaclReportManager; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.IngestValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator.IngestReportValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator.ShaclReportManager; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.Lang; import org.apache.jena.shacl.ValidationReport; diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/pom.xml b/ldes-server-ingest/ldes-server-ingest-kafka/pom.xml new file mode 100644 index 000000000..1babd7653 --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + be.vlaanderen.informatievlaanderen.vsds + ldes-server-ingest + 3.6.0-SNAPSHOT + + + ldes-server-ingest-kafka + + + + be.vlaanderen.informatievlaanderen.vsds + ldes-server-ingest-common + ${project.version} + + + org.springframework.kafka + spring-kafka + ${spring.kafka.version} + + + + + org.junit.jupiter + junit-jupiter + test + + + + + ${project.artifactId} + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + \ No newline at end of file diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/KafkaListenerContainerManager.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/KafkaListenerContainerManager.java new file mode 100644 index 000000000..d4948eca4 --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/KafkaListenerContainerManager.java @@ -0,0 +1,89 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka; + +import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.EventStreamDeletedEvent; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.KafkaSourceAddedEvent; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.MemberIngester; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.listener.IngestListener; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.IngestValidator; +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.RDFLanguages; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.springframework.boot.autoconfigure.kafka.KafkaProperties; +import org.springframework.context.event.EventListener; +import org.springframework.kafka.config.KafkaListenerContainerFactory; +import org.springframework.kafka.config.KafkaListenerEndpoint; +import org.springframework.kafka.config.KafkaListenerEndpointRegistry; +import org.springframework.kafka.config.MethodKafkaListenerEndpoint; +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.kafka.support.Acknowledgment; +import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; + +@Component +public class KafkaListenerContainerManager { + private final KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry; + private final KafkaListenerContainerFactory> kafkaListenerContainerFactory; + private final KafkaProperties kafkaProperties; + private final IngestValidator ingestValidator; + private final MemberIngester memberIngester; + + public KafkaListenerContainerManager(KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry, + KafkaListenerContainerFactory> kafkaListenerContainerFactory, + KafkaProperties kafkaProperties, IngestValidator ingestValidator, + MemberIngester memberIngester) { + this.kafkaListenerEndpointRegistry = kafkaListenerEndpointRegistry; + this.kafkaListenerContainerFactory = kafkaListenerContainerFactory; + this.kafkaProperties = kafkaProperties; + this.ingestValidator = ingestValidator; + this.memberIngester = memberIngester; + } + + public void registerListener(String listenerId, String collection, String topic, String mimeType) throws NoSuchMethodException { + kafkaListenerEndpointRegistry.registerListenerContainer( + createKafkaListenerEndpoint(listenerId, collection, topic, mimeType), kafkaListenerContainerFactory, true + ); + } + + public Collection listContainers() { + return kafkaListenerEndpointRegistry.getListenerContainers(); + } + + public Optional getContainer(String listenerId) { + return Optional.ofNullable(kafkaListenerEndpointRegistry.getListenerContainer(listenerId)); + } + + public void unregisterListener(String listenerId) { + kafkaListenerEndpointRegistry.unregisterListenerContainer(listenerId); + } + + @EventListener(KafkaSourceAddedEvent.class) + public void onKafkaSourceAdded(KafkaSourceAddedEvent event) throws NoSuchMethodException { + registerListener(UUID.randomUUID().toString(), event.kafkaSource().collection(), event.kafkaSource().topic(), event.kafkaSource().mimeType()); + } + + @EventListener(EventStreamDeletedEvent.class) + public void onEventStreamDeleted(EventStreamDeletedEvent event) { + unregisterListener(event.collectionName()); + } + + private KafkaListenerEndpoint createKafkaListenerEndpoint(String listenerId, String collection, String topic, String mimeType) throws NoSuchMethodException { + MethodKafkaListenerEndpoint kafkaListenerEndpoint = new MethodKafkaListenerEndpoint<>(); + kafkaListenerEndpoint.setId(listenerId); + kafkaListenerEndpoint.setGroupId(kafkaProperties.getConsumer().getGroupId()); + kafkaListenerEndpoint.setAutoStartup(true); + kafkaListenerEndpoint.setTopics(topic); + kafkaListenerEndpoint.setMessageHandlerMethodFactory(new DefaultMessageHandlerMethodFactory()); + + Lang lang = RDFLanguages.contentTypeToLang(mimeType); + + kafkaListenerEndpoint.setBean(new IngestListener(collection, lang, ingestValidator, memberIngester)); + + kafkaListenerEndpoint.setMethod(IngestListener.class.getMethod("onMessage", ConsumerRecord.class, Acknowledgment.class)); + return kafkaListenerEndpoint; + } +} diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/config/KafkaConfig.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/config/KafkaConfig.java new file mode 100644 index 000000000..11edc2fd7 --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/config/KafkaConfig.java @@ -0,0 +1,21 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.listener.ContainerProperties; + +@Configuration +public class KafkaConfig { + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory( + ConsumerFactory consumerFactory) { + ConcurrentKafkaListenerContainerFactory factory = + new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory); + factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL); + return factory; + } +} \ No newline at end of file diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerController.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerController.java new file mode 100644 index 000000000..8fa17dbdc --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerController.java @@ -0,0 +1,127 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.controller; + +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.KafkaListenerContainerManager; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.exception.KafkaConsumerException; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerAssignment; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerRequest; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerResponse; +import org.apache.kafka.common.TopicPartition; +import org.springframework.kafka.listener.MessageListenerContainer; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@RestController +@RequestMapping(path = "/consumers") +public class KafkaConsumerController { + private final KafkaListenerContainerManager kafkaListenerContainerManager; + + public KafkaConsumerController(KafkaListenerContainerManager kafkaListenerContainerManager) { + this.kafkaListenerContainerManager = kafkaListenerContainerManager; + } + + @PostMapping + public void create(@RequestBody KafkaConsumerRequest req) throws NoSuchMethodException { + kafkaListenerContainerManager.registerListener( + UUID.randomUUID().toString(), + req.collection(), + req.topic(), + req.mimeType() + ); + } + + @GetMapping + public List list() { + return kafkaListenerContainerManager.listContainers() + .stream() + .map(this::createKafkaConsumerResponse) + .toList(); + } + + @GetMapping(path="/{listenerId}") + public KafkaConsumerResponse get(@PathVariable String listenerId) { + return createKafkaConsumerResponse(getListenerContainer(listenerId)); + } + + @PutMapping(path = "/{listenerId}/activate") + public void activate(@PathVariable String listenerId) { + MessageListenerContainer listenerContainer = getListenerContainer(listenerId); + + if (listenerContainer.isRunning()) { + throw new KafkaConsumerException("Consumer is already running : " + listenerId); + } + + listenerContainer.start(); + } + + @PutMapping(path = "/{listenerId}/pause") + public void pause(@PathVariable String listenerId) { + MessageListenerContainer listenerContainer = getListenerContainer(listenerId); + if (!listenerContainer.isRunning()) { + throw new KafkaConsumerException("Consumer is not running: " + listenerId); + } else if (listenerContainer.isContainerPaused()) { + throw new KafkaConsumerException("Consumer is already paused: " + listenerId); + } else if (listenerContainer.isPauseRequested()) { + throw new KafkaConsumerException("Consumer pause is already requested: " + listenerId); + } + listenerContainer.pause(); + } + + @PutMapping(path = "/{listenerId}/resume") + public void resume(@PathVariable String listenerId) { + MessageListenerContainer listenerContainer = getListenerContainer(listenerId); + if (!listenerContainer.isRunning()) { + throw new KafkaConsumerException("Consumer is not running: " + listenerId); + } else if (!listenerContainer.isContainerPaused()) { + throw new KafkaConsumerException("Consumer is not paused: " + listenerId); + } + listenerContainer.resume(); + } + + @PutMapping(path = "/{listenerId}/stop") + public void stop(@PathVariable String listenerId) { + MessageListenerContainer listenerContainer = getListenerContainer(listenerId); + if (!listenerContainer.isRunning()) { + throw new KafkaConsumerException("Consumer is already stopped: " + listenerId); + } + listenerContainer.stop(); + } + + @DeleteMapping(path = "{listenerId}") + public void delete(@PathVariable String listenerId) { + MessageListenerContainer listenerContainer = getListenerContainer(listenerId); + listenerContainer.stop(); + kafkaListenerContainerManager.unregisterListener(listenerId); + } + + private MessageListenerContainer getListenerContainer(String listenerId) { + Optional listenerContainerOpt = kafkaListenerContainerManager.getContainer(listenerId); + if (listenerContainerOpt.isEmpty()) { + throw new KafkaConsumerException("No such consumer: " + listenerId); + } + + return listenerContainerOpt.get(); + } + + private KafkaConsumerResponse createKafkaConsumerResponse(MessageListenerContainer listenerContainer) { + return KafkaConsumerResponse.builder() + .groupId(listenerContainer.getGroupId()) + .listenerId(listenerContainer.getListenerId()) + .active(listenerContainer.isRunning()) + .assignments(Optional.ofNullable(listenerContainer.getAssignedPartitions()) + .map(topicPartitions -> topicPartitions.stream() + .map(this::createKafkaConsumerAssignmentResponse) + .toList()) + .orElse(null)) + .build(); + } + + private KafkaConsumerAssignment createKafkaConsumerAssignmentResponse(TopicPartition topicPartition) { + return KafkaConsumerAssignment.builder() + .topic(topicPartition.topic()) + .partition(topicPartition.partition()) + .build(); + } +} diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/exception/KafkaConsumerException.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/exception/KafkaConsumerException.java new file mode 100644 index 000000000..2361ee819 --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/exception/KafkaConsumerException.java @@ -0,0 +1,8 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.exception; + +public class KafkaConsumerException extends RuntimeException { + public KafkaConsumerException(String message) { + super(message); + + } +} diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/listener/IngestListener.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/listener/IngestListener.java new file mode 100644 index 000000000..6d37e7006 --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/listener/IngestListener.java @@ -0,0 +1,41 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.listener; + +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.MemberIngester; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.IngestValidator; +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.RDFParser; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.listener.AcknowledgingMessageListener; +import org.springframework.kafka.support.Acknowledgment; + +public class IngestListener implements AcknowledgingMessageListener { + Logger log = LoggerFactory.getLogger(IngestListener.class); + + private final String collection; + private final Lang lang; + private final IngestValidator validator; + private final MemberIngester memberIngester; + + public IngestListener(String collection, Lang lang, IngestValidator validator, MemberIngester memberIngester) { + this.collection = collection; + this.lang = lang; + this.validator = validator; + this.memberIngester = memberIngester; + } + + @Override + public void onMessage(ConsumerRecord data, Acknowledgment ack) { + try { + var model = RDFParser.fromString(data.value(), lang).toModel(); + + validator.validate(model, collection); + memberIngester.ingest(collection, model); + + ack.acknowledge(); + } catch (Exception e) { + log.error(e.toString()); + } + } +} diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerAssignment.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerAssignment.java new file mode 100644 index 000000000..2dafc00c9 --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerAssignment.java @@ -0,0 +1,26 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model; + +public record KafkaConsumerAssignment(String topic, Integer partition) { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String topic; + private Integer partition; + + public Builder topic(String topic) { + this.topic = topic; + return this; + } + + public Builder partition(Integer partition) { + this.partition = partition; + return this; + } + + public KafkaConsumerAssignment build() { + return new KafkaConsumerAssignment(topic, partition); + } + } +} diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerRequest.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerRequest.java new file mode 100644 index 000000000..022ad92cd --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerRequest.java @@ -0,0 +1,4 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model; + +public record KafkaConsumerRequest(String collection, String topic, String mimeType) { +} diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerResponse.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerResponse.java new file mode 100644 index 000000000..76e5c9755 --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/model/KafkaConsumerResponse.java @@ -0,0 +1,40 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model; + +import java.util.List; + +public record KafkaConsumerResponse(String listenerId, String groupId, Boolean active, List assignments) { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String listenerId; + private String groupId; + private Boolean active; + private List assignments; + + public Builder listenerId(String listenerId) { + this.listenerId = listenerId; + return this; + } + + public Builder groupId(String groupId) { + this.groupId = groupId; + return this; + } + + public Builder active(Boolean active) { + this.active = active; + return this; + } + + public Builder assignments(List assignments) { + this.assignments = assignments; + return this; + } + + public KafkaConsumerResponse build() { + return new KafkaConsumerResponse(listenerId, groupId, active, assignments); + } + } +} diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerControllerTest.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerControllerTest.java new file mode 100644 index 000000000..1e5cbfdf8 --- /dev/null +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerControllerTest.java @@ -0,0 +1,100 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.controller; + +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.KafkaListenerContainerManager; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerRequest; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.kafka.listener.MessageListenerContainer; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.*; + +class KafkaConsumerControllerTest { + + private KafkaListenerContainerManager kafkaListenerContainerManager; + private KafkaConsumerController kafkaConsumerController; + + @BeforeEach + void setUp() { + kafkaListenerContainerManager = mock(KafkaListenerContainerManager.class); + kafkaConsumerController = new KafkaConsumerController(kafkaListenerContainerManager); + } + + @Test + void create() throws NoSuchMethodException { + KafkaConsumerRequest request = new KafkaConsumerRequest("collection", "topic", "mimeType"); + kafkaConsumerController.create(request); + verify(kafkaListenerContainerManager, times(1)).registerListener(anyString(), eq("collection"), eq("topic"), eq("mimeType")); + } + + @Test + void list() { + when(kafkaListenerContainerManager.listContainers()).thenReturn(Collections.emptyList()); + List response = kafkaConsumerController.list(); + assertTrue(response.isEmpty()); + } + + @Test + void get() { + MessageListenerContainer container = mock(MessageListenerContainer.class); + when(container.getListenerId()).thenReturn(UUID.randomUUID().toString()); + when(kafkaListenerContainerManager.getContainer(anyString())).thenReturn(Optional.of(container)); + KafkaConsumerResponse response = kafkaConsumerController.get("listenerId"); + assertNotNull(response); + } + + @Test + void activate() { + MessageListenerContainer container = mock(MessageListenerContainer.class); + when(container.isRunning()).thenReturn(false); + when(kafkaListenerContainerManager.getContainer(anyString())).thenReturn(Optional.of(container)); + kafkaConsumerController.activate("listenerId"); + verify(container, times(1)).start(); + } + + @Test + void pause() { + MessageListenerContainer container = mock(MessageListenerContainer.class); + when(container.isRunning()).thenReturn(true); + when(container.isContainerPaused()).thenReturn(false); + when(container.isPauseRequested()).thenReturn(false); + when(kafkaListenerContainerManager.getContainer(anyString())).thenReturn(Optional.of(container)); + kafkaConsumerController.pause("listenerId"); + verify(container, times(1)).pause(); + } + + @Test + void resume() { + MessageListenerContainer container = mock(MessageListenerContainer.class); + when(container.isRunning()).thenReturn(true); + when(container.isContainerPaused()).thenReturn(true); + when(kafkaListenerContainerManager.getContainer(anyString())).thenReturn(Optional.of(container)); + kafkaConsumerController.resume("listenerId"); + verify(container, times(1)).resume(); + } + + @Test + void stop() { + MessageListenerContainer container = mock(MessageListenerContainer.class); + when(container.isRunning()).thenReturn(true); + when(kafkaListenerContainerManager.getContainer(anyString())).thenReturn(Optional.of(container)); + kafkaConsumerController.stop("listenerId"); + verify(container, times(1)).stop(); + } + + @Test + void delete() { + MessageListenerContainer container = mock(MessageListenerContainer.class); + when(kafkaListenerContainerManager.getContainer(anyString())).thenReturn(Optional.of(container)); + kafkaConsumerController.delete("listenerId"); + verify(container, times(1)).stop(); + verify(kafkaListenerContainerManager, times(1)).unregisterListener("listenerId"); + } +} \ No newline at end of file diff --git a/ldes-server-ingest/ldes-server-ingest-rest/pom.xml b/ldes-server-ingest/ldes-server-ingest-rest/pom.xml index be54c5723..a5eb88037 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/pom.xml +++ b/ldes-server-ingest/ldes-server-ingest-rest/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-ingest - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-ingest-rest diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestController.java b/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestController.java index 6463ddd9f..87d03cfe9 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestController.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestController.java @@ -1,7 +1,7 @@ package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.MemberIngester; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.IngestValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.IngestValidator; import io.micrometer.observation.annotation.Observed; import org.apache.jena.rdf.model.Model; import org.springframework.http.HttpStatus; diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/collection/VersionOfPathCollection.java b/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/collection/VersionOfPathCollection.java deleted file mode 100644 index b9336ed0c..000000000 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/collection/VersionOfPathCollection.java +++ /dev/null @@ -1,32 +0,0 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.collection; - -import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.EventStreamCreatedEvent; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.EventStreamDeletedEvent; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; -import org.springframework.context.event.EventListener; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -@Component -public class VersionOfPathCollection { - private final Map versionOfPaths = new HashMap<>(); - - @EventListener - public void handleEventStreamCreatedEvent(EventStreamCreatedEvent event) { - EventStream eventStream = event.eventStream(); - versionOfPaths.put(eventStream.getCollection(), eventStream.getVersionOfPath()); - } - - @EventListener - public void handleEventStreamDeletedEvent(EventStreamDeletedEvent event) { - versionOfPaths.remove(event.collectionName()); - } - - public Optional getVersionOfPath(String collectionName) { - return Optional.ofNullable(versionOfPaths.get(collectionName)); - } -} - diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/exception/IngestionRestResponseEntityExceptionHandler.java b/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/exception/IngestionRestResponseEntityExceptionHandler.java index 0ca41da82..238daa60d 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/exception/IngestionRestResponseEntityExceptionHandler.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/exception/IngestionRestResponseEntityExceptionHandler.java @@ -16,14 +16,6 @@ @ControllerAdvice public class IngestionRestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { - @ExceptionHandler(value = { MemberIdNotFoundException.class }) - protected ResponseEntity handleGeneralException( - RuntimeException ex, WebRequest request) { - logger.error(ex.getMessage()); - String bodyOfResponse = ex.getMessage(); - return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST, request); - } - @ExceptionHandler(value = { ShaclValidationException.class }) protected ResponseEntity handleShaclValidationException( ShaclValidationException ex, WebRequest request) { diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/exception/MemberIdNotFoundException.java b/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/exception/MemberIdNotFoundException.java deleted file mode 100644 index ef4fec890..000000000 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/exception/MemberIdNotFoundException.java +++ /dev/null @@ -1,21 +0,0 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.exception; - -import org.apache.jena.rdf.model.Model; -import org.apache.jena.riot.Lang; -import org.apache.jena.riot.RDFWriter; - -public class MemberIdNotFoundException extends RuntimeException { - - private final transient Model model; - - public MemberIdNotFoundException(Model model) { - this.model = model; - } - - @Override - public String getMessage() { - final String modelAsString = RDFWriter.source(model).lang(Lang.TURTLE).asString(); - return "Member id could not be extracted from model: %n%n%s".formatted(modelAsString); - } - -} diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java index 48d276b2b..11bdcbf75 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java @@ -7,12 +7,12 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.VersionCreationProperties; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.MemberIngester; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.exceptions.MemberSubjectNotFoundException; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.converters.IngestedModelConverter; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.exception.IngestionRestResponseEntityExceptionHandler; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.exception.MemberIdNotFoundException; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator.BlankNodesValidator; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator.PathsValidator; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.memberingestvalidator.MemberIngestValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator.BlankNodesValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator.PathsValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.memberingestvalidator.MemberIngestValidator; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.riot.Lang; @@ -90,7 +90,7 @@ void when_POSTRequestIsPerformedWithMultipleNamedNodes_ThrowException() throws E byte[] ldesMemberBytes = readLdesMemberDataFromFile("example-ldes-member-with-multiple-nodes.nq", Lang.NQUADS); when(memberIngester.ingest(eq("mobility-hindrances"), any())) - .thenThrow(new MemberIdNotFoundException(ModelFactory.createDefaultModel())); + .thenThrow(new MemberSubjectNotFoundException(ModelFactory.createDefaultModel())); mockMvc.perform(post("/mobility-hindrances") .contentType("application/n-quads") @@ -116,7 +116,7 @@ void when_POSTRequestIsPerformed_WithoutVersionOf_ThenTheRequestFails() throws E Lang.NQUADS); when(memberIngester.ingest(eq("mobility-hindrances"), any())) - .thenThrow(new MemberIdNotFoundException(ModelFactory.createDefaultModel())); + .thenThrow(new MemberSubjectNotFoundException(ModelFactory.createDefaultModel())); mockMvc.perform(post("/mobility-hindrances").contentType("application/n-quads").content(ldesMemberBytes)) .andExpect(status().isBadRequest()) diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java index aa57a3e17..fb66db41a 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java @@ -5,8 +5,9 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.ShaclValidationException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.VersionCreationProperties; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator.BlankNodesValidator; -import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.validators.ingestreportvalidator.PathsValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator.BlankNodesValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.ingestreportvalidator.PathsValidator; +import be.vlaanderen.informatievlaanderen.ldes.server.ingest.validators.memberingestvalidator.MemberIngestValidator; import org.apache.jena.datatypes.xsd.XSDDatatype; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.RDFDataMgr; @@ -25,7 +26,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; class MemberIngestValidatorTest { private static final String TIMESTAMP_PATH = "http://purl.org/dc/terms/created"; diff --git a/ldes-server-ingest/pom.xml b/ldes-server-ingest/pom.xml index e4b832a14..9a0592ec5 100644 --- a/ldes-server-ingest/pom.xml +++ b/ldes-server-ingest/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT pom @@ -15,6 +15,7 @@ ldes-server-ingest-common ldes-server-ingest-rest + ldes-server-ingest-kafka \ No newline at end of file diff --git a/ldes-server-integration-test/pom.xml b/ldes-server-integration-test/pom.xml index b172599da..b29bfe3b5 100644 --- a/ldes-server-integration-test/pom.xml +++ b/ldes-server-integration-test/pom.xml @@ -6,11 +6,17 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-integration-test + + 1.18.3 + 3.6.0 + 1.18.3 + + @@ -84,6 +90,13 @@ test + + be.vlaanderen.informatievlaanderen.vsds + ldes-server-ingest-kafka + ${project.version} + test + + @@ -130,6 +143,27 @@ org.awaitility awaitility + + + org.testcontainers + junit-jupiter + ${testcontainers.version} + test + + + + org.testcontainers + kafka + ${kafka.version} + test + + + org.apache.kafka + kafka-clients + ${kafka-clients.version} + test + + \ No newline at end of file diff --git a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/IngestKafkaSteps.java b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/IngestKafkaSteps.java new file mode 100644 index 000000000..1ffd16fc6 --- /dev/null +++ b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/IngestKafkaSteps.java @@ -0,0 +1,80 @@ +package be.vlaanderen.informatievlaanderen.ldes.server; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.ListTopicsOptions; +import org.apache.kafka.clients.admin.ListTopicsResult; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.common.errors.TopicExistsException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.Objects; +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +@Testcontainers +public class IngestKafkaSteps extends LdesServerIntegrationTest { + + @Autowired + private KafkaTemplate kafkaTemplate; + + @Given("I have a Kafka Container running") + public void iHaveAKafkaContainerRunning() { + assertThat(kafka.isRunning()).isTrue(); + } + + @When("I add {int} members of template {string} to the Kafka topic {string}") + public void iAddMembersOfTemplateToTheKafkaTopic(int numberOfMembers, String memberTemplate, String topic) throws IOException, URISyntaxException { + final String memberContentTemplate = readMemberTemplate(memberTemplate); + + createTopicIfNotExists(topic, 1, (short) 1); + + for (int i = 0; i < numberOfMembers; i++) { + String memberContent = memberContentTemplate + .replace("ID", String.valueOf(i)) + .replace("DATETIME", getCurrentTimestamp()); + kafkaTemplate.send(topic, memberContent); + } + } + + private void createTopicIfNotExists(String topic, int partitions, short replicationFactor) { + Properties props = new Properties(); + props.put("bootstrap.servers", kafka.getBootstrapServers()); + + try (AdminClient adminClient = AdminClient.create(props)) { + ListTopicsResult topics = adminClient.listTopics(new ListTopicsOptions().timeoutMs(10000)); + if (!topics.names().get().contains(topic)) { + NewTopic newTopic = new NewTopic(topic, partitions, replicationFactor); + adminClient.createTopics(Collections.singleton(newTopic)).all().get(); + } + } catch (InterruptedException | ExecutionException e) { + if (!(e.getCause() instanceof TopicExistsException)) { + throw new RuntimeException("Failed to create topic", e); + } + } + } + + private String readMemberTemplate(String fileName) throws IOException, URISyntaxException { + ClassLoader classLoader = getClass().getClassLoader(); + Path path = Paths.get(Objects.requireNonNull(classLoader.getResource(fileName)).toURI()); + return Files.lines(path).collect(Collectors.joining()); + } + + private String getCurrentTimestamp() { + return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.[SSS]'Z'")); + } +} diff --git a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerIntegrationTest.java b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerIntegrationTest.java index 44d6816f7..e542114b7 100644 --- a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerIntegrationTest.java +++ b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerIntegrationTest.java @@ -18,10 +18,12 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Import; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.*; import org.springframework.test.web.servlet.MockMvc; +import org.testcontainers.containers.KafkaContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; import javax.sql.DataSource; @@ -41,6 +43,7 @@ "ldes-server.maintenance-cron=*/10 * * * * *", "ldes-server.compaction-duration=PT1S" }) +@Testcontainers @SuppressWarnings("java:S2187") public class LdesServerIntegrationTest { @Autowired @@ -62,4 +65,14 @@ public class LdesServerIntegrationTest { @Autowired JobExplorer jobExplorer; + + @Container + static final KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.4.0")) + .withKraft(); + + @DynamicPropertySource + static void overrideProperties(DynamicPropertyRegistry registry) { + kafka.start(); + registry.add("spring.kafka.bootstrap-servers", kafka::getBootstrapServers); + } } diff --git a/ldes-server-integration-test/src/test/resources/application-postgres-test.yml b/ldes-server-integration-test/src/test/resources/application-postgres-test.yml index e0b815ab7..cc3f2571b 100644 --- a/ldes-server-integration-test/src/test/resources/application-postgres-test.yml +++ b/ldes-server-integration-test/src/test/resources/application-postgres-test.yml @@ -18,6 +18,14 @@ spring: initialize-schema: always isolation-level-for-create: READ_COMMITTED + kafka: + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.apache.kafka.common.serialization.StringSerializer + consumer: + group-id: ldes + auto-offset-reset: earliest + zonky: test: database: diff --git a/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_jsonld.ttl b/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_jsonld.ttl new file mode 100644 index 000000000..e61b98dbb --- /dev/null +++ b/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_jsonld.ttl @@ -0,0 +1,16 @@ +@prefix ldes: . +@prefix dcterms: . +@prefix prov: . +@prefix tree: . +@prefix sh: . +@prefix server: . +@prefix xsd: . +@prefix event-stream: . + +server:jsonld + a ldes:EventStream ; + ldes:timestampPath dcterms:created ; + ldes:versionOfPath dcterms:isVersionOf ; + ldes:kafkaSource [ ldes:topic "jsonld" ; + ldes:mimeType "application/ld+json" ; ] ; + tree:shape [ a sh:NodeShape] . \ No newline at end of file diff --git a/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_nq.ttl b/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_nq.ttl new file mode 100644 index 000000000..3ee24e7d5 --- /dev/null +++ b/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_nq.ttl @@ -0,0 +1,16 @@ +@prefix ldes: . +@prefix dcterms: . +@prefix prov: . +@prefix tree: . +@prefix sh: . +@prefix server: . +@prefix xsd: . +@prefix event-stream: . + +server:nq + a ldes:EventStream ; + ldes:timestampPath dcterms:created ; + ldes:versionOfPath dcterms:isVersionOf ; + ldes:kafkaSource [ ldes:topic "nq" ; + ldes:mimeType "application/n-quads" ; ] ; + tree:shape [ a sh:NodeShape] . \ No newline at end of file diff --git a/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_ttl.ttl b/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_ttl.ttl new file mode 100644 index 000000000..cf216bfb7 --- /dev/null +++ b/ldes-server-integration-test/src/test/resources/data/input/eventstreams/kafka/event-stream_kafka_ttl.ttl @@ -0,0 +1,16 @@ +@prefix ldes: . +@prefix dcterms: . +@prefix prov: . +@prefix tree: . +@prefix sh: . +@prefix server: . +@prefix xsd: . + +server:ttl + a ldes:EventStream ; + ldes:timestampPath dcterms:created ; + ldes:versionOfPath dcterms:isVersionOf ; + ldes:kafkaSource [ ldes:topic "ttl" ; + ldes:mimeType "text/turtle" ; ] ; + + tree:shape [ a sh:NodeShape] . \ No newline at end of file diff --git a/ldes-server-integration-test/src/test/resources/data/input/members/mob-hind.template.json b/ldes-server-integration-test/src/test/resources/data/input/members/mob-hind.template.json new file mode 100644 index 000000000..ebcea619f --- /dev/null +++ b/ldes-server-integration-test/src/test/resources/data/input/members/mob-hind.template.json @@ -0,0 +1,30 @@ +[ + { + "@id": "http://test-data/mobility-hindrance/1" + }, + { + "@id": "http://test-data/mobility-hindrance/1/ID", + "http://purl.org/dc/terms/isVersionOf": [ + { + "@id": "http://test-data/mobility-hindrance/1" + } + ], + "@type": [ + "https://data.vlaanderen.be/ns/mobiliteit#Mobiliteitshinder" + ], + "http://www.opengis.net/ont/geosparql#asWKT": [ + { + "@value": "POLYGON ((3.7337472847142124 51.04745170597559, 4.359276660355135 50.851907920816956, 4.711285586572245 50.84364854093491, 4.4020885567877315 51.214619167436666, 3.7337472847142124 51.04745170597559))", + "@type": "http://www.opengis.net/ont/geosparql#wktLiteral" + } + ], + "http://purl.org/dc/terms/created": [ + { + "@value": "DATETIME" + } + ] + }, + { + "@id": "https://data.vlaanderen.be/ns/mobiliteit#Mobiliteitshinder" + } +] \ No newline at end of file diff --git a/ldes-server-integration-test/src/test/resources/data/input/members/mob-hind.template.nq b/ldes-server-integration-test/src/test/resources/data/input/members/mob-hind.template.nq new file mode 100644 index 000000000..6edac37ec --- /dev/null +++ b/ldes-server-integration-test/src/test/resources/data/input/members/mob-hind.template.nq @@ -0,0 +1,4 @@ + . + . + "POLYGON ((3.7337472847142124 51.04745170597559, 4.359276660355135 50.851907920816956, 4.711285586572245 50.84364854093491, 4.4020885567877315 51.214619167436666, 3.7337472847142124 51.04745170597559))"^^ . + "DATETIME"^^ . \ No newline at end of file diff --git a/ldes-server-integration-test/src/test/resources/features/ingest/ingest-kafka.feature b/ldes-server-integration-test/src/test/resources/features/ingest/ingest-kafka.feature new file mode 100644 index 000000000..388ad217b --- /dev/null +++ b/ldes-server-integration-test/src/test/resources/features/ingest/ingest-kafka.feature @@ -0,0 +1,25 @@ +Feature: LDES Server Kafka Ingestion + + Scenario Outline: The LDES server supports Kafka ingestion + Given I have a Kafka Container running + And I create the eventstream + When I add 5 members of template to the Kafka topic + Then the LDES contains 5 members + And I delete the eventstream + Examples: + | eventStreamFile | templateFile | topic | + | "data/input/eventstreams/kafka/event-stream_kafka_ttl.ttl" | "data/input/members/mob-hind.template.ttl" | "ttl" | + | "data/input/eventstreams/kafka/event-stream_kafka_jsonld.ttl" | "data/input/members/mob-hind.template.json" | "jsonld" | + | "data/input/eventstreams/kafka/event-stream_kafka_nq.ttl" | "data/input/members/mob-hind.template.nq" | "nq" | + + + Scenario: The LDES server supports 2 parallel kafka ingestion pipelines + Given I have a Kafka Container running + And I create the eventstream "data/input/eventstreams/kafka/event-stream_kafka_ttl.ttl" + And I create the eventstream "data/input/eventstreams/kafka/event-stream_kafka_nq.ttl" + When I add 5 members of template "data/input/members/mob-hind.template.ttl" to the Kafka topic "ttl" + When I add 10 members of template "data/input/members/mob-hind.template.nq" to the Kafka topic "nq" + Then the LDES "ttl" contains 5 members + And the LDES "nq" contains 10 members + And I delete the eventstream "ttl" + And I delete the eventstream "nq" \ No newline at end of file diff --git a/ldes-server-maintenance/ldes-server-compaction/pom.xml b/ldes-server-maintenance/ldes-server-compaction/pom.xml index 9b344b9bb..ef809b96e 100644 --- a/ldes-server-maintenance/ldes-server-compaction/pom.xml +++ b/ldes-server-maintenance/ldes-server-compaction/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-maintenance - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-compaction diff --git a/ldes-server-maintenance/ldes-server-maintenance-common/pom.xml b/ldes-server-maintenance/ldes-server-maintenance-common/pom.xml index 430e413f2..1aacb4f65 100644 --- a/ldes-server-maintenance/ldes-server-maintenance-common/pom.xml +++ b/ldes-server-maintenance/ldes-server-maintenance-common/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-maintenance - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-maintenance-common diff --git a/ldes-server-maintenance/ldes-server-retention/pom.xml b/ldes-server-maintenance/ldes-server-retention/pom.xml index a9bca1faa..a0e0428dc 100644 --- a/ldes-server-maintenance/ldes-server-retention/pom.xml +++ b/ldes-server-maintenance/ldes-server-retention/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server-maintenance - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-retention diff --git a/ldes-server-maintenance/pom.xml b/ldes-server-maintenance/pom.xml index f4c428c82..4ddf94046 100644 --- a/ldes-server-maintenance/pom.xml +++ b/ldes-server-maintenance/pom.xml @@ -6,7 +6,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT ldes-server-maintenance diff --git a/pom.xml b/pom.xml index 52215c02d..dbd812679 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ be.vlaanderen.informatievlaanderen.vsds ldes-server - 3.5.1-SNAPSHOT + 3.6.0-SNAPSHOT pom @@ -78,6 +78,7 @@ 6.0.13 + 3.1.2 5.1.0 @@ -89,7 +90,7 @@ 1.10.2 5.8.2 5.10.2 - 5.11.0 + 5.14.2 1.14.12 2.35.2 4.2.0 From 8ed5bd3fa30a3001ef9298ec8c3116cc39177ed1 Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Tue, 19 Nov 2024 17:43:02 +0100 Subject: [PATCH 07/45] chore: refactor-prefix-adder (#1421) * feat: addition of well known prefixes feat: creation of ldes-name and view-name prefixes * feat: separation of PrefixConstructor feat: tests added for Prefixes feat: new impl for PrefixAdder * feat: cleanup and configuration test added * chore: small refactor of config and uri creators * fix: broken tests * fix: bad property name used * feat: missing http presence handling in PrefixConstructor * chore: improve tests * docs: prefixes --- docs/_features/rdf-prefixes.md | 71 + docs/how-to-run.md | 6 + .../services/DcatServerServiceImpl.java | 6 +- .../server/admin/spi/EventStreamWriter.java | 13 +- .../admin/spi/ViewSpecificationConverter.java | 6 +- .../services/DcatServerServiceImplTest.java | 4 +- .../ViewSpecificationConverterTest.java | 4 +- .../admin/spi/EventStreamReaderTest.java | 4 +- .../admin/spi/EventStreamWriterTest.java | 35 +- .../rest/config/SpringIntegrationTest.java | 5 +- .../AdminDcatServerControllerTest.java | 36 +- .../AdminEventStreamsRestControllerTest.java | 6 +- .../AdminShapeRestControllerTest.java | 3 +- .../AdminViewsRestControllerTest.java | 7 +- .../DcatDatasetRestControllerTest.java | 6 +- .../DcatViewsRestControllerTest.java | 31 +- .../collections/ConfiguredPrefixes.java | 23 + .../server/domain/collections/Prefixes.java | 8 + .../collections/WellKnownPrefixesConfig.java | 33 + .../domain/converter/PrefixAdderImpl.java | 86 +- .../rest/HostNamePrefixConstructor.java | 32 + .../rest/HostNamePrefixConstructorConfig.java | 17 + ...java => RelativeUriPrefixConstructor.java} | 21 +- .../domain/rest/UriPrefixConstructor.java | 5 + .../src/main/java/module-info.java | 4 +- .../main/resources/well-known-prefixes.csv | 15 + .../collections/ConfiguredPrefixesTest.java | 40 + .../converter/HttpModelConverterTest.java | 3 +- .../domain/converter/PrefixAdderImplTest.java | 47 +- .../rest/HostNamePrefixConstructorTest.java | 48 + .../domain/rest/PrefixConstructorTest.java | 57 - .../RelativeUriPrefixConstructorTest.java | 48 + .../UriPrefixConstructorBeanLoadingTest.java | 49 + .../resources/eventstream/example-gipod.nq | 5905 ----------------- .../services/TreeNodeConverterImpl.java | 18 +- .../EventStreamControllerTest.java | 6 +- .../rest/treenode/TreeNodeControllerTest.java | 10 +- .../services/TreeNodeConverterImplTest.java | 20 +- 38 files changed, 572 insertions(+), 6166 deletions(-) create mode 100644 docs/_features/rdf-prefixes.md create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/ConfiguredPrefixes.java create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/Prefixes.java create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixesConfig.java create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructor.java create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructorConfig.java rename ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/{PrefixConstructor.java => RelativeUriPrefixConstructor.java} (61%) create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/UriPrefixConstructor.java create mode 100644 ldes-server-domain/src/main/resources/well-known-prefixes.csv create mode 100644 ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/ConfiguredPrefixesTest.java create mode 100644 ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructorTest.java delete mode 100644 ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/PrefixConstructorTest.java create mode 100644 ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/RelativeUriPrefixConstructorTest.java create mode 100644 ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/UriPrefixConstructorBeanLoadingTest.java delete mode 100644 ldes-server-domain/src/test/resources/eventstream/example-gipod.nq diff --git a/docs/_features/rdf-prefixes.md b/docs/_features/rdf-prefixes.md new file mode 100644 index 000000000..2e0d51e11 --- /dev/null +++ b/docs/_features/rdf-prefixes.md @@ -0,0 +1,71 @@ +--- +layout: default +title: RDF Prefixes +nav_order: 3 +--- + +# RDF Prefixes +{: .no_toc } + +For some RDF formats, e.g. `text/turtle`, prefixes can be added to have a more clean and readable output. There are +several ways that prefixes will be added to the output of the LDES Server. + +1. TOC +{:toc} + +## Well known prefixes + +Well known prefixes are some of the prefixes that are most frequent used in LDES and are hard coded in the LDES server +and can be found here: + +| Prefix | URI | +|--------|---------------------------------------------| +| foaf | http://xmlns.com/foaf/0.1/ | +| rdf | http://www.w3.org/1999/02/22-rdf-syntax-ns# | +| rdfs | http://www.w3.org/2000/01/rdf-schema# | +| skos | http://www.w3.org/2004/02/skos/core# | +| owl | http://www.w3.org/2002/07/owl# | +| xsd | http://www.w3.org/2001/XMLSchema# | +| geo | http://www.opengis.net/ont/geosparql# | +| dcat | http://www.w3.org/ns/dcat# | +| dct | http://purl.org/dc/terms/ | +| prov | http://www.w3.org/ns/prov# | +| m8g | http://data.europa.eu/m8g/ | +| tree | https://w3id.org/tree# | +| ldes | https://w3id.org/ldes# | +| sh | http://www.w3.org/ns/shacl# | +| shsh | http://www.w3.org/ns/shacl-shacl# | + +## Configured prefixes + +When needed, additional prefixes can be added to the LDES Server. This can come in handy for project specific prefixes. +To add these prefixes, a map can be added to the application properties as follows + +```yaml +ldes-server: + formatting: + prefixes: + prefix1: uri1 + prefix2: uri2 + prefix3: uri3 +``` + +In the following example are two prefixes added to the LDES Server: +```yaml +ldes-server: + formatting: + prefixes: + example: http://example.org/ + vsds-verkeersmetingen: http://data.vlaanderen.be/ns/verkeersmetingen# +``` + +## Event Stream and fragment specific prefixes + +Per event stream and fragment, prefixes will be extracted and added to the output. Those will look something like this: + +**Event stream** +- `collectionName: ${ldes-server.host-name}/{collectionName}` + +**Tree node** +- `collectionName: ${ldes-server.host-name}/{collectionName}` +- `viewName: ${ldes-server.host-name}/{collectionName}/{viewName}` diff --git a/docs/how-to-run.md b/docs/how-to-run.md index d9f4a75fb..2a80d54f6 100644 --- a/docs/how-to-run.md +++ b/docs/how-to-run.md @@ -99,6 +99,12 @@ Here is an explanation provided for all the possibilities on how to tweak and co No 604800 + + ldes-server.formatting.prefixes + Prefixes that will be used in the LDES Server when fetching data from the server in text/turtle format + No + + PostgreSQL Storage2 spring.datasource.url diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/dcat/dcatserver/services/DcatServerServiceImpl.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/dcat/dcatserver/services/DcatServerServiceImpl.java index be5ec1033..689cd8fe1 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/dcat/dcatserver/services/DcatServerServiceImpl.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/dcat/dcatserver/services/DcatServerServiceImpl.java @@ -10,7 +10,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.ExistingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.DcatView; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.UriPrefixConstructor; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Statement; @@ -26,7 +26,7 @@ public class DcatServerServiceImpl implements DcatServerService { private final DcatServerRepository dcatServerRepository; private final DcatViewService dcatViewService; private final DcatDatasetService dcatDatasetService; - private final PrefixConstructor prefixConstructor; + private final UriPrefixConstructor prefixConstructor; private final ModelValidator dcatShaclValidator; @@ -34,7 +34,7 @@ public DcatServerServiceImpl(DcatServerRepository dcatServerRepository, DcatViewService dcatViewService, DcatDatasetService dcatDatasetService, DcatShaclValidator dcatShaclValidator, - PrefixConstructor prefixConstructor) { + UriPrefixConstructor prefixConstructor) { this.dcatServerRepository = dcatServerRepository; this.dcatViewService = dcatViewService; this.dcatDatasetService = dcatDatasetService; diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamWriter.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamWriter.java index e3cc745ad..9c1427428 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamWriter.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamWriter.java @@ -2,7 +2,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.PrefixAdder; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.UriPrefixConstructor; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.Resource; import org.apache.jena.rdf.model.Statement; @@ -13,11 +14,9 @@ import java.util.Optional; import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.RdfConstants.*; -import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.RdfConstants.RDF_SYNTAX_TYPE; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel; import static org.apache.jena.rdf.model.ResourceFactory.*; -import static org.apache.jena.rdf.model.ResourceFactory.createResource; @Component public class EventStreamWriter { @@ -26,9 +25,9 @@ public class EventStreamWriter { private final ViewSpecificationConverter viewSpecificationConverter; private final PrefixAdder prefixAdder; - private final PrefixConstructor prefixConstructor; + private final UriPrefixConstructor prefixConstructor; - public EventStreamWriter(ViewSpecificationConverter viewSpecificationConverter, PrefixAdder prefixAdder, PrefixConstructor prefixConstructor) { + public EventStreamWriter(ViewSpecificationConverter viewSpecificationConverter, PrefixAdder prefixAdder, UriPrefixConstructor prefixConstructor) { this.viewSpecificationConverter = viewSpecificationConverter; this.prefixAdder = prefixAdder; this.prefixConstructor = prefixConstructor; @@ -54,6 +53,10 @@ public Model write(EventStreamTO eventStreamTO) { .add(eventSourceStatements) .add(dataset); + if(prefixConstructor instanceof HostNamePrefixConstructor hostNamePrefixConstructor) { + eventStreamModel.setNsPrefixes(hostNamePrefixConstructor.buildCollectionUri(eventStreamTO.getCollection())); + } + Statement shaclStatement = getShaclReferenceStatement(eventStreamTO.getShacl(), subject); eventStreamModel.add(shaclStatement); diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/ViewSpecificationConverter.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/ViewSpecificationConverter.java index 2a2d4966a..faaedcdbd 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/ViewSpecificationConverter.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/ViewSpecificationConverter.java @@ -4,7 +4,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.FragmentationConfig; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.UriPrefixConstructor; import org.apache.jena.graph.GraphMemFactory; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; @@ -27,11 +27,11 @@ public class ViewSpecificationConverter { public static final int DEFAULT_PAGE_SIZE = 100; private final RetentionModelExtractor retentionModelExtractor; private final FragmentationConfigExtractor fragmentationConfigExtractor; - private final PrefixConstructor prefixConstructor; + private final UriPrefixConstructor prefixConstructor; public ViewSpecificationConverter(RetentionModelExtractor retentionModelExtractor, FragmentationConfigExtractor fragmentationConfigExtractor, - PrefixConstructor prefixConstructor) { + UriPrefixConstructor prefixConstructor) { this.retentionModelExtractor = retentionModelExtractor; this.fragmentationConfigExtractor = fragmentationConfigExtractor; this.prefixConstructor = prefixConstructor; diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/dcatserver/services/DcatServerServiceImplTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/dcatserver/services/DcatServerServiceImplTest.java index 5f7b2616a..8efbc929f 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/dcatserver/services/DcatServerServiceImplTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/dcatserver/services/DcatServerServiceImplTest.java @@ -12,7 +12,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.DcatView; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructor; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.riot.Lang; @@ -37,7 +37,7 @@ class DcatServerServiceImplTest { private static final String ID = "2a896d35-8c72-4723-83b3-add9b1be96aa"; private static final Model DCAT = ModelFactory.createDefaultModel(); private static final DcatServer SERVER_DCAT = new DcatServer(ID, DCAT); - private final PrefixConstructor prefixConstructor = new PrefixConstructor("http://localhost.dev", false); + private final HostNamePrefixConstructor prefixConstructor = new HostNamePrefixConstructor("http://localhost.dev"); private DcatServerService service; @Mock private DcatServerRepository repository; diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/view/service/ViewSpecificationConverterTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/view/service/ViewSpecificationConverterTest.java index 498085a53..5f7248ec3 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/view/service/ViewSpecificationConverterTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/view/service/ViewSpecificationConverterTest.java @@ -7,7 +7,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.FragmentationConfig; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructor; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFDataMgr; @@ -35,7 +35,7 @@ class ViewSpecificationConverterTest { void setup() throws URISyntaxException { viewSpecificationConverter = new ViewSpecificationConverter(new RetentionModelExtractor(), new FragmentationConfigExtractor(), - new PrefixConstructor(HOST_NAME, false)); + new HostNamePrefixConstructor(HOST_NAME)); Model retentionModel = readModelFromFile("retention/example_timebased.ttl"); FragmentationConfig fragmentationConfig = new FragmentationConfig(); fragmentationConfig.setName("ExampleFragmentation"); diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReaderTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReaderTest.java index 3b3e0b3aa..b727c5bdd 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReaderTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamReaderTest.java @@ -3,7 +3,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.FragmentationConfig; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructor; import org.apache.commons.io.FileUtils; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.Lang; @@ -33,7 +33,7 @@ class EventStreamReaderTest { @BeforeEach void setUp() { String hostName = "http://localhost:8080"; - PrefixConstructor prefixConstructor = new PrefixConstructor(hostName, false); + HostNamePrefixConstructor prefixConstructor = new HostNamePrefixConstructor(hostName); RetentionModelExtractor retentionModelExtractor = new RetentionModelExtractor(); ViewSpecificationConverter viewSpecificationConverter = new ViewSpecificationConverter(retentionModelExtractor, new FragmentationConfigExtractor(), prefixConstructor); diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamWriterTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamWriterTest.java index 18eb23716..e57b4ef43 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamWriterTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/spi/EventStreamWriterTest.java @@ -5,8 +5,11 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.FragmentationConfig; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.UriPrefixConstructor; import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.riot.Lang; @@ -35,18 +38,44 @@ class EventStreamWriterTest { @BeforeEach void setUp() { String hostName = "http://localhost:8080"; - PrefixConstructor prefixConstructor = new PrefixConstructor(hostName, false); + UriPrefixConstructor prefixConstructor = new HostNamePrefixConstructor(hostName); ViewSpecificationConverter viewSpecificationConverter = new ViewSpecificationConverter( new RetentionModelExtractor(), new FragmentationConfigExtractor(), prefixConstructor ); - eventStreamWriter = new EventStreamWriter(viewSpecificationConverter, new PrefixAdderImpl(), prefixConstructor); + eventStreamWriter = new EventStreamWriter(viewSpecificationConverter, new PrefixAdderImpl(List.of()), prefixConstructor); shacl = RDFDataMgr.loadModel("shacl/collection-shape.ttl"); dataSetModel = RDFDataMgr.loadModel("dcat/dataset/valid.ttl"); eventSourceRetentionModels = List.of(RDFDataMgr.loadModel("retention/example_timebased.ttl")); } + @Test + void when_RelativeUrlEnabled_when_ConvertToModel_then_ModelHasEmptyPrefixMap() { + final UriPrefixConstructor uriPrefixConstructor = new RelativeUriPrefixConstructor(); + ViewSpecificationConverter viewSpecificationConverter = new ViewSpecificationConverter( + new RetentionModelExtractor(), + new FragmentationConfigExtractor(), + uriPrefixConstructor + ); + final EventStreamWriter writerWithoutPrefixes = new EventStreamWriter(viewSpecificationConverter, model -> model, uriPrefixConstructor); + + final Model result = writerWithoutPrefixes.write(baseBuilder().withShacl(ModelFactory.createDefaultModel()).build()); + + assertThat(result.getNsPrefixMap()).isEmpty(); + } + + @Test + void test_PrefixMapIsNotEmpty() { + final EventStreamTO eventStream = baseBuilder() + .withShacl(shacl) + .build(); + + final Model convertedModel = eventStreamWriter.write(eventStream); + + assertThat(convertedModel.getNsPrefixMap()).containsKey(COLLECTION_NAME); + } + @Nested class EventStreamWithViews { private List views; diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/config/SpringIntegrationTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/config/SpringIntegrationTest.java index c4a75dedf..ae558d09a 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/config/SpringIntegrationTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/config/SpringIntegrationTest.java @@ -12,7 +12,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.controllers.*; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.PrefixAdderImpl; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.RdfModelConverter; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import io.cucumber.spring.CucumberContextConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -32,7 +33,7 @@ @ActiveProfiles("test") @ContextConfiguration(classes = { AdminEventStreamsRestController.class, AdminViewsRestController.class, AdminServerDcatController.class, DcatViewsRestController.class, DcatDatasetRestController.class, EventSourceServiceImpl.class, PrefixAdderImpl.class, - PrefixConstructor.class, RdfModelConverter.class}) + HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, RdfModelConverter.class}) @ComponentScan(value = { "be.vlaanderen.informatievlaanderen.ldes.server.admin.spi", "be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventstream", diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminDcatServerControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminDcatServerControllerTest.java index c0f41ea25..830bf02c8 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminDcatServerControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminDcatServerControllerTest.java @@ -11,7 +11,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.ExistingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.ShaclValidationException; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import org.apache.commons.io.FileUtils; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.Lang; @@ -41,8 +42,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest -@ContextConfiguration(classes = { AdminServerDcatController.class, HttpModelConverter.class, PrefixAdderImpl.class, - AdminRestResponseEntityExceptionHandler.class, PrefixConstructor.class, RdfModelConverter.class }) +@ContextConfiguration(classes = {AdminServerDcatController.class, HttpModelConverter.class, PrefixAdderImpl.class, + AdminRestResponseEntityExceptionHandler.class, HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, + RdfModelConverter.class}) @ExtendWith(MockitoExtension.class) class AdminDcatServerControllerTest { private static final String ID = "id"; @@ -67,8 +69,8 @@ void when_PostValidDcatModel_then_ReturnStatus200() throws Exception { when(service.createDcatServer(any())).thenReturn(new DcatServer(ID, model)); mockMvc.perform(post("/admin/api/v1/dcat") - .contentType(Lang.TURTLE.getHeaderString()) - .content(readDataFromFile())) + .contentType(Lang.TURTLE.getHeaderString()) + .content(readDataFromFile())) .andExpect(status().isCreated()) .andExpect(content().string(ID)); @@ -86,8 +88,8 @@ void when_PostInvalidDcatModel_then_ReturnStatus400() throws Exception { doThrow(IllegalArgumentException.class).when(validator).validate(any(), any()); mockMvc.perform(post("/admin/api/v1/dcat") - .contentType(Lang.TURTLE.getHeaderString()) - .content(modelString)) + .contentType(Lang.TURTLE.getHeaderString()) + .content(modelString)) .andExpect(status().isBadRequest()); verify(validator).validate(any(), any()); @@ -99,8 +101,8 @@ void when_ServerAlreadyHasDcatConfigured_and_PostDcat_then_Return400() throws Ex when(service.createDcatServer(any())).thenThrow(ExistingResourceException.class); mockMvc.perform(post("/admin/api/v1/dcat") - .contentType(Lang.TURTLE.getHeaderString()) - .content(readDataFromFile())) + .contentType(Lang.TURTLE.getHeaderString()) + .content(readDataFromFile())) .andExpect(status().isBadRequest()); InOrder inOrder = inOrder(service, validator); @@ -119,8 +121,8 @@ void when_PutValidDcat_then_ReturnStatus200() throws Exception { when(service.createDcatServer(any())).thenReturn(new DcatServer(ID, model)); mockMvc.perform(put("/admin/api/v1/dcat/{id}", ID) - .contentType(Lang.TURTLE.getHeaderString()) - .content(readDataFromFile())) + .contentType(Lang.TURTLE.getHeaderString()) + .content(readDataFromFile())) .andExpect(status().isOk()); InOrder inOrder = inOrder(service, validator); @@ -137,8 +139,8 @@ void when_PutInvalidDcatModel_then_ReturnStatus400() throws Exception { doThrow(IllegalArgumentException.class).when(validator).validate(any(), any()); mockMvc.perform(put("/admin/api/v1/dcat/{id}", ID) - .contentType(Lang.TURTLE.getHeaderString()) - .content(modelString)) + .contentType(Lang.TURTLE.getHeaderString()) + .content(modelString)) .andExpect(status().isBadRequest()); verify(validator).validate(any(), any()); @@ -151,8 +153,8 @@ void when_ServerHasNoDcatYet_and_PutServerDcat_then_ReturnStatus404() throws Exc when(service.updateDcatServer(eq(ID), any())).thenThrow(MissingResourceException.class); mockMvc.perform(put("/admin/api/v1/dcat/{id}", ID) - .contentType(Lang.TURTLE.getHeaderString()) - .content(readDataFromFile())) + .contentType(Lang.TURTLE.getHeaderString()) + .content(readDataFromFile())) .andExpect(status().isNotFound()); InOrder inOrder = inOrder(service, validator); @@ -204,7 +206,7 @@ void should_ReturnDcat_when_Valid() throws Exception { when(service.getComposedDcat()).thenReturn(model); mockMvc.perform(get("/admin/api/v1/dcat") - .accept(MediaType.ALL)) + .accept(MediaType.ALL)) .andExpect(status().isOk()) .andExpect(IsIsomorphic.with(model)); @@ -217,7 +219,7 @@ void should_ReturnValidationReport_when_Invalid() throws Exception { doThrow(new ShaclValidationException("validation-report", null)).when(service).getComposedDcat(); mockMvc.perform(get("/admin/api/v1/dcat") - .accept(MediaType.ALL)) + .accept(MediaType.ALL)) .andExpect(status().isInternalServerError()); verify(service).getComposedDcat(); diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java index 61f532d08..b1ea3d948 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java @@ -16,7 +16,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.FragmentationConfig; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.RDFDataMgr; import org.junit.jupiter.api.BeforeEach; @@ -62,7 +63,8 @@ EventStreamWriter.class, EventStreamReader.class, KafkaSourceReader.class, ViewSpecificationConverter.class, PrefixAdderImpl.class, ValidatorsConfig.class, AdminRestResponseEntityExceptionHandler.class, RetentionModelExtractor.class, CharsetEncodingConfig.class, - FragmentationConfigExtractor.class, PrefixConstructor.class, RdfModelConverter.class, AdminVersionHeaderControllerAdvice.class}) + FragmentationConfigExtractor.class, HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, + RdfModelConverter.class, AdminVersionHeaderControllerAdvice.class}) @Import(BuildProperties.class) class AdminEventStreamsRestControllerTest { private static final String COLLECTION = "name1"; diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminShapeRestControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminShapeRestControllerTest.java index 2b5228c4c..42ac08052 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminShapeRestControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminShapeRestControllerTest.java @@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -140,7 +141,7 @@ void when_ModelWithoutType_Then_ReturnedBadRequest() throws Exception { static class AdminShapeRestControllerTestConfig { @Bean public HttpModelConverter modelConverter() { - return new HttpModelConverter(new PrefixAdderImpl(), new RdfModelConverter()); + return new HttpModelConverter(new PrefixAdderImpl(List.of()), new RdfModelConverter()); } } } diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestControllerTest.java index e7e9dce7a..0c8bbd314 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestControllerTest.java @@ -18,7 +18,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFDataMgr; @@ -54,9 +55,9 @@ @ActiveProfiles({"test", "rest"}) @ContextConfiguration(classes = {AdminViewsRestController.class, CharsetEncodingConfig.class, PrefixAdderImpl.class, HttpModelConverter.class, ViewHttpConverter.class, ListViewHttpConverter.class, - ViewSpecificationConverter.class, ValidatorsConfig.class, + ViewSpecificationConverter.class, ValidatorsConfig.class, RdfModelConverter.class, AdminRestResponseEntityExceptionHandler.class, RetentionModelExtractor.class, - FragmentationConfigExtractor.class, PrefixConstructor.class, RdfModelConverter.class}) + FragmentationConfigExtractor.class, HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class}) class AdminViewsRestControllerTest { private static final String COLLECTION_NAME = "name1"; private static final String VIEW_NAME = "view1"; diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/DcatDatasetRestControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/DcatDatasetRestControllerTest.java index 225ce41f9..25e0c1c05 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/DcatDatasetRestControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/DcatDatasetRestControllerTest.java @@ -9,7 +9,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.RdfModelConverter; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.ExistingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import org.apache.jena.riot.Lang; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -38,7 +39,8 @@ @WebMvcTest @ActiveProfiles({ "test", "rest" }) @ContextConfiguration(classes = { HttpModelConverter.class, PrefixAdderImpl.class, DcatDatasetRestController.class, - AdminRestResponseEntityExceptionHandler.class, PrefixConstructor.class, RdfModelConverter.class, RdfModelConverter.class }) + AdminRestResponseEntityExceptionHandler.class, HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, + RdfModelConverter.class, RdfModelConverter.class }) class DcatDatasetRestControllerTest { private static final String COLLECTION_NAME = "collection"; @Autowired diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/DcatViewsRestControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/DcatViewsRestControllerTest.java index 2935ff937..8da0ff69c 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/DcatViewsRestControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/DcatViewsRestControllerTest.java @@ -9,7 +9,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.RdfModelConverter; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFParser; @@ -31,10 +32,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest -@ActiveProfiles({ "test", "rest" }) -@ContextConfiguration(classes = { DcatViewsRestController.class, PrefixAdderImpl.class, - HttpModelConverter.class, AdminRestResponseEntityExceptionHandler.class, PrefixConstructor.class, - RdfModelConverter.class}) +@ActiveProfiles({"test", "rest"}) +@ContextConfiguration(classes = {DcatViewsRestController.class, PrefixAdderImpl.class, + HttpModelConverter.class, AdminRestResponseEntityExceptionHandler.class, RdfModelConverter.class, + HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class}) class DcatViewsRestControllerTest { private static final String COLLECTION_NAME = "collectionName"; @@ -62,8 +63,8 @@ void should_Return400_when_ValidatorThrowsIllegalArgumentException() throws Exce doThrow(IllegalArgumentException.class).when(validator).validate(any(), any()); mockMvc.perform(post(BASE_URL, COLLECTION_NAME, VIEW_NAME) - .content(writeToTurtle(readTurtleFromFile("dcat/dataservice/dcat-view-valid.ttl"))) - .contentType(Lang.TURTLE.getHeaderString())) + .content(writeToTurtle(readTurtleFromFile("dcat/dataservice/dcat-view-valid.ttl"))) + .contentType(Lang.TURTLE.getHeaderString())) .andExpect(status().isBadRequest()); verifyNoInteractions(dcatViewService); @@ -73,8 +74,8 @@ void should_Return400_when_ValidatorThrowsIllegalArgumentException() throws Exce void should_Return201_when_CreatedSuccessfully() throws Exception { Model dcat = readTurtleFromFile("dcat/dataservice/dcat-view-valid.ttl"); mockMvc.perform(post(BASE_URL, COLLECTION_NAME, VIEW_NAME) - .content(writeToTurtle(dcat)) - .contentType(Lang.TURTLE.getHeaderString())) + .content(writeToTurtle(dcat)) + .contentType(Lang.TURTLE.getHeaderString())) .andExpect(status().isCreated()); verify(dcatViewService) @@ -91,8 +92,8 @@ void should_Return400_when_ValidatorThrowsIllegalArgumentException() throws Exce doThrow(IllegalArgumentException.class).when(validator).validate(any(), any()); mockMvc.perform(put(BASE_URL, COLLECTION_NAME, VIEW_NAME) - .content(writeToTurtle(readTurtleFromFile("dcat/dataservice/dcat-view-valid.ttl"))) - .contentType(Lang.TURTLE.getHeaderString())) + .content(writeToTurtle(readTurtleFromFile("dcat/dataservice/dcat-view-valid.ttl"))) + .contentType(Lang.TURTLE.getHeaderString())) .andExpect(status().isBadRequest()); verifyNoInteractions(dcatViewService); @@ -102,8 +103,8 @@ void should_Return400_when_ValidatorThrowsIllegalArgumentException() throws Exce void should_Return200_when_UpdatedSuccessfully() throws Exception { Model dcat = readTurtleFromFile("dcat/dataservice/dcat-view-valid.ttl"); mockMvc.perform(put(BASE_URL, COLLECTION_NAME, VIEW_NAME) - .content(writeToTurtle(dcat)) - .contentType(Lang.TURTLE.getHeaderString())) + .content(writeToTurtle(dcat)) + .contentType(Lang.TURTLE.getHeaderString())) .andExpect(status().isOk()); verify(dcatViewService) @@ -116,8 +117,8 @@ void should_Return404_when_ResourceNotFound() throws Exception { Model dcat = readTurtleFromFile("dcat/dataservice/dcat-view-valid.ttl"); mockMvc.perform(put(BASE_URL, COLLECTION_NAME, VIEW_NAME) - .content(writeToTurtle(dcat)) - .contentType(Lang.TURTLE.getHeaderString())) + .content(writeToTurtle(dcat)) + .contentType(Lang.TURTLE.getHeaderString())) .andExpect(status().isNotFound()); verify(dcatViewService) diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/ConfiguredPrefixes.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/ConfiguredPrefixes.java new file mode 100644 index 000000000..c2e5806c2 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/ConfiguredPrefixes.java @@ -0,0 +1,23 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.collections; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; + +@Configuration +@EnableConfigurationProperties +@ConfigurationProperties(prefix = "ldes-server.formatting") +public class ConfiguredPrefixes implements Prefixes { + private Map prefixes = Map.of(); + + @Override + public Map getPrefixes() { + return prefixes; + } + + public void setPrefixes(Map prefixes) { + this.prefixes = prefixes; + } +} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/Prefixes.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/Prefixes.java new file mode 100644 index 000000000..22d96f46d --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/Prefixes.java @@ -0,0 +1,8 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.collections; + +import java.util.Map; + +@FunctionalInterface +public interface Prefixes { + Map getPrefixes(); +} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixesConfig.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixesConfig.java new file mode 100644 index 000000000..24b221f59 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixesConfig.java @@ -0,0 +1,33 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.collections; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.ResourceUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Map; +import java.util.stream.Collectors; + +@Configuration +public class WellKnownPrefixesConfig { + + @Bean + public Prefixes wellKnownPrefixes() { + final Map prefixes = readPrefixes(); + return () -> prefixes; + } + + + private Map readPrefixes() { + try { + final File wellKnownPrefixes = ResourceUtils.getFile("classpath:well-known-prefixes.csv"); + return Files.readAllLines(wellKnownPrefixes.toPath()).stream() + .map(line -> line.split(",")) + .collect(Collectors.toMap(line -> line[0], line -> line[1])); + } catch (IOException e) { + return Map.of(); + } + } +} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/PrefixAdderImpl.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/PrefixAdderImpl.java index e14a7ee9d..c935b39dc 100644 --- a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/PrefixAdderImpl.java +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/PrefixAdderImpl.java @@ -1,94 +1,22 @@ package be.vlaanderen.informatievlaanderen.ldes.server.domain.converter; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.collections.Prefixes; import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.Statement; -import org.apache.jena.shared.PrefixMapping; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.util.List; @Component public class PrefixAdderImpl implements PrefixAdder { + private final List prefixes; - private static final String VALID_LOCALNAME_REGEX = "([a-zA-Z][\\-_a-zA-Z0-9]*)$"; - private static final String VALID_PREFIX_REGEX = "^[a-zA-Z_][\\w.-]*$"; // NCName regex - private static final Logger LOGGER = LoggerFactory.getLogger(PrefixAdderImpl.class); + public PrefixAdderImpl(List prefixes) { + this.prefixes = prefixes; + } @Override public Model addPrefixesToModel(Model model) { - Map nameSpaceMap = new HashMap<>(); - Map localNamesMap = new HashMap<>(); - model.listStatements().forEach(statement -> extractNamespaces(nameSpaceMap, localNamesMap, statement)); - removePrefixesWithNonCompliantLocalName(nameSpaceMap, localNamesMap); - addNameSpacesAsPrefix(model, nameSpaceMap); + prefixes.stream().map(Prefixes::getPrefixes).forEach(model::setNsPrefixes); return model; } - - private void removePrefixesWithNonCompliantLocalName(Map nameSpaceMap, - Map localNamesMap) { - localNamesMap.forEach((localName, prefix) -> { - if (!localName.matches(VALID_LOCALNAME_REGEX)) { - nameSpaceMap.remove(prefix); - } - }); - } - - private void extractNamespaces(Map nameSpaceMap, Map localNamesMap, - Statement statement) { - - addPotentialPrefixToNamespaceMap(nameSpaceMap, localNamesMap, statement.getPredicate().getNameSpace(), - statement.getPredicate().getLocalName()); - if (statement.getObject().isURIResource()) { - addPotentialPrefixToNamespaceMap(nameSpaceMap, localNamesMap, - statement.getObject().asResource().getNameSpace(), - statement.getObject().asResource().getLocalName()); - } - } - - private void addPotentialPrefixToNamespaceMap(Map nameSpaceMap, Map localNamesMap, - String predicateNameSpace, String localName) { - if(predicateNameSpace.length() > 1){ - String candidateForPrefix = getPrefixCandidate(predicateNameSpace); - if (isValidPrefixCandidate(candidateForPrefix)) { - nameSpaceMap.put(candidateForPrefix, predicateNameSpace); - localNamesMap.put(localName, candidateForPrefix); - } - } - } - - private static boolean isValidPrefixCandidate(String candidateForPrefix) { - return !candidateForPrefix.contains(".") && candidateForPrefix.matches(VALID_PREFIX_REGEX); - } - - private String getPrefixCandidate(String nameSpace) { - return getStandardPrefix(nameSpace).orElseGet(() -> { - String[] split = nameSpace.split("/"); - return split[split.length - 1].replace("#", ""); - }); - } - - private Optional getStandardPrefix(String nameSpace) { - return PrefixMapping.Extended - .getNsPrefixMap() - .entrySet() - .stream() - .filter(entry -> entry.getValue().equals(nameSpace)) - .map(Map.Entry::getKey) - .findFirst(); - } - - private void addNameSpacesAsPrefix(Model model, Map nameSpaceMap) { - nameSpaceMap.forEach((prefix, uri) -> { - try { - model.setNsPrefix(prefix, uri); - } catch (PrefixMapping.IllegalPrefixException exception) { - // If namespace cannot be added as prefix, ignore. - LOGGER.warn("IllegalPrefixException: {}", exception.getMessage()); - } - }); - } } diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructor.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructor.java new file mode 100644 index 000000000..d1240e7b5 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructor.java @@ -0,0 +1,32 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; + +import java.util.Map; + +public class HostNamePrefixConstructor implements UriPrefixConstructor { + private final String hostname; + + public HostNamePrefixConstructor(String hostname) { + this.hostname = hostname; + } + + @Override + public String buildPrefix() { + return hostname; + } + + public Map buildCollectionUri(String collectionName) { + return Map.of(collectionName, createCollectionUri(collectionName)); + } + + public Map buildFragmentUri(String collectionName, String fragmentId) { + String[] fragmentIdParts = fragmentId.split(collectionName + "/" + "|\\?"); + return Map.of( + collectionName, createCollectionUri(collectionName), + fragmentIdParts[1], "%s/%s/%s/".formatted(hostname, collectionName, fragmentIdParts[1]) + ); + } + + private String createCollectionUri(String collectionName) { + return hostname + "/" + collectionName + "/"; + } +} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructorConfig.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructorConfig.java new file mode 100644 index 000000000..d2952aa23 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructorConfig.java @@ -0,0 +1,17 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.ServerConfig.HOST_NAME_KEY; + +@Configuration +public class HostNamePrefixConstructorConfig { + @Bean + @ConditionalOnMissingBean(UriPrefixConstructor.class) + public UriPrefixConstructor hostNamePrefixConstructor(@Value(HOST_NAME_KEY) String hostname) { + return new HostNamePrefixConstructor(hostname); + } +} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/PrefixConstructor.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/RelativeUriPrefixConstructor.java similarity index 61% rename from ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/PrefixConstructor.java rename to ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/RelativeUriPrefixConstructor.java index 28466bc97..58bc3cf3b 100644 --- a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/PrefixConstructor.java +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/RelativeUriPrefixConstructor.java @@ -1,7 +1,7 @@ package be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; @@ -9,24 +9,11 @@ import java.util.Arrays; -import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.ServerConfig.HOST_NAME_KEY; -import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.ServerConfig.USE_RELATIVE_URL_KEY; - @Component -public class PrefixConstructor { - - private final String hostname; - private final boolean useRelativeUrl; - - public PrefixConstructor(@Value(HOST_NAME_KEY) String hostname, @Value(USE_RELATIVE_URL_KEY) boolean useRelativeUrl) { - this.hostname = hostname; - this.useRelativeUrl = useRelativeUrl; - } - +@ConditionalOnProperty(value = "ldes-server.use-relative-url", havingValue = "true") +public class RelativeUriPrefixConstructor implements UriPrefixConstructor { + @Override public String buildPrefix() { - if (!useRelativeUrl) { - return hostname; - } StringBuilder prefix = new StringBuilder(); Arrays.stream(extractRequestURL().split("/")).filter(s -> !s.isEmpty()).forEach(s -> prefix.append("/..")); if (!prefix.isEmpty()) { diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/UriPrefixConstructor.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/UriPrefixConstructor.java new file mode 100644 index 000000000..8d03b1bf8 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/UriPrefixConstructor.java @@ -0,0 +1,5 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; + +public interface UriPrefixConstructor { + String buildPrefix(); +} diff --git a/ldes-server-domain/src/main/java/module-info.java b/ldes-server-domain/src/main/java/module-info.java index 9ac61dfb0..8101c51f5 100644 --- a/ldes-server-domain/src/main/java/module-info.java +++ b/ldes-server-domain/src/main/java/module-info.java @@ -11,8 +11,9 @@ exports be.vlaanderen.informatievlaanderen.ldes.server.domain.events.retention; exports be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin; exports be.vlaanderen.informatievlaanderen.ldes.server.domain.services; + exports be.vlaanderen.informatievlaanderen.ldes.server.domain.collections; - requires spring.web; + requires spring.web; requires spring.context; requires spring.beans; requires spring.boot; @@ -27,5 +28,6 @@ requires micrometer.core; requires org.apache.tomcat.embed.core; requires titanium.json.ld; + requires spring.boot.autoconfigure; } \ No newline at end of file diff --git a/ldes-server-domain/src/main/resources/well-known-prefixes.csv b/ldes-server-domain/src/main/resources/well-known-prefixes.csv new file mode 100644 index 000000000..477e3d3d9 --- /dev/null +++ b/ldes-server-domain/src/main/resources/well-known-prefixes.csv @@ -0,0 +1,15 @@ +foaf,http://xmlns.com/foaf/0.1/ +rdf,http://www.w3.org/1999/02/22-rdf-syntax-ns# +rdfs,http://www.w3.org/2000/01/rdf-schema# +skos,http://www.w3.org/2004/02/skos/core# +owl,http://www.w3.org/2002/07/owl# +xsd,http://www.w3.org/2001/XMLSchema# +geo,http://www.opengis.net/ont/geosparql# +dcat,http://www.w3.org/ns/dcat# +dct,http://purl.org/dc/terms/ +prov,http://www.w3.org/ns/prov# +m8g,http://data.europa.eu/m8g/ +tree,https://w3id.org/tree# +ldes,https://w3id.org/ldes# +sh,http://www.w3.org/ns/shacl# +shsh,http://www.w3.org/ns/shacl-shacl# \ No newline at end of file diff --git a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/ConfiguredPrefixesTest.java b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/ConfiguredPrefixesTest.java new file mode 100644 index 000000000..f98554225 --- /dev/null +++ b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/ConfiguredPrefixesTest.java @@ -0,0 +1,40 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.collections; + +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class ConfiguredPrefixesTest { + private ApplicationContextRunner runner; + + @Test + void test_Empty() { + new ApplicationContextRunner() + .withBean(ConfiguredPrefixes.class) + .run(context -> assertThat(context.getBean(Prefixes.class)) + .isNotNull() + .extracting(Prefixes::getPrefixes, InstanceOfAssertFactories.MAP) + .isEmpty()); + } + + @Test + void test_WithPropertiesProvided() { + new ApplicationContextRunner() + .withSystemProperties("ldes-server.formatting.prefixes.myapp=http://my-app.com#", "ldes-server.formatting.prefixes.example=http://example.com/") + .withUserConfiguration(ConfiguredPrefixes.class) + .run(context -> assertThat(context.getBean(ConfiguredPrefixes.class)) + .isNotNull() + .extracting(Prefixes::getPrefixes, InstanceOfAssertFactories.MAP) + .containsAllEntriesOf(Map.of( + "myapp", "http://my-app.com#", + "example", "http://example.com/" + )) + .doesNotContainKey("other-key") + .doesNotContainKey("ldes-server.formatting.prefixes.myapp") + ); + } +} \ No newline at end of file diff --git a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/HttpModelConverterTest.java b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/HttpModelConverterTest.java index 68cbba55e..5afc2fdee 100644 --- a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/HttpModelConverterTest.java +++ b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/HttpModelConverterTest.java @@ -10,13 +10,14 @@ import org.springframework.util.ResourceUtils; import java.io.*; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; class HttpModelConverterTest { - private final HttpModelConverter httpModelConverter = new HttpModelConverter(new PrefixAdderImpl(), new RdfModelConverter()); + private final HttpModelConverter httpModelConverter = new HttpModelConverter(new PrefixAdderImpl(List.of()), new RdfModelConverter()); @Test void when_ReadHttpInputMessage_then_ReturnModel() throws IOException { diff --git a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/PrefixAdderImplTest.java b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/PrefixAdderImplTest.java index 11699609b..6e3f6f4e4 100644 --- a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/PrefixAdderImplTest.java +++ b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/converter/PrefixAdderImplTest.java @@ -1,45 +1,32 @@ package be.vlaanderen.informatievlaanderen.ldes.server.domain.converter; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.collections.Prefixes; import org.apache.jena.rdf.model.Model; -import org.apache.jena.riot.Lang; -import org.apache.jena.riot.RDFParserBuilder; +import org.apache.jena.rdf.model.ModelFactory; import org.junit.jupiter.api.Test; -import java.io.File; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; class PrefixAdderImplTest { - PrefixAdder prefixAdder = new PrefixAdderImpl(); + private final Prefixes gipodPrefixes = () -> Map.of("gipod", "http://data.vlaanderen.be/ns/gipod#"); + private final Prefixes wellKnownPrefixes = () -> Map.of( + "rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "dcterms", "http://purl.org/dc/terms/" + ); + private final PrefixAdderImpl prefixAdder = new PrefixAdderImpl(List.of(gipodPrefixes, wellKnownPrefixes, Map::of)); @Test - void when_PrefixesAndLocalNamesAreValid_TheyAreAddedToPrefixMap() throws URISyntaxException, IOException { - Model model = readLdesMemberFromFile(getClass().getClassLoader(), "eventstream/example-gipod.nq"); - Model updatedModel = prefixAdder.addPrefixesToModel(model); - Map nsPrefixMap = updatedModel.getNsPrefixMap(); + void test_AddPrefixesToMap() { + Model model = ModelFactory.createDefaultModel(); - // verify that there is no prefix for a namespace if ONE or MORE of its - // localNames is invalid. - assertFalse(nsPrefixMap.containsKey("mobiliteit")); + final Map nsPrefixMap = prefixAdder.addPrefixesToModel(model).getNsPrefixMap(); - assertTrue(nsPrefixMap.containsKey("statuses")); - assertTrue(nsPrefixMap.containsKey("rdf")); - } - - private Model readLdesMemberFromFile(ClassLoader classLoader, String fileName) - throws URISyntaxException, IOException { - File file = new File(Objects.requireNonNull(classLoader.getResource(fileName)).toURI()); - - return RDFParserBuilder.create() - .fromString(Files.lines(Paths.get(file.toURI())).collect(Collectors.joining())).lang(Lang.NQUADS) - .toModel(); + assertThat(nsPrefixMap) + .hasSize(3) + .containsAllEntriesOf(gipodPrefixes.getPrefixes()) + .containsAllEntriesOf(wellKnownPrefixes.getPrefixes()); } } \ No newline at end of file diff --git a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructorTest.java b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructorTest.java new file mode 100644 index 000000000..3ff56a993 --- /dev/null +++ b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/HostNamePrefixConstructorTest.java @@ -0,0 +1,48 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class HostNamePrefixConstructorTest { + + private final String hostname = "http://localhost:8080"; + private HostNamePrefixConstructor prefixConstructor; + + @BeforeEach + void setUp() { + prefixConstructor = new HostNamePrefixConstructor(hostname); + } + + @Test + void when_BuildPrefix_Then_ReturnHostname() { + String prefix = prefixConstructor.buildPrefix(); + + assertThat(prefix).isEqualTo(hostname); + } + + @Test + void given_CollectionUri_When_CreateUri_then_ReturnMap() { + Map result = prefixConstructor.buildCollectionUri("event-stream"); + + assertThat(result) + .containsEntry("event-stream", "http://localhost:8080/event-stream/"); + } + + @ParameterizedTest + @ValueSource(strings = {"/event-stream/timebased", "/event-stream/timebased?pageNumber=1", "http://localhost:8080/event-stream/timebased", "http://localhost:8080/event-stream/timebased?pageNumber=1"}) + void given_FragmentId_when_CreatePrefixes_then_ReturnValidMap(String fragmentId) { + Map result = prefixConstructor.buildFragmentUri("event-stream", fragmentId); + + assertThat(result) + .containsExactlyInAnyOrderEntriesOf(Map.of( + "timebased", "http://localhost:8080/event-stream/timebased/", + "event-stream", "http://localhost:8080/event-stream/" + )); + } +} \ No newline at end of file diff --git a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/PrefixConstructorTest.java b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/PrefixConstructorTest.java deleted file mode 100644 index eb14db038..000000000 --- a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/PrefixConstructorTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import java.util.stream.Stream; - -import static org.assertj.core.api.Assertions.assertThat; - -class PrefixConstructorTest { - - private final String hostname = "http://localhost"; - private PrefixConstructor prefixConstructor; - - @Test - void when_NotUsingRelativeUrls_Then_GetHostname() { - prefixConstructor = new PrefixConstructor(hostname, false); - MockHttpServletRequest request = new MockHttpServletRequest(); - RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); - request.setRequestURI("any/any"); - - String prefix = prefixConstructor.buildPrefix(); - - assertThat(prefix).isEqualTo(hostname); - } - @ParameterizedTest(name = "Request with URI {0} returns {1}") - @ArgumentsSource(RequestUriArgumentsProvider.class) - void when_UsingRelativeUrls_Then_GetCorrectPrefix(String requestUri, String expected) { - prefixConstructor = new PrefixConstructor(hostname, true); - MockHttpServletRequest request = new MockHttpServletRequest(); - RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); - request.setRequestURI(requestUri); - - String prefix = prefixConstructor.buildPrefix(); - - assertThat(prefix).isEqualTo(expected); - } - - static class RequestUriArgumentsProvider implements ArgumentsProvider { - @Override - public Stream provideArguments(ExtensionContext extensionContext) { - return Stream.of( - Arguments.of("test", ".."), - Arguments.of("test/testing", "../.."), - Arguments.of("/test/testing", "../.."), - Arguments.of("", ""), - Arguments.of("test/testing/testing/testing", "../../../..")); - } - } -} \ No newline at end of file diff --git a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/RelativeUriPrefixConstructorTest.java b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/RelativeUriPrefixConstructorTest.java new file mode 100644 index 000000000..6ef9e4491 --- /dev/null +++ b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/RelativeUriPrefixConstructorTest.java @@ -0,0 +1,48 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import static org.assertj.core.api.Assertions.assertThat; + +class RelativeUriPrefixConstructorTest { + private UriPrefixConstructor prefixConstructor; + + @BeforeEach + void setUp() { + prefixConstructor = new RelativeUriPrefixConstructor(); + } + + @ParameterizedTest(name = "Request with URI {0} returns {1}") + @CsvSource(value = { + "test,..", + "test/testing,../..", + "/test/testing,../..", + "'',''", + "test/testing/testing/testing,../../../.."}) + void test_BuildPrefix(String requestUri, String expected) { + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); + request.setRequestURI(requestUri); + + String prefix = prefixConstructor.buildPrefix(); + + assertThat(prefix).isEqualTo(expected); + } + + @Test + void when_RequestAttributesAreNull_test_BuildPrefix() { + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestContextHolder.setRequestAttributes(null); + request.setRequestURI("/test"); + + String prefix = prefixConstructor.buildPrefix(); + + assertThat(prefix).isEmpty(); + } +} \ No newline at end of file diff --git a/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/UriPrefixConstructorBeanLoadingTest.java b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/UriPrefixConstructorBeanLoadingTest.java new file mode 100644 index 000000000..6b7b21d84 --- /dev/null +++ b/ldes-server-domain/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/rest/UriPrefixConstructorBeanLoadingTest.java @@ -0,0 +1,49 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +class UriPrefixConstructorBeanLoadingTest { + private ApplicationContextRunner applicationContextRunner; + + @BeforeEach + void setUp() { + applicationContextRunner = new ApplicationContextRunner() + .withPropertyValues("ldes-server.host-name=http://localhost:8080") + .withUserConfiguration(HostNamePrefixConstructorConfig.class) + .withBean(RelativeUriPrefixConstructor.class); + } + + @Test + void test_UseRelativeUrlIsTrue() { + applicationContextRunner + .withPropertyValues("ldes-server.use-relative-url=true") + .run(context -> assertThat(context) + .hasSingleBean(RelativeUriPrefixConstructor.class) + .doesNotHaveBean(HostNamePrefixConstructor.class) + ); + } + + @Test + void test_MissingUseRelativeUrl() { + applicationContextRunner + .run(context -> assertThat(context) + .hasSingleBean(HostNamePrefixConstructor.class) + .doesNotHaveBean(RelativeUriPrefixConstructor.class) + ); + } + + @Test + void test_UseRelativeUrlIsFalse() { + applicationContextRunner + .withPropertyValues("ldes-server.use-relative-url=false") + .run(context -> assertThat(context) + .hasSingleBean(HostNamePrefixConstructor.class) + .doesNotHaveBean(RelativeUriPrefixConstructor.class) + ); + } +} \ No newline at end of file diff --git a/ldes-server-domain/src/test/resources/eventstream/example-gipod.nq b/ldes-server-domain/src/test/resources/eventstream/example-gipod.nq deleted file mode 100644 index b46cde74e..000000000 --- a/ldes-server-domain/src/test/resources/eventstream/example-gipod.nq +++ /dev/null @@ -1,5905 +0,0 @@ - "2021-01-06T13:17:30.173Z"^^ . - "2021-01-06T13:17:30.173Z"^^ . - "2021-01-06T18:05:27.2Z"^^ . - _:B49c1dc268446ec1952d55d136a72b37b . - . - _:B14c3cf74630fe09b6d0a8e450dc94d68 . - . - . - _:Bdaf102bdc35f7f79fd8ee0b9c580b83c . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B553ba70919b0b534e3ad64ed3d1ca4f5 . - "10590531"^^ . - _:Ba5b7839048a4b77d54513101517f90dc . - "9120 Beveren, Yzerhand 4: Stelling / Verlenging"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B334f2851ade92838f1e0ed5e61da276e . - . - "2021-01-06T14:12:33.057Z"^^ . - _:B21d0538d4cbd99a1b7ea4e88a41bc43b . - "9520 Sint-Lievens-Houtem, Edgard Tinelstraat 11: Andere"^^ . - "10590455"^^ . - _:B4babbc3b5bf82c76672aa56c1170400b . - _:B424916895c219af5013792dfa08ff8e2 . - . - "2021-01-06T18:04:56.907Z"^^ . - . - _:B0c5c051b64b0149b3961de830cedd3c6 . - . - "2021-01-06T14:12:33.057Z"^^ . -_:B0768cfc7b5596b8384439c9f67febfa4 "https://gipod.vlaanderen.be"@nl-BE . -_:B0768cfc7b5596b8384439c9f67febfa4 "10590584"^^ . -_:B0768cfc7b5596b8384439c9f67febfa4 . -_:B5ad0cdf27cfd4f9551c4e5962eaab833 "https://gipod.vlaanderen.be"@nl-BE . -_:B5ad0cdf27cfd4f9551c4e5962eaab833 "10590390"^^ . -_:B5ad0cdf27cfd4f9551c4e5962eaab833 . -_:B938041365d5912f5f7320867f8e95fcf "https://gipod.vlaanderen.be"@nl-BE . -_:B938041365d5912f5f7320867f8e95fcf "10590347"^^ . -_:B938041365d5912f5f7320867f8e95fcf . -_:Bf61c7ac2f42d99f9de3157c5f07d563e "https://gipod.vlaanderen.be"@nl-BE . -_:Bf61c7ac2f42d99f9de3157c5f07d563e "10590478"^^ . -_:Bf61c7ac2f42d99f9de3157c5f07d563e . - . - . - "9197156"^^ . -_:Bdc53cf7bab7a76c237a9a55afc92be38 "https://gipod.vlaanderen.be"@nl-BE . -_:Bdc53cf7bab7a76c237a9a55afc92be38 "10590485"^^ . -_:Bdc53cf7bab7a76c237a9a55afc92be38 . -_:B548e6f72b19d73155c4641fb25354afd " POLYGON ((136099.335744357 191421.761713748, 136100.901545801 191421.016094012, 136103.212966982 191423.774887034, 136101.796289484 191425.117002558, 136099.335744357 191421.761713748))"^^ . -_:B548e6f72b19d73155c4641fb25354afd . - _:Bf40cc6df4eb23104e9a12f612bd870a5 . - "2021-01-06T14:08:41.89Z"^^ . - . - . - "2021-01-06T14:17:00.21Z"^^ . - _:Bd08cf8345059db10e694953707018dff . - "2021-01-06T18:05:01.117Z"^^ . - "10590464"^^ . - . - _:Bd140ab71f8928489c4d00c1923a195f6 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bcce77798d3a689528c52c86b37308d5e . - "Vrachtwagen/werfwagen beton storten"^^ . - _:Bc866e111ddf3ae37a30fbf408683d5a5 . - . - . - . - "9197231"^^ . -_:B7e7081e8e638c98abea87621b06d3689 "Stad Dendermonde"^^ . -_:B7e7081e8e638c98abea87621b06d3689 . -_:B7e7081e8e638c98abea87621b06d3689 . - . - _:B63d6622f2b43aa7181ba0bea6ba7c713 . - . -_:B98e61b89bdf5dd5ba424613172335a30 "https://gipod.vlaanderen.be"@nl-BE . -_:B98e61b89bdf5dd5ba424613172335a30 "10590412"^^ . -_:B98e61b89bdf5dd5ba424613172335a30 . - . - . - "9197223"^^ . -_:B1c71eac8ecbc3ca28e99442f93fffed3 "Stad Ronse"^^ . -_:B1c71eac8ecbc3ca28e99442f93fffed3 . -_:B1c71eac8ecbc3ca28e99442f93fffed3 . -_:B342cb15e40269689fd4d27745bfe821a "Stad Hasselt"^^ . -_:B342cb15e40269689fd4d27745bfe821a . -_:B342cb15e40269689fd4d27745bfe821a . -_:B7a68f78e3235ea8096053f3e97a79951 "2021-01-14T08:00:00Z"^^ . -_:B7a68f78e3235ea8096053f3e97a79951 "2021-01-14T17:00:00Z"^^ . -_:B7a68f78e3235ea8096053f3e97a79951 . -_:B0f37adbf06d1fb29d5291a503803ed64 " MULTIPOLYGON (((60336.2386981964 201892.215392419, 60341.6071602923 201904.443556082, 60331.7649797832 201908.022530813, 60326.0982697931 201898.180350304, 60336.2386981964 201892.215392419)), ((60308.7998919285 201755.916104763, 60324.0105345336 201757.407344234, 60317.1508329666 201783.354911031, 60301.3436945731 201777.389953146, 60308.7998919285 201755.916104763)))"^^ . -_:B0f37adbf06d1fb29d5291a503803ed64 . -_:B1cab394929f807dc1c9d25b1a14ca149 " POLYGON ((157720.315653858 190282.239878826, 157705.99977314 190293.519079363, 157703.396894011 190290.699276954, 157717.278964575 190279.203162237, 157720.315653858 190282.239878826))"^^ . -_:B1cab394929f807dc1c9d25b1a14ca149 . - "2021-01-06T14:20:53.95Z"^^ . - "10590443"^^ . - . - "2021-01-06T18:04:53.007Z"^^ . - _:B72b7a239d8d36e4c9eef1ebeb9ed24e4 . - "2021-01-06T14:22:09.08Z"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bb39d4ebdf8790ac12f48da09c105b601 . - _:B7a68f78e3235ea8096053f3e97a79951 . - _:B734b5b55ff88cffff35c40f4d7829def . - . - "1860 Meise, Boechtstraat 16: Verhuis/leveringen"^^ . - . - _:B341016649f2b6e1b5192c785c27e627c . -_:B30158b77d17b9dfcd02da1cc4fdf877e "https://gipod.vlaanderen.be"@nl-BE . -_:B30158b77d17b9dfcd02da1cc4fdf877e "10590461"^^ . -_:B30158b77d17b9dfcd02da1cc4fdf877e . - . - _:Baa56b3cfdc39dc020047a533ac95f37e . - . - "Wegeniswerken Plaatsen van signalisatie voor nutswerken.\n\nDeze aanvraag betreft pagina 1 van 4 pagina's !"^^ . - _:Bdd99da2028ca7ce0976e6dcf235d0dfe . - _:Bd47dd681ab36e8118690338c179a8936 . - _:B3846feeed71af0fa2b5f50a85fec1066 . - _:B63699ede0572cd20d6ccde8902e67f9b . - . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:40:33.943Z"^^ . - "2021-01-06T18:04:46.327Z"^^ . - "2021-01-06T14:40:33.943Z"^^ . - "10590419"^^ . - . - _:B4272cba92665121e08c5b25dabb4b75c . -_:Bbd6a38af5b85a990df0c9a09d6136913 "Stad Ronse"^^ . -_:Bbd6a38af5b85a990df0c9a09d6136913 . -_:Bbd6a38af5b85a990df0c9a09d6136913 . - . - _:B0a8172fcbe75ef027c26e7e0d68da676 . - . -_:B0582bf0ca4746dc7699116ceab1b4b30 "Stad Hasselt"^^ . -_:B0582bf0ca4746dc7699116ceab1b4b30 . -_:B0582bf0ca4746dc7699116ceab1b4b30 . -_:B56cc145d4861dd139d0205ab2d155d2e "https://gipod.vlaanderen.be"@nl-BE . -_:B56cc145d4861dd139d0205ab2d155d2e "10590557"^^ . -_:B56cc145d4861dd139d0205ab2d155d2e . -_:B793027b93d20d3d2436bd8c299dd3df6 "Politiezone Brugge"^^ . -_:B793027b93d20d3d2436bd8c299dd3df6 . -_:B793027b93d20d3d2436bd8c299dd3df6 . - . - . - "9197324"^^ . -_:B88872278f61b6228cb6dc33522005059 "Gemeente Ingelmunster"^^ . -_:B88872278f61b6228cb6dc33522005059 . -_:B88872278f61b6228cb6dc33522005059 . -_:B837362e5b8a0fac9777cc89426f4d911 "https://gipod.vlaanderen.be"@nl-BE . -_:B837362e5b8a0fac9777cc89426f4d911 "10590515"^^ . -_:B837362e5b8a0fac9777cc89426f4d911 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B14da98d5abe8e909ec149aad423c20e2 . - "10590567"^^ . - _:B3255d16cc35f70132d8cb90dea964b9c . - _:Bf84bf1a0fb4e36210e98b9f7ab42b60f . - . - _:B9e568be89baf8414b6d79b0af884ce6f . - _:B14c5091b1b6bf6312621f1196d4d46ae . - "9120 Beveren, Pauwstraat 88: Wegenwerken (3a-2a-2b)"^^ . - . - . - "2021-01-06T12:56:33.89Z"^^ . - "2021-01-06T12:56:33.89Z"^^ . - . - "2021-01-06T18:05:37.12Z"^^ . -_:B33e084e8a903a18cb8b2425254328472 " POLYGON ((95546.9552656286 159461.9612512481, 95547.04574184009 159461.96319760388, 95547.13603738231 159461.96923483865, 95547.22596738115 159461.97935059154, 95547.31534771094 159461.99352415127, 95547.40399537141 159462.0117264984, 95547.4917288624 159462.03392036483, 95547.57836855543 159462.06006031015, 95547.6637370615 159462.09009281447, 95547.74765959433 159462.12395638833, 95547.82996432808 159462.16158169828, 95547.91048274934 159462.20289170902, 95547.98905000198 159462.24780184106, 95548.06550522482 159462.29622014388, 95548.13969188088 159462.34804748427, 95548.21145807793 159462.4031777492, 95548.28065687948 159462.4614980631, 95548.34714660558 159462.52288901902, 95548.41079112295 159462.5872249231, 95548.47146012372 159462.65437405187, 95548.52902939213 159462.72419892196, 95548.58338105895 159462.79655657161, 95548.63440384278 159462.87129885334, 95548.68199327785 159462.94827273735, 95548.72605192798 159463.0273206247, 95548.76648958602 159463.10828067016, 95548.80322345858 159463.19098711343, 95548.83617833549 159463.27527061853, 95548.86528674384 159463.36095862067, 95548.89048908609 159463.44787567938, 95548.91173376216 159463.53584383774, 95548.92897727496 159463.62468298685, 95548.94218431957 159463.71421123447, 95548.95188662251 159463.81151022573, 95548.95682172895 159463.909167141, 95548.95697784246 159464.00694855035, 95548.95235458991 159464.1046207261, 95548.94296302229 159464.2019502018, 95548.9288255883 159464.29870433008, 95548.90997608079 159464.3946518389, 95548.88645955584 159464.4895633842, 95548.85833222518 159464.5832120983, 95548.82566132175 159464.67537413197, 95548.78852493908 159464.76582918965, 95548.7470118445 159464.854361056, 95548.70122126705 159464.94075811267, 95548.6512626603 159465.02481384412, 95548.59725544063 159465.1063273314, 95548.53932870191 159465.18510373216, 95548.47762090682 159465.26095474671, 95548.41227955594 159465.33369906776, 95548.34346083515 159465.40316281407, 95548.27132924236 159465.46917994594, 95548.1960571942 159465.53159266216, 95548.11782461399 159465.59025177718, 95548.03681850163 159465.6450170777, 95547.9532324866 159465.6957576578, 95547.86726636514 159465.742352232, 95547.77912562268 159465.78468942485, 95547.68902094265 159465.82266803752, 95547.59716770294 159465.85619728942, 95547.50378546097 159465.88519703542, 95547.409097429 159465.90959795713, 95547.31332994049 159465.9293417289, 95547.21671190913 159465.94438115705, 95547.20453876552 159465.94593431955, 95517.57953876552 159469.63343431955, 95517.56735632104 159469.6349127598, 95517.4699996292 159469.6440178647, 95517.37231427104 159469.64835366668, 95517.27453374452 159469.6479098018, 95517.17689177516 159469.6426873311, 95517.07962175725 159469.6326987378, 95516.98295619599 159469.6179678978, 95516.88712615176 159469.59853002228, 95516.7923606878 159469.5744315737, 95516.69888632269 159469.54573015484, 95516.60692648884 159469.51249437084, 95516.51670099849 159469.47480366545, 95516.42842551829 159469.43274813102, 95516.34231105374 159469.3864282932, 95516.25856344485 159469.33595487062, 95516.17738287413 159469.28144851027, 95516.09896338807 159469.2230394991, 95516.02349243332 159469.16086745256, 95515.95115040865 159469.09508098094, 95515.88211023371 159469.02583733413, 95515.81653693572 159468.95330202568, 95515.754587255 159468.87764843728, 95515.6964092703 159468.79905740422, 95515.64214204489 159468.7177167832, 95515.59191529409 159468.6338210033, 95515.54584907526 159468.5475706012, 95515.50405350082 159468.45917174182, 95515.46662847501 159468.36883572562, 95515.43366345516 159468.27677848338, 95515.40523723776 159468.18322006022, 95515.38141777022 159468.08838408947, 95515.36226198838 159467.99249725824, 95515.34781568043 159467.8957887655, 95515.3381133775 159467.79848977426, 95515.33317827106 159467.70083285897, 95515.33302215755 159467.60305144964, 95515.3376454101 159467.50537927388, 95515.34703697772 159467.4080497982, 95515.36117441171 159467.3112956699, 95515.38002391922 159467.2153481611, 95515.40354044417 159467.12043661578, 95515.43166777483 159467.02678790168, 95515.46433867826 159466.93462586802, 95515.50147506093 159466.84417081033, 95515.5429881555 159466.75563894399, 95515.58877873296 159466.6692418873, 95515.6387373397 159466.58518615586, 95515.69274455938 159466.5036726686, 95515.7506712981 159466.42489626782, 95515.81237909319 159466.34904525327, 95515.87772044407 159466.27630093222, 95515.94653916486 159466.20683718592, 95516.01867075765 159466.14082005405, 95516.0939428058 159466.07840733783, 95516.17217538602 159466.0197482228, 95516.25318149838 159465.96498292228, 95516.3367675134 159465.91424234217, 95516.42273363487 159465.867647768, 95516.51087437733 159465.82531057514, 95516.60097905736 159465.78733196246, 95516.69283229706 159465.75380271056, 95516.78621453904 159465.72480296457, 95516.880902571 159465.70040204286, 95516.97667005952 159465.6806582711, 95517.07328809088 159465.66561884293, 95517.08546123448 159465.66406568044, 95546.71046123448 159461.97656568044, 95546.72264367896 159461.9750872402, 95546.83875296728 159461.9647783267, 95546.9552656286 159461.9612512481))"^^ . -_:B33e084e8a903a18cb8b2425254328472 . -_:B9cd89f7248cd3bd59e3d7c2714b5e2fd "https://gipod.vlaanderen.be"@nl-BE . -_:B9cd89f7248cd3bd59e3d7c2714b5e2fd "10590551"^^ . -_:B9cd89f7248cd3bd59e3d7c2714b5e2fd . -_:B9c7674ba0c18dd72477cf08a878e8b7b " POLYGON ((70047.687061855 211732.342260781, 70048.296408572 211727.379530022, 70050.2815008753 211727.623268709, 70049.6721541583 211732.585999467, 70047.687061855 211732.342260781))"^^ . -_:B9c7674ba0c18dd72477cf08a878e8b7b . -_:B6da25e0b9eb7722898f00950b325b05d "Gemeente Zedelgem"^^ . -_:B6da25e0b9eb7722898f00950b325b05d . -_:B6da25e0b9eb7722898f00950b325b05d . - . - . - _:B765b1b7550bdc2dc904cdce0a4e142e7 . - . -_:Bbd1593202edc05fc4b7df0334e6ff9fc "Gemeente Tervuren"^^ . -_:Bbd1593202edc05fc4b7df0334e6ff9fc . -_:Bbd1593202edc05fc4b7df0334e6ff9fc . - . - _:B77e7c7a24be86eadeb335db97e11fef3 . - . - . - _:B41bb1d1181d0d7e47f794941b3da5e88 . - . -_:Baa56b3cfdc39dc020047a533ac95f37e " POLYGON ((130828.773519741 190976.328483736, 130828.549833821 190978.863590837, 130843.238542611 190980.056582414, 130843.536790505 190977.67059926, 130828.773519741 190976.328483736))"^^ . -_:Baa56b3cfdc39dc020047a533ac95f37e . -_:B368a7f1117f860d95ac9ae37e79c50b4 " POLYGON ((71947.82537437545 169324.96504250076, 71942.42800153115 169323.85583334882, 71941.9222654997 169326.3026490705, 71947.31963594248 169327.4118571505, 71952.71700401718 169328.5210705325, 71953.22274485152 169326.07425695565, 71947.82537437545 169324.96504250076))"^^ . -_:B368a7f1117f860d95ac9ae37e79c50b4 . -_:B49e2cfe00910157904def2fb499f8cf4 "2021-02-07T07:00:00Z"^^ . -_:B49e2cfe00910157904def2fb499f8cf4 "2021-02-08T19:00:00Z"^^ . -_:B49e2cfe00910157904def2fb499f8cf4 . - . - . - "9197164"^^ . -_:B12e85cd42c81251e30d8a2ef1df9f25b "Gemeente Asse"^^ . -_:B12e85cd42c81251e30d8a2ef1df9f25b . -_:B12e85cd42c81251e30d8a2ef1df9f25b . -_:Bdae77f0e31c13f592e0cf7a0904ef9ee "Stad Mechelen"^^ . -_:Bdae77f0e31c13f592e0cf7a0904ef9ee . -_:Bdae77f0e31c13f592e0cf7a0904ef9ee . - "10590520"^^ . - _:B23deadd8ddb2b98c1d0a873ac05258d5 . - _:B25bdd7350edd64f8c051b2a0270da481 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:05:24.21Z"^^ . - "2021-01-06T13:22:08.703Z"^^ . - _:B4c192abbd0e67d102de8554e07abd262 . - . - "8660 De Panne, Zeedijk / Zeilweg 16 (verlenging EagleBe1236657): Openbare Werken"^^ . - _:B2cd3e5821b881512d27c7673618b8288 . - . - . - _:Bc27cbcdaaf5253d142b41d4fa46f97b8 . - "2021-01-06T13:22:08.703Z"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B0c39bad0f320c91f2380420e649403f1 . - "2021-01-06T13:32:52.887Z"^^ . - _:B6c22b03c4ccf6d0758e7390a411b45aa . - _:B233d8235e28f24fa9e720b1a818fcd22 . - _:B788add619ef1e97a79a04aab2f18e9f4 . - . - _:Be111c5d349d6bb08d9aa691d82d6fd92 . - "2021-01-06T18:05:17.96Z"^^ . - "10590504"^^ . - . - . - "2021-01-06T13:32:36.11Z"^^ . - "9600 Ronse - Spinstersstraat 14 - container"^^ . -_:B0124a7da98549c06fce1de016028fa69 "2021-01-13T23:00:00Z"^^ . -_:B0124a7da98549c06fce1de016028fa69 "2021-01-14T22:30:00Z"^^ . -_:B0124a7da98549c06fce1de016028fa69 . - _:B4065ba40b0720e7aaebb0b73b4c3193d . - . - "2021-01-06T18:05:10.94Z"^^ . - _:Bc02dcac7f8fa3b1424f1b3d8c1b50940 . - . - "10590493"^^ . - _:Bcef58f5944fdbfea27742ee59a6ad1b0 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "Voertuig Verhuis"^^ . - _:B9b6dc4ea64835b12f56a27d090596dab . - "2021-01-06T15:29:30.2Z"^^ . - . - _:Bca18ed5f789a175741c5261cabde0525 . - "2021-01-06T13:40:55.663Z"^^ . -_:B9b28b8b62803bb7a2c1b3ee468fc5f67 "https://gipod.vlaanderen.be"@nl-BE . -_:B9b28b8b62803bb7a2c1b3ee468fc5f67 "10590373"^^ . -_:B9b28b8b62803bb7a2c1b3ee468fc5f67 . -_:Baf7ac4e46099fd9916c1a91d223f64f1 "https://gipod.vlaanderen.be"@nl-BE . -_:Baf7ac4e46099fd9916c1a91d223f64f1 "10590366"^^ . -_:Baf7ac4e46099fd9916c1a91d223f64f1 . -_:Baa7ec2b64eb8f550188010191dd58cd1 " POLYGON ((63837.7557727201 204052.896724985, 63837.8449889903 204052.514942044, 63837.858008838 204052.123089725, 63837.7943319177 204051.736226691, 63837.6564052978 204051.369219873, 63837.449529421 204051.036173137, 63837.1816544112 204050.749885282, 63836.8630745548 204050.52135819, 63836.506032697 204050.359374029, 63836.1242497561 204050.270157759, 63835.7323974366 204050.257137911, 63835.3455344032 204050.320814831, 63834.9785275854 204050.458741451, 63834.6454808494 204050.665617328, 63834.3591929944 204050.933492338, 63834.1306659023 204051.252072194, 63833.9686817409 204051.609114052, 63827.6309139888 204070.24960744, 63827.5416977186 204070.631390381, 63827.528677871 204071.023242701, 63827.5923547912 204071.410105734, 63827.7302814111 204071.777112552, 63827.9371572879 204072.110159288, 63828.2050322977 204072.396447143, 63828.5236121541 204072.624974235, 63828.8806540119 204072.786958397, 63829.2624369528 204072.876174667, 63829.6542892723 204072.889194514, 63830.0411523057 204072.825517594, 63830.4081591235 204072.687590974, 63830.7412058595 204072.480715097, 63831.0274937145 204072.212840088, 63831.2560208067 204071.894260231, 63831.4180049681 204071.537218373, 63837.7557727201 204052.896724985))"^^ . -_:Baa7ec2b64eb8f550188010191dd58cd1 . -_:B83c964d0cc1a06705e777bfcf516da6b "Gemeente Hemiksem"^^ . -_:B83c964d0cc1a06705e777bfcf516da6b . -_:B83c964d0cc1a06705e777bfcf516da6b . - . - _:B9e3b8a7140e95a264a962e02368fa878 . - . -_:B2f1fd2bcf0cad9ce676210938b66bc27 "2021-01-08T06:00:00Z"^^ . -_:B2f1fd2bcf0cad9ce676210938b66bc27 "2021-01-15T18:00:00Z"^^ . -_:B2f1fd2bcf0cad9ce676210938b66bc27 . -_:Bf7a1a56d1445c31f31a15bf8db2bf100 "Gemeente Koksijde"^^ . -_:Bf7a1a56d1445c31f31a15bf8db2bf100 . -_:Bf7a1a56d1445c31f31a15bf8db2bf100 . -_:Bcf111921130256590d0fbc205e50303a "2021-01-07T05:00:00Z"^^ . -_:Bcf111921130256590d0fbc205e50303a "2021-01-07T18:00:00Z"^^ . -_:Bcf111921130256590d0fbc205e50303a . -_:Bef2381e732e6cc9746c3b7b442a85e7f "Stad Dendermonde"^^ . -_:Bef2381e732e6cc9746c3b7b442a85e7f . -_:Bef2381e732e6cc9746c3b7b442a85e7f . - . - _:B5bd820737d23d0da033932b4a3f7ff47 . - . -_:B53de1467045aa611a97540f9e496ce05 "Stad Turnhout"^^ . -_:B53de1467045aa611a97540f9e496ce05 . -_:B53de1467045aa611a97540f9e496ce05 . - . - . - "9197265"^^ . -_:Bc0261de661a39421e858a0ae410f99cc " POLYGON ((121383.312281293 204227.778692464, 121383.824065996 204225.845281897, 121395.424529394 204228.915990117, 121394.91274469 204230.849400683, 121383.312281293 204227.778692464))"^^ . -_:Bc0261de661a39421e858a0ae410f99cc . -_:Be2f45c5a405d04b9351b4748412721ac " POLYGON ((132918.24195278907 198112.2362116538, 132921.24802307258 198112.2263693437, 132921.31345860093 198132.21366461087, 132918.3073998679 198132.2235068828, 132918.24195278907 198112.2362116538))"^^ . -_:Be2f45c5a405d04b9351b4748412721ac . -_:B30ce14ae5fa5bd577d0830e54f1bb71b "Gemeente Koksijde"^^ . -_:B30ce14ae5fa5bd577d0830e54f1bb71b . -_:B30ce14ae5fa5bd577d0830e54f1bb71b . -_:B07d040bbaf2cbde532cca73f4cf46fc0 "2021-01-22T06:00:00Z"^^ . -_:B07d040bbaf2cbde532cca73f4cf46fc0 "2021-01-26T15:00:00Z"^^ . -_:B07d040bbaf2cbde532cca73f4cf46fc0 . -_:B5fa870dd2dc6d91b04aeb096d1b98c23 " POLYGON ((96327.29339168593 160297.49625064668, 96327.39612525977 160297.49880821566, 96327.49859184452 160297.50663939468, 96327.6005209097 160297.51972350798, 96327.70164334407 160297.5380260111, 96327.80169216597 160297.56149858216, 96327.90040322828 160297.59007924923, 96327.99751591583 160297.62369255416, 96328.09277383344 160297.66224975174, 96328.10401202955 160297.6671793245, 96334.3663943785 160300.4370792096, 96334.36723131921 160300.4372970579, 96334.52405321736 160300.48559181028, 96334.67638829738 160300.54657963075, 96334.82321113507 160300.61984998756, 96334.96353341115 160300.7049096706, 96335.09641056413 160300.80118611146, 96335.22094814834 160300.90803123754, 96335.33630785489 160301.0247258345, 96335.44171315459 160301.15048438744, 96335.5364545251 160301.28446036874, 96335.61989422694 160301.4257519361, 96335.69147059637 160301.5734080033, 96335.75070182617 160301.7264346424, 96335.79718920885 160301.88380177398, 96335.83061982052 160302.04445010124, 96335.85076862728 160302.20729824042, 96335.8575 160302.37125, 96335.8551096929 160302.4690023136, 96335.84794448518 160302.56652096912, 96335.8360215039 160302.66357286708, 96335.81936924861 160302.75992602363, 96335.79802752334 160302.85535012512, 96335.77204734138 160302.94961707864, 96335.74149080331 160303.0425015572, 96335.70643094866 160303.13378153843, 96335.66695158124 160303.2232388351, 96335.62314706887 160303.31065961684, 96335.57512211778 160303.3958349211, 96335.52299152236 160303.47856115273, 96335.46687989074 160303.55864057067, 96335.40692134693 160303.6358817605, 96335.3432592103 160303.71010009205, 96335.27604565288 160303.78111816075, 96335.20544133573 160303.84876621157, 96335.13161502483 160303.91288254492, 96335.05474318775 160303.97331390303, 96334.97500957179 160304.02991583644, 96334.89260476475 160304.08255304914, 96334.80772573948 160304.131099722, 96334.72057538286 160304.1754398136, 96334.63136201103 160304.2154673375, 96334.54029887135 160304.25108661558, 96334.44760363268 160304.28221250686, 96334.35349786512 160304.30877061092, 96334.25820651033 160304.33069744572, 96334.16195734392 160304.34794059937, 96334.06498043098 160304.3604588555, 96333.96750757609 160304.36822229152, 96333.8697717693 160304.37121235055, 96333.8575 160304.37125, 96333.795 160304.37125, 96333.69093735707 160304.36854090678, 96333.58715662955 160304.36042096635, 96333.48393896909 160304.34691217632, 96333.38156400195 160304.32805113334, 96333.28030907147 160304.3038889337, 96333.18044848669 160304.27449103503, 96333.08225277923 160304.239937079, 96332.98598797045 160304.2003206755, 96326.48598797045 160301.3253206755, 96326.4747802332 160301.32032223928, 96326.38660688099 160301.27805300293, 96326.3006048673 160301.23152471025, 96326.21697976334 160301.18084857808, 96326.1359314588 160301.126145738, 96326.05765368404 160301.06754694658, 96325.98233354694 160301.00519227292, 96325.91015108579 160300.93923076382, 96325.84127883881 160300.86982008757, 96325.77588143184 160300.79712615698, 96325.71411518476 160300.7213227329, 96325.65612773788 160300.64259100877, 96325.60205769898 160300.56111917758, 96325.55203431209 160300.47710198208, 96325.50617714845 160300.3907402491, 96325.46459582075 160300.3022404097, 96325.42738972117 160300.21181400577, 96325.39464778367 160300.11967718406, 96325.36644827157 160300.02605017996, 96325.34285859033 160299.93115679073, 96325.32393512657 160299.83522384072, 96325.30972311315 160299.73848063912, 96325.30025652116 160299.6411584319, 96325.29555797868 160299.54348984905, 96325.29563871663 160299.44570834842, 96325.30049854204 160299.34804765787, 96325.31012583846 160299.25074121644, 96325.32449759364 160299.15402161638, 96325.34357945473 160299.0581200473, 96325.36732581018 160298.9632657433, 96325.39567989892 160298.86968543538, 96325.42857394597 160298.77760280916, 96325.46592932448 160298.68723797044, 96325.52895791351 160298.55758320674, 96325.60116239841 160298.4328055118, 96325.68216762342 160298.31355319815, 96325.77155270644 160298.20044586982, 96325.86885322581 160298.09407120312, 96325.97356363329 160297.9949818931, 96326.08513988083 160297.9036927822, 96326.20300224722 160297.8206781848, 96326.32653835023 160297.74636942326, 96326.45510632836 160297.68115258656, 96326.5880381758 160297.62536652444, 96326.72464321321 160297.57930108684, 96326.86421167631 160297.54319561773, 96327.00601840361 160297.51723771179, 96327.14932660421 160297.50156223954, 96327.29339168593 160297.49625064668))"^^ . -_:B5fa870dd2dc6d91b04aeb096d1b98c23 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "Verhuiswagen"^^ . - "2021-01-06T17:11:43.167Z"^^ . - "2021-01-06T18:04:12.173Z"^^ . - _:Bd9618a16b393e48f0be7ba0fc74ce62e . - . - _:B097747e7f3b0c83434db8fcd0df9630a . - . - . - _:B03d19bae1a3213e4fef09ac6bab7f16b . - _:B62ca47ea90f2325137ab476fb29f6a95 . - . - "10590330"^^ . - _:B091813a480ec604ff0bb81fb3821d265 . - "2021-01-06T17:11:43.167Z"^^ . - . - _:B2428ca908693b2a06a36e020ac13b8cd . - "8700 Tielt, Nieuwstraat 22 bus 10: Verhuislift/Verhuiswagen"^^ . - _:B4a9c40f6d6c5839e85cac22f7e490d21 . - _:B205ccd1aac196f1e67116ff80182fdc5 . - "2021-01-06T15:40:25.597Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:27.133Z"^^ . - _:B273c08cfe90e6c30a274f729cc85b7d7 . - . - "2021-01-06T15:32:51.723Z"^^ . - . - . - _:B2b26a6cb95996137118fe5cc31aa8e66 . - "10590363"^^ . - . - . - _:B65bf02e9ffdb7e587fb868197d95fb00 . - . - . - . - "9197025"^^ . - . - _:Bec004dc9f2d430c6c5e2af72e0f55b64 . - _:B4e9e6ebb29887b478ee37897f7cf4dc0 . - "8000 Brugge, Boomgaardstraat: Doorlopende vergunning"^^ . - . - . - _:Bdb93f09f475997306ffe4e509792953e . - "2021-01-06T13:46:48.413Z"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B0768cfc7b5596b8384439c9f67febfa4 . - "10590584"^^ . - _:B329bbd0cd66334d7a9e7881ecb85634d . - "2021-01-06T18:05:41.41Z"^^ . - "2021-01-06T12:47:21.667Z"^^ . -_:Bf22c531d78edb483d385379ca85b8490 "https://gipod.vlaanderen.be"@nl-BE . -_:Bf22c531d78edb483d385379ca85b8490 "10590535"^^ . -_:Bf22c531d78edb483d385379ca85b8490 . - "Handelaars moeilijk bereikbaar"@nl-BE . -_:Bf803249d8839d273af3a8eacf516d597 "2021-02-02T23:00:00Z"^^ . -_:Bf803249d8839d273af3a8eacf516d597 "2021-02-06T22:30:00Z"^^ . -_:Bf803249d8839d273af3a8eacf516d597 . - . - . - "9196935"^^ . -_:Baefd00198bce6e80c82a6fba6594ad62 "2021-01-10T23:00:00Z"^^ . -_:Baefd00198bce6e80c82a6fba6594ad62 "2021-01-30T22:00:00Z"^^ . -_:Baefd00198bce6e80c82a6fba6594ad62 . - . - . - "9197038"^^ . - . - . - "9197332"^^ . -_:Bb725f1fd316a5bb77eee15276bc0ef08 " POLYGON ((155371.959164779 220203.287000242, 155372.573945528 220201.383833241, 155383.992947529 220205.072517733, 155383.736539303 220205.866276608, 155383.378166781 220206.975684734, 155371.959164779 220203.287000242))"^^ . -_:Bb725f1fd316a5bb77eee15276bc0ef08 . -_:B02a2e167c901548ad4294d439dd6905a "Stad Dendermonde"^^ . -_:B02a2e167c901548ad4294d439dd6905a . -_:B02a2e167c901548ad4294d439dd6905a . - . - "Voertuig Werken in opdracht van Proximus: aanleggen van ondergrondse leidingen.\nParkeerplaatsen om de voertuigen en doorgang te kunnen garanderen voor omstaanders en voertuigen."^^ . - "2021-01-06T13:14:42.28Z"^^ . - _:Bf4d73e4cc3def3229bb5e18f90d844c4 . - _:Bb9241c13d523c613db57dc309c836b23 . - _:B18eb15d95f42fdb7b892c279d5121640 . - _:B109ab38a98a8649687b300fd086ca7e2 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - "2021-01-06T13:12:13.387Z"^^ . - _:Ba31f6b6d271b130e5be071e94f957be6 . - "10590538"^^ . - . - "2021-01-06T18:05:29.04Z"^^ . - . -_:B4719964c44d8f257dde3f56d13ae8e7b " MULTIPOLYGON (((148650.702261962 203335.870344003, 148631.614396732 203352.572226079, 148647.123287231 203338.256327157, 148650.702261962 203335.870344003)), ((148813.545612204 203200.91317187, 148811.607000891 203204.939518442, 148810.414009315 203204.193898707, 148813.545612204 203200.91317187)))"^^ . -_:B4719964c44d8f257dde3f56d13ae8e7b . -_:B03b5b001c87f4911c5da18981c3c52f2 "Stad Kortrijk"^^ . -_:B03b5b001c87f4911c5da18981c3c52f2 . -_:B03b5b001c87f4911c5da18981c3c52f2 . -_:B052fae9cb6328933b4ed34ecfd2ace06 "2021-01-13T06:00:00Z"^^ . -_:B052fae9cb6328933b4ed34ecfd2ace06 "2021-01-15T21:00:00Z"^^ . -_:B052fae9cb6328933b4ed34ecfd2ace06 . -_:Bade44b89c57951fbfb70ebffa1d92b1a "Gemeente Heist-op-den-Berg"^^ . -_:Bade44b89c57951fbfb70ebffa1d92b1a . -_:Bade44b89c57951fbfb70ebffa1d92b1a . - . - _:B6e72aa41dcba691228c3b5432895cd59 . - . -_:Be1a330d7240da6a6bdef6a49eda146a4 "2021-01-11T06:00:00Z"^^ . -_:Be1a330d7240da6a6bdef6a49eda146a4 "2021-01-22T15:00:00Z"^^ . -_:Be1a330d7240da6a6bdef6a49eda146a4 . -_:Ba64c87db2d87a50214a4e84ec467a26d "Stad Lier"^^ . -_:Ba64c87db2d87a50214a4e84ec467a26d . -_:Ba64c87db2d87a50214a4e84ec467a26d . -_:B748bd33cb97bd5bf416bab7eb2f7abd6 "2021-01-31T06:00:00Z"^^ . -_:B748bd33cb97bd5bf416bab7eb2f7abd6 "2021-01-31T18:00:00Z"^^ . -_:B748bd33cb97bd5bf416bab7eb2f7abd6 . - . - "2021-01-06T18:05:24.447Z"^^ . - . - . - . - _:B98955608a81831bc9dbbb75075886221 . - _:Bebcc1fa52a1d5312b02f11a4df937f07 . - "2620 Hemiksem, Assestraat: Stelling"^^ . - _:B83c964d0cc1a06705e777bfcf516da6b . - "2021-01-06T13:25:00.66Z"^^ . - "10590521"^^ . - _:B7250640df6c41dfcd9794e74d7f98ec5 . - _:B25b38574c76efbd0f0dde29df5e9d16b . - "2021-01-06T13:21:57.14Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . -_:Bcef4d9041a362cb80642419ffa088e6a " POLYGON ((141277.750709413 210786.245681289, 141260.719187323 210773.530903359, 141259.306432702 210775.257601934, 141276.02401539 210788.12935184, 141277.750709413 210786.245681289))"^^ . -_:Bcef4d9041a362cb80642419ffa088e6a . -_:Bbbf4bd0e7c094b3f4e7f071c9b137c25 " POLYGON ((217478.37521590834 179687.61339238565, 217478.30203471967 179682.11763161328, 217475.7972752472 179682.1506348215, 217475.87045907113 179687.64639548957, 217475.94364266554 179693.1421504058, 217476.01682603077 179698.63789957203, 217478.5215775978 179698.6048966758, 217478.44839686758 179693.10914740525, 217478.37521590834 179687.61339238565))"^^ . -_:Bbbf4bd0e7c094b3f4e7f071c9b137c25 . -_:B6be66f55fac59bc1acbc557fc370a22c "Stad Ronse"^^ . -_:B6be66f55fac59bc1acbc557fc370a22c . -_:B6be66f55fac59bc1acbc557fc370a22c . -_:B8737e2cd0c2fda45ef64e8dafe35d223 " POLYGON ((79042.5685391235 175465.173343506, 79042.5108949647 175464.58807254, 79042.3401777211 175464.025293209, 79042.0629479604 175463.506632807, 79041.6898594671 175463.052023162, 79041.2352498226 175462.678934669, 79040.7165894206 175462.401704908, 79040.1538100896 175462.230987665, 79039.5685391235 175462.173343506, 79038.9832681575 175462.230987665, 79038.4204888264 175462.401704908, 79037.9018284245 175462.678934669, 79037.44721878 175463.052023162, 79037.0741302866 175463.506632807, 79036.796900526 175464.025293209, 79036.6261832823 175464.58807254, 79036.5685391235 175465.173343506, 79036.6261832823 175465.758614472, 79036.796900526 175466.321393803, 79037.0741302866 175466.840054205, 79037.44721878 175467.294663849, 79037.9018284245 175467.667752343, 79038.4204888264 175467.944982103, 79038.9832681575 175468.115699347, 79039.5685391235 175468.173343506, 79040.1538100896 175468.115699347, 79040.7165894206 175467.944982103, 79041.2352498226 175467.667752343, 79041.6898594671 175467.294663849, 79042.0629479604 175466.840054205, 79042.3401777211 175466.321393803, 79042.5108949647 175465.758614472, 79042.5685391235 175465.173343506))"^^ . -_:B8737e2cd0c2fda45ef64e8dafe35d223 . - . - . - "9197118"^^ . - "Geen doorgang voor fietsers"@nl-BE . - . - . - "9197185"^^ . -_:Bbfa37d5dcd48ffe704d7341f29e4e6e8 "2021-01-17T23:00:00Z"^^ . -_:Bbfa37d5dcd48ffe704d7341f29e4e6e8 "2021-01-18T22:30:00Z"^^ . -_:Bbfa37d5dcd48ffe704d7341f29e4e6e8 . -_:B05f03d7343018fbc06975dbfaef5599f "Gemeente Tervuren"^^ . -_:B05f03d7343018fbc06975dbfaef5599f . -_:B05f03d7343018fbc06975dbfaef5599f . - "2021-01-06T14:29:43.687Z"^^ . - _:Bacffa69584d2f4cd98a2cec77c33e603 . - . - "2021-01-06T14:29:43.687Z"^^ . - _:B767244b5d4c1537596d769a39a81e810 . - . - _:B2f8cdac853c594488761e0251eaf57a6 . - . - _:B53c5097a2f61ccdea461bd3a0b6eee4b . - "Wegeniswerken"^^ . - "2021-01-06T18:04:51.343Z"^^ . - . - "10590438"^^ . - _:B7c0ed1c3584c0d78ebeec31effb614b6 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . -_:B7a06567d7b71f145186e4e8d37238a77 "2020-12-07T00:00:00Z"^^ . -_:B7a06567d7b71f145186e4e8d37238a77 "2021-01-18T00:00:00Z"^^ . -_:B7a06567d7b71f145186e4e8d37238a77 . -_:Bb9ce466731e03620a44caefb4d8cbb8b " POLYGON ((133036.651419267 190738.774035993, 133039.037402421 190744.291622036, 133043.511120834 190742.651258617, 133040.826889786 190736.984548627, 133036.651419267 190738.774035993))"^^ . -_:Bb9ce466731e03620a44caefb4d8cbb8b . -_:B8b9256c0063bcf4e2c812bde90c14b42 "https://gipod.vlaanderen.be"@nl-BE . -_:B8b9256c0063bcf4e2c812bde90c14b42 "10590392"^^ . -_:B8b9256c0063bcf4e2c812bde90c14b42 . -_:Be96f5019eabec8493e13c44654a5e25e "https://gipod.vlaanderen.be"@nl-BE . -_:Be96f5019eabec8493e13c44654a5e25e "10590581"^^ . -_:Be96f5019eabec8493e13c44654a5e25e . -_:B089c7f3c53964b2f76adb504bd359e4a "2021-01-15T06:00:00Z"^^ . -_:B089c7f3c53964b2f76adb504bd359e4a "2021-01-15T16:00:00Z"^^ . -_:B089c7f3c53964b2f76adb504bd359e4a . -_:Ba5eba5d0622c35a9453df2d21e64b6e3 "https://gipod.vlaanderen.be"@nl-BE . -_:Ba5eba5d0622c35a9453df2d21e64b6e3 "10590367"^^ . -_:Ba5eba5d0622c35a9453df2d21e64b6e3 . -_:B3df20dbe98b47690d58965cfd3d58132 "Politiezone Leuven"^^ . -_:B3df20dbe98b47690d58965cfd3d58132 . -_:B3df20dbe98b47690d58965cfd3d58132 . - . - . - "9197273"^^ . -_:B3568fbe4d682666665932ca93847bed2 "Stad Mechelen"^^ . -_:B3568fbe4d682666665932ca93847bed2 . -_:B3568fbe4d682666665932ca93847bed2 . - . - _:B5daf0259cc7670a34548691ecbbe3d9f . - . - . - _:Bbd28b54854cecdf22750b6f12c599f61 . - . - . - _:B699087a36a9a05b2de41551dab9596a9 . - . - . - _:B2ad3a31d2b10d3f1a056dc56d81b14ee . - . - . - _:Ba0e97f72420be8d0e6062006fd8fc687 . - . -_:B0f2517b39960535cb3cee38b90f4297d "Stad Lier"^^ . -_:B0f2517b39960535cb3cee38b90f4297d . -_:B0f2517b39960535cb3cee38b90f4297d . -_:B8971e76f175d56203b5eacef190d4dc9 "Gemeente Bornem"^^ . -_:B8971e76f175d56203b5eacef190d4dc9 . -_:B8971e76f175d56203b5eacef190d4dc9 . -_:B9c1a589d1f2b2b1eae00b53b15a07645 "Gemeente Tessenderlo"^^ . -_:B9c1a589d1f2b2b1eae00b53b15a07645 . -_:B9c1a589d1f2b2b1eae00b53b15a07645 . -_:B0008ed5f728bb5452d9b7be214d97aed " POLYGON ((133873.1286121877 207035.84371021125, 133873.83547799505 207037.7146299665, 133856.99720019777 207044.07642223148, 133856.29033439042 207042.20550247622, 133873.1286121877 207035.84371021125))"^^ . -_:B0008ed5f728bb5452d9b7be214d97aed . - . - _:B684ad70c617f15e86d92c5859f951fee . - . - . - . - _:B234d77df8372d53e841ee55caae75d23 . - . -_:B303014beaec855cbb8505e361aaaacce "https://gipod.vlaanderen.be"@nl-BE . -_:B303014beaec855cbb8505e361aaaacce "10590440"^^ . -_:B303014beaec855cbb8505e361aaaacce . - . - . - "9197046"^^ . -_:Be1e221795f65ef118d1a9c054c667f4d "Politiezone Leuven"^^ . -_:Be1e221795f65ef118d1a9c054c667f4d . -_:Be1e221795f65ef118d1a9c054c667f4d . - "10590469"^^ . - . - "2021-01-06T18:05:03.313Z"^^ . - _:B9238c6d216e37761d86c833d0ca89583 . - _:B232b35ff7aa28024e17a9b8b22e52546 . - "2021-01-06T13:58:32.317Z"^^ . - . - "3700 Tongeren, Hemelingenstraat 56-58: Voertuig"^^ . - _:B050acb5acec8337e282f52d3f8d7add7 . - "2021-01-06T14:06:26.563Z"^^ . - . - _:Bfddb67940b887bf8a545b36d7fcb1694 . - _:B8ae71616b81e940d4c871b1ce7c84b2c . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B6704d176f24e81d604062b456c5b821c . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B26c4301a91aad795fded7c2e6ba1cf3b . - _:B84fcc60a8a2dc896daf705cca3505ea1 . - "2021-01-06T15:58:24.84Z"^^ . - "10590352"^^ . - _:B88872278f61b6228cb6dc33522005059 . - "8770 Ingelmunster, Waterstraat 4: Parkeerverbod"^^ . - . - . - "2021-01-06T18:04:20.217Z"^^ . - . - "2021-01-06T15:58:24.84Z"^^ . - . - _:B58210a9e828a4af42d5c001669f25991 . -_:B90957ccea685a12c61253aaa65f64370 "Politiezone Brugge"^^ . -_:B90957ccea685a12c61253aaa65f64370 . -_:B90957ccea685a12c61253aaa65f64370 . -_:B1a605cebe5af4bdcbecafa42d82c1af5 "2021-01-14T08:00:00Z"^^ . -_:B1a605cebe5af4bdcbecafa42d82c1af5 "2021-01-14T14:00:00Z"^^ . -_:B1a605cebe5af4bdcbecafa42d82c1af5 . -_:B3ce3c3cb6eb197c4b2c7afd7716bc7f4 " POLYGON ((143078.17249827966 174842.65664925426, 143072.66159119786 174842.66390139516, 143072.66488012316 174845.16215703264, 143078.17578457008 174845.15490489453, 143078.17249827966 174842.65664925426))"^^ . -_:B3ce3c3cb6eb197c4b2c7afd7716bc7f4 . -_:B80f7698cc4a53b775869eaceb67223db "Gemeente Bornem"^^ . -_:B80f7698cc4a53b775869eaceb67223db . -_:B80f7698cc4a53b775869eaceb67223db . - . - . - "9196969"^^ . - _:B376b4457288c1eeae159bc0ed93f3822 . - "Container"^^ . - _:Bceff1f3db91b0e0beb2ab62e34155d3d . - "10590399"^^ . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:39.643Z"^^ . - _:B50dd1fd9dac0c1d421d3e7b5941db999 . - _:B85ec7901826d41ae789470c0445262b8 . - . - _:Bd82a1117a1c47af35064455d0fed52d3 . - "2021-01-06T14:52:41.627Z"^^ . - "2021-01-06T14:58:07.62Z"^^ . - . -_:B9105ba7bc9b454c424def620f55e8060 "Gemeente Tessenderlo"^^ . -_:B9105ba7bc9b454c424def620f55e8060 . -_:B9105ba7bc9b454c424def620f55e8060 . - . - . - "9197345"^^ . - . - . - "9197113"^^ . -_:B6a4ba624fb7db4cc094fdb2c8f3c8ab7 "Gemeente Asse"^^ . -_:B6a4ba624fb7db4cc094fdb2c8f3c8ab7 . -_:B6a4ba624fb7db4cc094fdb2c8f3c8ab7 . - "2021-01-06T18:04:30.21Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "Koning Boudewijnlaan 24: Werken in voetpad iov Fluvius"^^ . - "2021-01-06T15:22:26.913Z"^^ . - _:B6ea3bf49a1f6bde11ee6074771b4a3e0 . - "2021-01-06T15:24:23.837Z"^^ . - "10590370"^^ . - _:B24449f06eee39b22196402f9bf86a933 . - _:B83957ea2aa5de8738e11fe87532433ff . - _:Bef2381e732e6cc9746c3b7b442a85e7f . - . - . - _:B62f97f59f85fa5e70e191ddc2389a84d . - . - . - "10590591"^^ . - _:Bd38799674605a26821edf7386b02591f . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T12:42:50.027Z"^^ . - "2021-01-06T18:05:43.197Z"^^ . - . - _:B4c62b2bc2c77e81bf293fc8a223d111a . - _:B3f1292c5c6e3ee5f31041149291cfdf7 . - "2021-01-06T12:42:50.027Z"^^ . - . - . - _:B10ee9f7864f928e1efe560ab563bfcf3 . - _:B1c50cfe5f97d54aaac1dd3937addbb82 . - "9120 Beveren, Bijlstraat 133: Wegenwerken (4-3b)"^^ . - . -_:Bb78c619c91dd4508a71b03326eefd0c0 "Stad Ronse"^^ . -_:Bb78c619c91dd4508a71b03326eefd0c0 . -_:Bb78c619c91dd4508a71b03326eefd0c0 . - . - . - _:Bdaf4a1dcff3de3b14e47d2a0a3edf153 . - . -_:B11dbd9d0101f134b49d9089ecbb67f0d "Stad Ninove"^^ . -_:B11dbd9d0101f134b49d9089ecbb67f0d . -_:B11dbd9d0101f134b49d9089ecbb67f0d . -_:Bf7dfda4f642fe6ab8fb249d2cfe7cf6b "Gemeente Asse"^^ . -_:Bf7dfda4f642fe6ab8fb249d2cfe7cf6b . -_:Bf7dfda4f642fe6ab8fb249d2cfe7cf6b . -_:B0129b437a37beb381d231ac2959a2986 "https://gipod.vlaanderen.be"@nl-BE . -_:B0129b437a37beb381d231ac2959a2986 "10590518"^^ . -_:B0129b437a37beb381d231ac2959a2986 . -_:Bf9b4828d0f0775512a1db73b0f70aa30 "Gemeente Zedelgem"^^ . -_:Bf9b4828d0f0775512a1db73b0f70aa30 . -_:Bf9b4828d0f0775512a1db73b0f70aa30 . -_:B054f47eba38f668342fe128caa4e8ee8 "Stad Mechelen"^^ . -_:B054f47eba38f668342fe128caa4e8ee8 . -_:B054f47eba38f668342fe128caa4e8ee8 . - . - . - _:Bf3e793f4c4c6bbffc83127a4e5ecaabc . - . -_:Bfe648790bda1c41f2143f751aee80a35 "2021-01-14T06:00:00Z"^^ . -_:Bfe648790bda1c41f2143f751aee80a35 "2021-01-14T17:00:00Z"^^ . -_:Bfe648790bda1c41f2143f751aee80a35 . - "Wisselend verkeer via verkeerslichten"@nl-BE . -_:B376b4457288c1eeae159bc0ed93f3822 "Stad Izegem"^^ . -_:B376b4457288c1eeae159bc0ed93f3822 . -_:B376b4457288c1eeae159bc0ed93f3822 . -_:B94c26eb56aedccf2b7f68faf84efe2bd "Politiezone Brugge"^^ . -_:B94c26eb56aedccf2b7f68faf84efe2bd . -_:B94c26eb56aedccf2b7f68faf84efe2bd . - "2021-01-06T14:19:11.123Z"^^ . - _:B7e4588eab28352a074b617dc4f12e3e9 . - _:B1d62eafd52a7793019a580d3051c6701 . - _:B39fdc655ba17cd3685e22bc45db6858b . - "2021-01-06T18:04:54.59Z"^^ . - . - "2021-01-06T14:36:27.88Z"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B79fddffe33871c86585cabd79de3583c . - . - . - _:Bff665acc76cabc37a2bcbe923a20ec37 . - "9300 Aalst, Bergemeersenstraat 59: Vrachtwagen levering meubelen. Inname 3 parkeerplaatsen (18x2m)"^^ . - "10590447"^^ . -_:Bee96dfbd126d199414a65f9c233c1ec3 " POLYGON ((100166.40614857 180257.746537446, 100164.616661205 180257.597413499, 100164.914909099 180256.255297975, 100180.274675651 180257.448289552, 100180.423799598 180259.386900864, 100166.40614857 180257.746537446))"^^ . -_:Bee96dfbd126d199414a65f9c233c1ec3 . - _:Bd91cdc624e9b5fb860c6340311cc86c8 . - "2021-01-06T14:22:00.49Z"^^ . - . - _:B00b97a7cdf667cf216efb0ad7a497599 . - "10590460"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B912ebcb729714aed1f9d10b1da9a5d33 . - . - "2021-01-06T14:10:39.96Z"^^ . - . - "2021-01-06T18:05:00.03Z"^^ . - _:B22b9c7378a16619f0b8473854e40005e . - _:B001ca1373f2a690417871225cdb2a99c . - "8200 Brugge, Albert Serreynstraat 10: Inname openbaar domein met lichte hinder"^^ . -_:B8bf5afe00720df6b184456687fe18262 " POLYGON ((178000.725780457 197251.076453052, 178006.452143667 197252.269444629, 178010.508307747 197236.283355679, 178004.543349862 197236.283355679, 178000.725780457 197251.076453052))"^^ . -_:B8bf5afe00720df6b184456687fe18262 . -_:B0e69fc45882de35840c4393147f63ab0 "Gemeente Middelkerke"^^ . -_:B0e69fc45882de35840c4393147f63ab0 . -_:B0e69fc45882de35840c4393147f63ab0 . - . - . - . - _:Bdadb49a628b919297dda7e478ea1d458 . - . - . - . - . - _:B1d3fc62a8603e7d996cae306f0c10d01 . - . -_:Ba4658017497ea6a3d89fea3326be3b24 "Stad Sint-Niklaas"^^ . -_:Ba4658017497ea6a3d89fea3326be3b24 . -_:Ba4658017497ea6a3d89fea3326be3b24 . -_:B9b6dc4ea64835b12f56a27d090596dab "2021-01-11T23:00:00Z"^^ . -_:B9b6dc4ea64835b12f56a27d090596dab "2021-01-12T22:30:00Z"^^ . -_:B9b6dc4ea64835b12f56a27d090596dab . - . - _:B2f6c422e5d3f94a21729598037f8ca19 . - . -_:B13a02aedc9a75b04ea57efaba1fe173e " POLYGON ((191277.59842452544 223896.89796962216, 191287.68316856114 223898.47046781704, 191302.22847318387 223809.81371085625, 191291.7576881526 223809.73007204384, 191277.59842452544 223896.89796962216))"^^ . -_:B13a02aedc9a75b04ea57efaba1fe173e . -_:Be66e17cf4c25f17bf8a94960a945b012 " POLYGON ((70414.346701031 211760.088774863, 70398.8711444896 211777.647579401, 70398.8196756723 211777.70837585, 70381.9838265911 211798.417960118, 70371.5607507835 211810.627848921, 70371.3366492372 211810.949557257, 70371.1796159223 211811.308804101, 70371.0956855409 211811.691783798, 70371.0880834906 211812.083778652, 70371.1571019138 211812.469724521, 70371.3000884713 211812.834789722, 70371.5115482699 211813.164945004, 70371.783355028 211813.447502685, 70372.1050633645 211813.671604232, 70372.4643102083 211813.828637546, 70372.8472899047 211813.912567928, 70373.2392847587 211813.920169978, 70373.625230628 211813.851151555, 70373.9902958293 211813.708164997, 70374.3204511115 211813.496705199, 70374.6030087923 211813.224898441, 70385.0416850899 211800.996734778, 70385.0724425218 211800.959815538, 70401.8983196149 211780.262497698, 70417.380870227 211762.695757581, 70417.4455902908 211762.618483731, 70449.3581149719 211722.504141959, 70449.570953736 211722.174873956, 70449.7154658623 211721.810409963, 70449.7860978309 211721.424756127, 70449.7801352948 211721.032732907, 70449.6978073909 211720.649405536, 70449.5422779345 211720.289505071, 70449.3195238354 211719.966862284, 70449.0381054085 211719.693876156, 70448.7088374063 211719.481037392, 70448.3443734134 211719.336525266, 70447.9587195766 211719.265893297, 70447.5666963567 211719.271855833, 70447.1833689862 211719.354183737, 70446.8234685208 211719.509713194, 70446.5008257337 211719.732467293, 70446.2278396062 211720.01388572, 70414.346701031 211760.088774863))"^^ . -_:Be66e17cf4c25f17bf8a94960a945b012 . -_:Ba3976bbcb1913c8428a32146b3f7f9d9 "https://gipod.vlaanderen.be"@nl-BE . -_:Ba3976bbcb1913c8428a32146b3f7f9d9 "10590339"^^ . -_:Ba3976bbcb1913c8428a32146b3f7f9d9 . - _:Bc049830191c39214aa5a49f5c0b1f660 . - "Theodoor Vermylenstraat 20: werken in voetpad iov Fluvius"^^ . - "10590366"^^ . - _:B47969c03b0a9f0cddcb74ec738ac9629 . - "2021-01-06T18:04:28.593Z"^^ . - _:Baf7ac4e46099fd9916c1a91d223f64f1 . - _:B4c36cf2deeb3df6a604c600bed7bf38e . - _:B07d040bbaf2cbde532cca73f4cf46fc0 . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - "2021-01-06T15:30:41.657Z"^^ . - "2021-01-06T15:28:58.267Z"^^ . -_:Bfeb4e2a8976e8d9f99aa826242fe6e41 "Gemeente Beveren"^^ . -_:Bfeb4e2a8976e8d9f99aa826242fe6e41 . -_:Bfeb4e2a8976e8d9f99aa826242fe6e41 . -_:Bde9543222a08124bf455d729c055d030 " MULTIPOLYGON (((173180.32596535218 179445.19594726898, 173183.59598043514 179448.98150094226, 173179.8003708746 179452.24269131292, 173176.53035510323 179448.4571423754, 173180.32596535218 179445.19594726898)), ((173194.6406663478 179433.99641735293, 173197.67285470353 179437.9740092419, 173193.68468727858 179440.99800369237, 173190.65249766127 179437.0204164153, 173194.6406663478 179433.99641735293)), ((173209.28783285816 179424.89264251664, 173211.99775399457 179429.09524008073, 173207.78397095425 179431.79782296717, 173205.07404784823 179427.5952297598, 173209.28783285816 179424.89264251664)), ((173214.93048769044 179411.07018947508, 173217.5521969204 179415.2196801901, 173172.53917873604 179444.3599861255, 173169.5402864231 179440.20886370074, 173186.19316735555 179429.51830346324, 173185.94635706858 179429.1125841858, 173190.22962623404 179426.520918509, 173190.4073029139 179426.8129929863, 173214.93048769044 179411.07018947508)), ((173251.67118191236 179399.34213536046, 173254.23235836515 179403.6365119815, 173249.92654704445 179406.1907451898, 173247.36536832177 179401.89637277927, 173251.67118191236 179399.34213536046)))"^^ . -_:Bde9543222a08124bf455d729c055d030 . -_:B49ed45c5e9dd746503df8219b6274672 "Gemeente Zedelgem"^^ . -_:B49ed45c5e9dd746503df8219b6274672 . -_:B49ed45c5e9dd746503df8219b6274672 . -_:B14c3cf74630fe09b6d0a8e450dc94d68 "https://gipod.vlaanderen.be"@nl-BE . -_:B14c3cf74630fe09b6d0a8e450dc94d68 "10590531"^^ . -_:B14c3cf74630fe09b6d0a8e450dc94d68 . - . - . - "9196964"^^ . -_:B4babbc3b5bf82c76672aa56c1170400b "Gemeente Sint-Lievens-Houtem"^^ . -_:B4babbc3b5bf82c76672aa56c1170400b . -_:B4babbc3b5bf82c76672aa56c1170400b . - . - . - "9197067"^^ . - . - _:B797eb69a758ef5685769affe866fab48 . - "2021-01-06T12:50:10.47Z"^^ . - "10590581"^^ . - . - _:B524d26653889ac657c519464212d5b24 . - . - _:Bf0319fa96cbfb0aa6809d755de1197f4 . - _:B845d12fc54b42407c913b55f904e1e53 . - "2800 Mechelen, Onze-Lieve-Vrouwekerkhof 5: Container"^^ . - . - "2021-01-06T18:05:40.777Z"^^ . - "2021-01-06T12:50:10.47Z"^^ . - _:Be96f5019eabec8493e13c44654a5e25e . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - "9197361"^^ . -_:B47969c03b0a9f0cddcb74ec738ac9629 "Stad Dendermonde"^^ . -_:B47969c03b0a9f0cddcb74ec738ac9629 . -_:B47969c03b0a9f0cddcb74ec738ac9629 . -_:Bf3e793f4c4c6bbffc83127a4e5ecaabc " POLYGON ((166965.21623117052 198275.24876145273, 166970.09214526645 198278.16948159877, 167024.76431734939 198194.57819569204, 167021.86318922893 198191.10163559485, 166965.21623117052 198275.24876145273))"^^ . -_:Bf3e793f4c4c6bbffc83127a4e5ecaabc . -_:Bf40cc6df4eb23104e9a12f612bd870a5 "Stad Hasselt"^^ . -_:Bf40cc6df4eb23104e9a12f612bd870a5 . -_:Bf40cc6df4eb23104e9a12f612bd870a5 . -_:Bc857560bb6686086619e59d1fbe06552 " POLYGON ((41070.2168573509 209562.509035296, 41071.5416555115 209560.388915056, 41081.7182326653 209566.747946227, 41080.3934345047 209568.868066467, 41070.2168573509 209562.509035296))"^^ . -_:Bc857560bb6686086619e59d1fbe06552 . -_:B549b0d4c02a08455f7214273a5a2bba5 "2021-01-19T06:00:00Z"^^ . -_:B549b0d4c02a08455f7214273a5a2bba5 "2021-01-24T18:00:00Z"^^ . -_:B549b0d4c02a08455f7214273a5a2bba5 . -_:B97402900c6591564bf5f9b523210c9ae "Gemeente Ranst"^^ . -_:B97402900c6591564bf5f9b523210c9ae . -_:B97402900c6591564bf5f9b523210c9ae . -_:B319b035f61155439460c9b744d8ed1c7 "Gemeente Borsbeek"^^ . -_:B319b035f61155439460c9b744d8ed1c7 . -_:B319b035f61155439460c9b744d8ed1c7 . - . - . - "9197353"^^ . -_:B8fbba5a8ccd752ce1c9c7cc4bf22ac33 "Gemeente Hooglede"^^ . -_:B8fbba5a8ccd752ce1c9c7cc4bf22ac33 . -_:B8fbba5a8ccd752ce1c9c7cc4bf22ac33 . -_:B0acc8fb377efd68aab75543c706628a6 "Politiezone Leuven"^^ . -_:B0acc8fb377efd68aab75543c706628a6 . -_:B0acc8fb377efd68aab75543c706628a6 . -_:B1ce63bebb2a0abf1548df2eaa63d5b82 "Stad Turnhout"^^ . -_:B1ce63bebb2a0abf1548df2eaa63d5b82 . -_:B1ce63bebb2a0abf1548df2eaa63d5b82 . -_:Bea65a3690ae1001172d9ce48a82f44df "2021-01-11T06:00:00Z"^^ . -_:Bea65a3690ae1001172d9ce48a82f44df "2021-01-11T21:00:00Z"^^ . -_:Bea65a3690ae1001172d9ce48a82f44df . -_:B47e6828cb4b75c4930e86a801602c4d1 "Stad Aalst"^^ . -_:B47e6828cb4b75c4930e86a801602c4d1 . -_:B47e6828cb4b75c4930e86a801602c4d1 . - . - _:B2f078c9a786f4349ac56cb65aad30cb1 . - . -_:Bb351de16d2028c7538c8c7d8c37682e4 " POLYGON ((76968.6402001585 188159.839406189, 76971.384084426 188152.741107672, 76973.6507702424 188153.814797361, 76970.7875886376 188160.555201591, 76968.6402001585 188159.839406189))"^^ . -_:Bb351de16d2028c7538c8c7d8c37682e4 . -_:B8ba383de2aaf55e236b33edfdcb23bfa "Stad Sint-Niklaas"^^ . -_:B8ba383de2aaf55e236b33edfdcb23bfa . -_:B8ba383de2aaf55e236b33edfdcb23bfa . - . - . - "9197126"^^ . -_:B7287ebd16c0effc733bbab41dad55fbf "2021-01-15T06:00:00Z"^^ . -_:B7287ebd16c0effc733bbab41dad55fbf "2021-02-05T17:00:00Z"^^ . -_:B7287ebd16c0effc733bbab41dad55fbf . -_:B6470b2e30fe79019e6f213303d3c9c11 "Politiezone Leuven"^^ . -_:B6470b2e30fe79019e6f213303d3c9c11 . -_:B6470b2e30fe79019e6f213303d3c9c11 . -_:B845d12fc54b42407c913b55f904e1e53 "2021-01-09T06:00:00Z"^^ . -_:B845d12fc54b42407c913b55f904e1e53 "2021-09-30T16:00:00Z"^^ . -_:B845d12fc54b42407c913b55f904e1e53 . - . - _:B368a7f1117f860d95ac9ae37e79c50b4 . - . -_:B5c1cfface6721055632727e33dc62f18 "2021-01-13T06:00:00Z"^^ . -_:B5c1cfface6721055632727e33dc62f18 "2021-01-19T15:00:00Z"^^ . -_:B5c1cfface6721055632727e33dc62f18 . -_:B3a65f94be4764d7596a634d1d42278ce "Gemeente Ingelmunster"^^ . -_:B3a65f94be4764d7596a634d1d42278ce . -_:B3a65f94be4764d7596a634d1d42278ce . -_:Be27c4de21f3486f879630c45129d96ad "2021-01-26T07:00:00Z"^^ . -_:Be27c4de21f3486f879630c45129d96ad "2021-01-26T22:30:00Z"^^ . -_:Be27c4de21f3486f879630c45129d96ad . -_:Ba3d67d4a20f41eaa99abe3cb6ffa55a3 "Stad Hasselt"^^ . -_:Ba3d67d4a20f41eaa99abe3cb6ffa55a3 . -_:Ba3d67d4a20f41eaa99abe3cb6ffa55a3 . -_:Bca5e765fd113d3a3e8bbc6be9c7b720d " MULTIPOLYGON (((130179.299 191704.676, 130179.695 191705.262, 130164.967 191781.491, 130146.697 191865.022, 130143.368 191882.771, 130156.568 191882.771, 130204.017 191880.117, 130204.545 191880.616, 130204.073 191881.115, 130156.61 191883.77, 130156.582 191883.771, 130142.766 191883.771, 130142.275 191883.179, 130145.716 191864.83, 130145.719 191864.815, 130163.986 191781.295, 130178.713 191705.072, 130179.299 191704.676)), ((130117.055 191683.253, 130118.05 191683.325, 130118.049 191683.361, 130118.045 191683.397, 130111.475 191728.578, 130110.908 191729.001, 130110.485 191728.434, 130117.055 191683.253)), ((130057.38 191598.728, 130057.832 191599.272, 130056.409 191614.842, 130059.156 191631.595, 130067.497 191649.436, 130079.345 191664.324, 130096.448 191675.582, 130119.654 191681.807, 130182.861 191691.63, 130183.284 191692.124, 130182.707 191692.618, 130119.474 191682.791, 130119.448 191682.786, 130119.421 191682.78, 130096.111 191676.527, 130095.966 191676.462, 130078.728 191665.116, 130078.612 191665.009, 130066.678 191650.012, 130066.616 191649.913, 130058.221 191631.956, 130058.181 191631.825, 130055.412 191614.941, 130055.407 191614.814, 130056.836 191599.18, 130057.38 191598.728)))"^^ . -_:Bca5e765fd113d3a3e8bbc6be9c7b720d . - "2021-01-06T13:17:11.537Z"^^ . - _:B350c7f0abc650b45fba3af67a9021cf9 . - . - "2021-01-06T13:17:11.537Z"^^ . - . - "10590532"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B54601af375152e3e62fe87126907b81b . - "2021-01-06T18:05:27.383Z"^^ . - . - "8000 Brugge, Landjuwelenstraat 35: Inname openbaar domein met lichte hinder"^^ . - _:Bcc4d4a3eaa26248c013f1feb70cea61e . - . - _:B25589f7b3c1e4c70c309c70532337bb7 . - _:B314af7fb2e14261df9489ba0c801880f . - . - _:B8960eb842c90fbcc78959fa71e484da6 . - . - . - . - "9197214"^^ . - . - _:B56d6c510e010c63592df767533b5dc67 . - . -_:B602ef67f7648ab07568212d6e3e3c891 "2021-01-18T06:00:00Z"^^ . -_:B602ef67f7648ab07568212d6e3e3c891 "2021-01-22T15:00:00Z"^^ . -_:B602ef67f7648ab07568212d6e3e3c891 . -_:B861031f27c23c1be79e8e39f7982eedc "2021-01-12T05:00:00Z"^^ . -_:B861031f27c23c1be79e8e39f7982eedc "2021-01-12T19:00:00Z"^^ . -_:B861031f27c23c1be79e8e39f7982eedc . -_:B83bdbf9c3300f1f5769bdf6663042192 "2021-01-14T23:00:00Z"^^ . -_:B83bdbf9c3300f1f5769bdf6663042192 "2021-01-18T22:30:00Z"^^ . -_:B83bdbf9c3300f1f5769bdf6663042192 . -_:Bf266a50528ceb0a7c12262a1a1185b97 "2021-01-11T06:00:00Z"^^ . -_:Bf266a50528ceb0a7c12262a1a1185b97 "2021-01-22T15:00:00Z"^^ . -_:Bf266a50528ceb0a7c12262a1a1185b97 . - . - . - . - _:B8737e2cd0c2fda45ef64e8dafe35d223 . - . - _:B19da948e16c0b0070aec46aaf0de492a . - "2021-01-06T15:03:11.613Z"^^ . - _:B87d0721a98b0c09191544d5ffb819183 . - "2021-01-06T18:04:34.947Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "Kraan Ruiming van puin van riolen, bermen en grachten in naam van Stad Kortrijk."^^ . - _:Ba026b1c494721a683b3b512c36ae0be7 . - . - _:B187b1c8aec3d87351270e04c56456afa . - . - "2021-01-06T15:28:52.57Z"^^ . - . - . - _:B6a7c202cef47f44b7fd913ec41c56e6b . - "10590383"^^ . -_:B30c6e021ccad7731b1dc78be1815f3ef "https://gipod.vlaanderen.be"@nl-BE . -_:B30c6e021ccad7731b1dc78be1815f3ef "10590514"^^ . -_:B30c6e021ccad7731b1dc78be1815f3ef . -_:B7035fb41f08094e3157166f72bb7d032 "https://gipod.vlaanderen.be"@nl-BE . -_:B7035fb41f08094e3157166f72bb7d032 "10590508"^^ . -_:B7035fb41f08094e3157166f72bb7d032 . -_:B0a97a86dbcde233959b00b6c917a70b0 "https://gipod.vlaanderen.be"@nl-BE . -_:B0a97a86dbcde233959b00b6c917a70b0 "10590477"^^ . -_:B0a97a86dbcde233959b00b6c917a70b0 . - . - _:B4719964c44d8f257dde3f56d13ae8e7b . - . -_:B916c3fa133826b761aaf7e6fa1dee17c "Stad Mechelen"^^ . -_:B916c3fa133826b761aaf7e6fa1dee17c . -_:B916c3fa133826b761aaf7e6fa1dee17c . -_:B98c1ff7fbddc160e56f2977a1f48de23 "Politiezone Leuven"^^ . -_:B98c1ff7fbddc160e56f2977a1f48de23 . -_:B98c1ff7fbddc160e56f2977a1f48de23 . - . - . - "9197054"^^ . -_:Bd7683bb97ee280285d320de50ae61f32 "Gemeente Ingelmunster"^^ . -_:Bd7683bb97ee280285d320de50ae61f32 . -_:Bd7683bb97ee280285d320de50ae61f32 . -_:Bc02dcac7f8fa3b1424f1b3d8c1b50940 "https://gipod.vlaanderen.be"@nl-BE . -_:Bc02dcac7f8fa3b1424f1b3d8c1b50940 "10590493"^^ . -_:Bc02dcac7f8fa3b1424f1b3d8c1b50940 . -_:Bca1df3d66a570a55e52d17d760c0908d "https://gipod.vlaanderen.be"@nl-BE . -_:Bca1df3d66a570a55e52d17d760c0908d "10590332"^^ . -_:Bca1df3d66a570a55e52d17d760c0908d . -_:Bc15b22eb246d3a2112ece28f3c2d40c3 "https://gipod.vlaanderen.be"@nl-BE . -_:Bc15b22eb246d3a2112ece28f3c2d40c3 "10590435"^^ . -_:Bc15b22eb246d3a2112ece28f3c2d40c3 . -_:B5b6aad1a73e784714a22fe23b1c40521 "Gemeente Asse"^^ . -_:B5b6aad1a73e784714a22fe23b1c40521 . -_:B5b6aad1a73e784714a22fe23b1c40521 . - . - . - "9196998"^^ . - . - . - _:B6fe795917dd8918883cedefb5c866447 . - _:Bcda4a9667802ccaaf1311ca46f4b7185 . - _:B255256009a1a29660f1a6941c46701d8 . - _:Be542303d24bde73be54033980395c3b0 . - . - "2021-01-06T16:17:40.2Z"^^ . - "10590346"^^ . - . - _:Bc91983e5d5167edf5c99eebdb7df282f . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T16:18:43.373Z"^^ . - "8000 Brugge, Karel Mestdaghstraat 85: Doorlopende vergunning"^^ . - "2021-01-06T18:04:17.953Z"^^ . -_:B978187050d27413ae9623979a556474a " POLYGON ((218530.83153439205 179099.80497135315, 218534.0513468479 179095.34463547263, 218536.08430362307 179096.80442212615, 218532.8644902975 179101.26475552563, 218530.83153439205 179099.80497135315))"^^ . -_:B978187050d27413ae9623979a556474a . -_:B95f57e82eadf8d077be263158a94d3d7 " MULTIPOLYGON (((190983.5561549791 224805.51254365034, 190991.1756929284 224811.26009669807, 190989.67202383548 224812.27372042555, 190982.6118343242 224806.71706900094, 190983.5561549791 224805.51254365034)), ((190979.64366971672 224803.80335207563, 190981.4070572578 224805.40227258205, 190979.99168582266 224807.0692224009, 190978.22608120024 224805.74998054747, 190979.64366971672 224803.80335207563)))"^^ . -_:B95f57e82eadf8d077be263158a94d3d7 . - . - _:Bbdb7411539917c7989616215cc879d78 . - . -_:Bdb962510044918d11ac26e4e5b4a7cfd "Stad Mechelen"^^ . -_:Bdb962510044918d11ac26e4e5b4a7cfd . -_:Bdb962510044918d11ac26e4e5b4a7cfd . -_:B231efb1aa701fd438d0f131ce31c9c5c "Politiezone Leuven"^^ . -_:B231efb1aa701fd438d0f131ce31c9c5c . -_:B231efb1aa701fd438d0f131ce31c9c5c . -_:B0c5c051b64b0149b3961de830cedd3c6 "https://gipod.vlaanderen.be"@nl-BE . -_:B0c5c051b64b0149b3961de830cedd3c6 "10590455"^^ . -_:B0c5c051b64b0149b3961de830cedd3c6 . - . - "10590466"^^ . - _:Bbfb354120b354dc8a79cba5fd1357dc5 . - _:B386a6308462421f3c6e9c1916463c3b2 . - "2021-01-06T14:08:34.757Z"^^ . - "2021-01-06T18:05:01.547Z"^^ . - "2021-01-06T14:04:05.853Z"^^ . - . - _:B8bbc47823740a9ab41c78afa4342e280 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "9300 Aalst, Jan De Windtstraat 1A: Stelling (13m x 1m) + container voor de poort (6m x 2m) / Verlenging = 25m²"^^ . - . - _:Bf8f71247ff26446e438299dd1195bc99 . - _:Bae4bcd05325cb597bc89496b9206e45a . - . - . - _:B3da0c7a0842f1e5f7be400ca0dd432eb . - . -_:B43160946bc918cc0a82fdea8494fd098 " POLYGON ((77451.8208943843 171625.222206265, 77454.0204726042 171626.89985067, 77458.4941910174 171621.680512521, 77456.3318937844 171619.779182196, 77451.8208943843 171625.147644292, 77451.8208943843 171625.222206265))"^^ . -_:B43160946bc918cc0a82fdea8494fd098 . - . - . - "9197134"^^ . -_:B291299e8a658cc0a1855bc84d03acadc "Gemeente Brasschaat"^^ . -_:B291299e8a658cc0a1855bc84d03acadc . -_:B291299e8a658cc0a1855bc84d03acadc . -_:Bdaf102bdc35f7f79fd8ee0b9c580b83c "Gemeente Beveren"^^ . -_:Bdaf102bdc35f7f79fd8ee0b9c580b83c . -_:Bdaf102bdc35f7f79fd8ee0b9c580b83c . -_:B3846feeed71af0fa2b5f50a85fec1066 "Stad Turnhout"^^ . -_:B3846feeed71af0fa2b5f50a85fec1066 . -_:B3846feeed71af0fa2b5f50a85fec1066 . -_:B2f6c422e5d3f94a21729598037f8ca19 " POLYGON ((96119.76758185409 161107.6287516665, 96119.91776304062 161107.63459267083, 96120.06708155492 161107.65169493394, 96120.21469417647 161107.67996187718, 96120.35976731809 161107.7192338735, 96120.45238628943 161107.75058597917, 96120.54336219643 161107.78642747362, 96120.63247757877 161107.8266726847, 96120.71951942328 161107.87122541395, 96120.80427967325 161107.91997916668, 96120.88655572564 161107.97281740647, 96120.96615091542 161108.02961383367, 96121.04287498565 161108.09023268742, 96121.11654454222 161108.15452907002, 96121.1869834923 161108.22234929336, 96121.25402346514 161108.29353124628, 96121.31750421463 161108.36790478206, 96121.37727400228 161108.4452921251, 96121.43318995993 161108.52550829592, 96121.4851184313 161108.60836155323, 96121.53293529137 161108.69365385224, 96121.57652624318 161108.78118131822, 96121.61578709095 161108.87073473365, 96121.6506239892 161108.96210003833, 96121.68095366706 161109.05505884116, 96121.70670362726 161109.14938894202, 96121.72781231951 161109.24486486302, 96121.74422928756 161109.3412583874, 96121.75591528979 161109.43833910502, 96121.76284239307 161109.53587496316, 96121.76499403952 161109.63363282115, 96121.76236508602 161109.7313790077, 96121.75496181658 161109.82887987938, 96121.74280192728 161109.9259023792, 96121.72591448402 161110.0222145936, 96121.70433985293 161110.1175863068, 96121.67812960406 161110.21178955107, 96121.6745161265 161110.22351731808, 96119.2995161265 161117.84851731808, 96119.29583075673 161117.86022269246, 96119.26391094193 161117.95264754735, 96119.22751190451 161118.0434018225, 96119.18672064935 161118.13226858727, 96119.14163468007 161118.21903542284, 96119.09236176599 161118.30349492983, 96119.0390196845 161118.38544522403, 96118.98173593955 161118.46469041915, 96118.92064745691 161118.54104109478, 96118.85590025678 161118.61431474934, 96118.78764910487 161118.68433623636, 96118.71605714237 161118.75093818296, 96118.6412954961 161118.81396139, 96118.5635428693 161118.87325521267, 96118.48298511468 161118.92867792057, 96118.39981478997 161118.98009703637, 96118.31423069781 161119.0273896526, 96118.22643741046 161119.07044272535, 96118.13664478083 161119.10915334465, 96118.04506744086 161119.1434289801, 96117.95192428857 161119.17318770254, 96117.85743796465 161119.1983583794, 96117.76183432045 161119.21888084506, 96117.66534187803 161119.2347060445, 96117.56819128398 161119.24579615064, 96117.47061475803 161119.25212465477, 96117.37284553805 161119.25367642977, 96117.2751173225 161119.25044776642, 96117.17766371183 161119.24244638224, 96117.0807176501 161119.229691403, 96116.98451086816 161119.212213317, 96116.88927332978 161119.19005390222, 96116.7952326819 161119.1632661265, 96116.70261371057 161119.13191402084, 96116.61163780357 161119.0960725264, 96116.52252242123 161119.05582731531, 96116.43548057672 161119.01127458605, 96116.35072032675 161118.96252083333, 96116.26844427436 161118.90968259354, 96116.18884908457 161118.85288616634, 96116.11212501435 161118.7922673126, 96116.03845545778 161118.72797093, 96115.9680165077 161118.66015070665, 96115.90097653486 161118.58896875373, 96115.83749578537 161118.51459521794, 96115.77772599772 161118.4372078749, 96115.72181004006 161118.3569917041, 96115.6698815687 161118.27413844678, 96115.62206470863 161118.18884614776, 96115.57847375682 161118.1013186818, 96115.53921290905 161118.01176526636, 96115.5043760108 161117.92039996167, 96115.47404633294 161117.82744115885, 96115.44829637274 161117.73311105798, 96115.42718768049 161117.63763513698, 96115.41077071243 161117.5412416126, 96115.39908471021 161117.444160895, 96115.39215760693 161117.34662503685, 96115.39000596048 161117.24886717886, 96115.39263491398 161117.15112099232, 96115.40003818342 161117.05362012063, 96115.41219807272 161116.9565976208, 96115.42908551598 161116.8602854064, 96115.45066014706 161116.76491369322, 96115.47687039594 161116.67071044893, 96115.4804838735 161116.65898268193, 96117.8554838735 161109.03398268193, 96117.85916924327 161109.02227730755, 96117.91297482623 161108.87376473146, 96117.97833289127 161108.72996156962, 96118.05483575069 161108.59176483116, 96118.14200619828 161108.4600365537, 96118.239300486 161108.33559842614, 96118.3461117158 161108.2192266632, 96118.46177362523 161108.11164716363, 96118.58556474344 161108.01353098216, 96118.71671289159 161107.92549014362, 96118.85439999949 161107.84807382533, 96118.99776720845 161107.78176493142, 96119.14592022875 161107.72697708063, 96119.29793491792 161107.68405202625, 96119.45286304534 161107.6532575243, 96119.60973820709 161107.6347856634, 96119.76758185409 161107.6287516665))"^^ . -_:B2f6c422e5d3f94a21729598037f8ca19 . - . - . - "9197168"^^ . -_:B6e72aa41dcba691228c3b5432895cd59 " POLYGON ((71243.1056665872 212705.389962625, 71244.8884670446 212704.483528662, 71250.3270708229 212715.180331406, 71248.5442703656 212716.086765369, 71246.1295324203 212711.337389145, 71245.8373504288 212710.762717178, 71243.1056665872 212705.389962625))"^^ . -_:B6e72aa41dcba691228c3b5432895cd59 . -_:B1982723485d8d2a04dd04a102810e2aa "Stad Eeklo"^^ . -_:B1982723485d8d2a04dd04a102810e2aa . -_:B1982723485d8d2a04dd04a102810e2aa . -_:B43a945c27023c1c748b052119a09d2f5 "Stad Hasselt"^^ . -_:B43a945c27023c1c748b052119a09d2f5 . -_:B43a945c27023c1c748b052119a09d2f5 . -_:Bb76536cae2c41f21473e9dfff7529a21 "Stad Ronse"^^ . -_:Bb76536cae2c41f21473e9dfff7529a21 . -_:Bb76536cae2c41f21473e9dfff7529a21 . -_:B25dbeb7324f866fbe9db5009cc452556 "Stad Ronse"^^ . -_:B25dbeb7324f866fbe9db5009cc452556 . -_:B25dbeb7324f866fbe9db5009cc452556 . -_:Bda033b82a83b7f056b73533ca8f5c354 "Stad Ronse"^^ . -_:Bda033b82a83b7f056b73533ca8f5c354 . -_:Bda033b82a83b7f056b73533ca8f5c354 . -_:Be49663129f7da06cf393f6dc810d40be " POLYGON ((173387.54948928507 172654.46900482476, 173382.11829490183 172653.5375237465, 173381.69381849671 172655.99962814245, 173387.12501039333 172656.93110835645, 173392.55620037907 172657.86259405967, 173397.9873884535 172658.79408524558, 173398.411872318 172656.33198344614, 173392.98068175715 172655.40049139224, 173387.54948928507 172654.46900482476))"^^ . -_:Be49663129f7da06cf393f6dc810d40be . -_:Bb9d69c81e8ee598f5b3115041d7ac73c "Stad Hasselt"^^ . -_:Bb9d69c81e8ee598f5b3115041d7ac73c . -_:Bb9d69c81e8ee598f5b3115041d7ac73c . -_:B5e298795be82e27cfd9cff2ff66cf6d5 "Gemeente Zonhoven"^^ . -_:B5e298795be82e27cfd9cff2ff66cf6d5 . -_:B5e298795be82e27cfd9cff2ff66cf6d5 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:32.37Z"^^ . - . - . - _:B7f7a86d3300e0bc4e0fcdcb6d16e7212 . - _:Bf7a1a56d1445c31f31a15bf8db2bf100 . - "8670 Koksijde, Maurice Blieckstraat 13: IOD - Verhuis"^^ . - "2021-01-06T15:24:50.13Z"^^ . - _:B6cd0ff4e281f1a67ab7342452c4b0327 . - "2021-01-06T15:13:00.463Z"^^ . - "10590377"^^ . - . - _:B57ef8e0e9496a0b9bfc945ddbc5b61db . - . - _:B222cf9cbe61842497e059c3ee12fbdae . -_:B570b365c2b175789276ce7715ee4152e "Stad Ronse"^^ . -_:B570b365c2b175789276ce7715ee4152e . -_:B570b365c2b175789276ce7715ee4152e . -_:Bfe00918355244ef278a7837952e4315e "Politiezone Leuven"^^ . -_:Bfe00918355244ef278a7837952e4315e . -_:Bfe00918355244ef278a7837952e4315e . - . - . - "9197235"^^ . -_:Bd5fbe23860cf97058acccfb2b1a7b83d "Gemeente Deerlijk"^^ . -_:Bd5fbe23860cf97058acccfb2b1a7b83d . -_:Bd5fbe23860cf97058acccfb2b1a7b83d . - . - . - _:B583a319ab9fe92071727abb8c243f9a1 . - . -_:Be76a140233050d4064e40f3d87fe6dc7 "2021-01-11T06:00:00Z"^^ . -_:Be76a140233050d4064e40f3d87fe6dc7 "2021-12-31T19:00:00Z"^^ . -_:Be76a140233050d4064e40f3d87fe6dc7 . -_:B659b8bf6f40854874ab134ba915f61fb "2021-02-11T05:00:00Z"^^ . -_:B659b8bf6f40854874ab134ba915f61fb "2021-02-11T19:00:00Z"^^ . -_:B659b8bf6f40854874ab134ba915f61fb . -_:Bab1b8fafeb952ff37e4b69c9306a8081 "Politiezone Brugge"^^ . -_:Bab1b8fafeb952ff37e4b69c9306a8081 . -_:Bab1b8fafeb952ff37e4b69c9306a8081 . -_:B53dfba31b6a890c1cc16ce5b28b0c92e "https://gipod.vlaanderen.be"@nl-BE . -_:B53dfba31b6a890c1cc16ce5b28b0c92e "10590578"^^ . -_:B53dfba31b6a890c1cc16ce5b28b0c92e . -_:Bf0e298b05b0cd7ce154e1ce97882292a "https://gipod.vlaanderen.be"@nl-BE . -_:Bf0e298b05b0cd7ce154e1ce97882292a "10590576"^^ . -_:Bf0e298b05b0cd7ce154e1ce97882292a . -_:B632997c520c8674af167f131a5ab31c7 "Politiezone Leuven"^^ . -_:B632997c520c8674af167f131a5ab31c7 . -_:B632997c520c8674af167f131a5ab31c7 . - . - . - "9197227"^^ . - . - . - "9196980"^^ . -_:B824ed89c77a1ddc27326f1c352023c66 "2021-01-25T06:00:00Z"^^ . -_:B824ed89c77a1ddc27326f1c352023c66 "2021-01-27T17:00:00Z"^^ . -_:B824ed89c77a1ddc27326f1c352023c66 . -_:B1a43aa0753bc3e7ed5c9036993c9cc80 "Stad Dendermonde"^^ . -_:B1a43aa0753bc3e7ed5c9036993c9cc80 . -_:B1a43aa0753bc3e7ed5c9036993c9cc80 . -_:Bc8f0294a4e910c7b261ac61d99c1cd6b " POLYGON ((114286.958167444 178989.298243345, 114286.919738005 178988.908062701, 114286.805926509 178988.53287648, 114286.621106669 178988.187102879, 114286.372381007 178987.884029782, 114286.06930791 178987.63530412, 114285.723534309 178987.45048428, 114285.348348088 178987.336672784, 114284.958167444 178987.298243345, 114284.5679868 178987.336672784, 114284.19280058 178987.45048428, 114283.847026978 178987.63530412, 114283.543953882 178987.884029782, 114283.29522822 178988.187102879, 114283.110408379 178988.53287648, 114282.996596883 178988.908062701, 114282.958167444 178989.298243345, 114282.996596883 178989.688423989, 114283.110408379 178990.063610209, 114283.29522822 178990.409383811, 114283.543953882 178990.712456907, 114283.847026978 178990.961182569, 114284.19280058 178991.14600241, 114284.5679868 178991.259813905, 114284.958167444 178991.298243345, 114285.348348088 178991.259813905, 114285.723534309 178991.14600241, 114286.06930791 178990.961182569, 114286.372381007 178990.712456907, 114286.621106669 178990.409383811, 114286.805926509 178990.063610209, 114286.919738005 178989.688423989, 114286.958167444 178989.298243345))"^^ . -_:Bc8f0294a4e910c7b261ac61d99c1cd6b . - . - . - "9197062"^^ . - . - . - "9197008"^^ . - . - _:B3ce3c3cb6eb197c4b2c7afd7716bc7f4 . - . -_:B8e601aad769f4287c155fe6990002743 "Gemeente Drogenbos"^^ . -_:B8e601aad769f4287c155fe6990002743 . -_:B8e601aad769f4287c155fe6990002743 . -_:Bc3096bc5d182cd3bf6633ebe28fc277b " POLYGON ((174138.19141063443 174661.0229534367, 174138.89297951275 174658.62469662726, 174144.66427761823 174660.3041035831, 174143.96270630936 174662.7023588661, 174138.19141063443 174661.0229534367))"^^ . -_:Bc3096bc5d182cd3bf6633ebe28fc277b . -_:B51e1909d0818161791126c3e74667d6f "Stad Hasselt"^^ . -_:B51e1909d0818161791126c3e74667d6f . -_:B51e1909d0818161791126c3e74667d6f . -_:Bbe36c650174a119a64c38d4f52772c00 "Gemeente Koksijde"^^ . -_:Bbe36c650174a119a64c38d4f52772c00 . -_:Bbe36c650174a119a64c38d4f52772c00 . -_:Bf97303c8aa55aac4b88f238213041db9 "2021-01-20T06:00:00Z"^^ . -_:Bf97303c8aa55aac4b88f238213041db9 "2021-01-20T17:00:00Z"^^ . -_:Bf97303c8aa55aac4b88f238213041db9 . -_:B610c23989f0d2f272ff6b3ac0fef5320 "https://gipod.vlaanderen.be"@nl-BE . -_:B610c23989f0d2f272ff6b3ac0fef5320 "10590450"^^ . -_:B610c23989f0d2f272ff6b3ac0fef5320 . -_:Bae4bcd05325cb597bc89496b9206e45a "Stad Aalst"^^ . -_:Bae4bcd05325cb597bc89496b9206e45a . -_:Bae4bcd05325cb597bc89496b9206e45a . - . - _:Bd057f23c8937d0aae52b0e6341ada615 . - . -_:Bb946f072c1a9eff67c656a25448b1b0d "Stad Tielt"^^ . -_:Bb946f072c1a9eff67c656a25448b1b0d . -_:Bb946f072c1a9eff67c656a25448b1b0d . - . - _:Bcef4d9041a362cb80642419ffa088e6a . - . - . - . - "9197163"^^ . - _:Bbd6a38af5b85a990df0c9a09d6136913 . - _:B90ac90820c68a00d7c324f0f1ed31049 . - . - . - _:B3d51b2cabeca554b3971089b4955053d . - "10590495"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "9600 Ronse - Pierre D'Hauwerstraat 5 - parkeerverbod"^^ . - "2021-01-06T13:39:23.79Z"^^ . - . - "2021-01-06T18:05:11.813Z"^^ . - "2021-01-06T13:38:39.21Z"^^ . - _:B6be66f55fac59bc1acbc557fc370a22c . - . - _:Baabe4573e6f71f18838e6aa06c05c0f4 . -_:B222cf9cbe61842497e059c3ee12fbdae "Gemeente Koksijde"^^ . -_:B222cf9cbe61842497e059c3ee12fbdae . -_:B222cf9cbe61842497e059c3ee12fbdae . - "10590420"^^ . - "2021-01-06T18:04:46.567Z"^^ . - _:Bced9054e50097f0dc6dd7568be9fa5ad . - . - _:Bb0c540633eeba52e5444a717c98ee24f . - . - _:B434701ba97b1bfc7b73eaffed47ffe81 . - "2021-01-06T14:41:39.95Z"^^ . - "8730 Beernem, Wingene Steenweg 23: Inname voetpad en fietspad voor wegenwerken - herstel riolering en voetpad"^^ . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bde2223a30da28e19d640b8eaa7085ae8 . - _:Bc701119bbef792536286af46c7ccd13e . - "2021-01-06T14:40:20.94Z"^^ . -_:B27f6b9670796f3535b1779f93f3d23b9 "Gemeente Asse"^^ . -_:B27f6b9670796f3535b1779f93f3d23b9 . -_:B27f6b9670796f3535b1779f93f3d23b9 . -_:B1adb4e80e880d229954b49f393f03106 " MULTIPOLYGON (((157539.7188717026 220951.50508741956, 157542.24056737282 220953.13021847483, 157540.61543631754 220955.65191414507, 157538.0937406473 220954.0267830898, 157539.7188717026 220951.50508741956)), ((157528.34442412024 220945.47704201803, 157538.6588547764 220951.60994673273, 157537.63670399078 220953.32901850855, 157527.3222733346 220947.19611379385, 157528.34442412024 220945.47704201803)))"^^ . -_:B1adb4e80e880d229954b49f393f03106 . -_:B986e931f3e6efded7c740b08f1b24cc2 "Stad Kortrijk"^^ . -_:B986e931f3e6efded7c740b08f1b24cc2 . -_:B986e931f3e6efded7c740b08f1b24cc2 . -_:B0debbf3fddd4c425ad290d0d40857c38 "Gemeente Beveren"^^ . -_:B0debbf3fddd4c425ad290d0d40857c38 . -_:B0debbf3fddd4c425ad290d0d40857c38 . -_:Bbddb0e518d31887851b7cedd17c02cfc "Politiezone Brugge"^^ . -_:Bbddb0e518d31887851b7cedd17c02cfc . -_:Bbddb0e518d31887851b7cedd17c02cfc . -_:B050acb5acec8337e282f52d3f8d7add7 "https://gipod.vlaanderen.be"@nl-BE . -_:B050acb5acec8337e282f52d3f8d7add7 "10590469"^^ . -_:B050acb5acec8337e282f52d3f8d7add7 . - . - _:B1c927bfb741d9ec081eaf2a47c522c2e . - "2021-01-06T14:55:35.547Z"^^ . - "Verhuiswagen verhuis"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Ba2685a68a33619b544f1ceefea75930a . - "10590395"^^ . - . - "2021-01-06T15:24:03.38Z"^^ . - _:B2329a7fb326b012014a9918b901f4d5f . - _:B446ad098c4f693f9e264b7da6625d488 . - . - "2021-01-06T18:04:38.57Z"^^ . - _:B8ed3c39143bfaaf2c5495d962535bd81 . - . - . - _:Bdaa1e756271be914c975342dfa9f9608 . - . -_:B550b1149c0afc3b163f42220194039ef "Stad Hasselt"^^ . -_:B550b1149c0afc3b163f42220194039ef . -_:B550b1149c0afc3b163f42220194039ef . -_:Bcf8a743100ba6da35e3a732f75f53f85 " POLYGON ((53809.2248898358 216797.26772279, 53809.0892497821 216797.126191115, 53808.9286045539 216797.013840993, 53808.7491276573 216796.934989976, 53808.5577162888 216796.892668266, 53808.3617262799 216796.88850226, 53808.1686894167 216796.922652058, 53807.9860239977 216796.9938053, 53807.8207497524 216797.099227608, 53807.6792180774 216797.234867662, 53807.5668679556 216797.39551289, 53807.4880169392 216797.574989786, 53807.4456952286 216797.766401155, 53807.4415292232 216797.962391164, 53807.4756790204 216798.155428027, 53807.5468322627 216798.338093446, 53807.6522545707 216798.503367691, 53810.2768415009 216801.843743196, 53810.4124815546 216801.985274871, 53810.5731267828 216802.097624993, 53810.7526036794 216802.17647601, 53810.9440150479 216802.21879772, 53811.1400050568 216802.222963726, 53811.33304192 216802.188813928, 53811.515707339 216802.117660686, 53811.6809815843 216802.012238378, 53811.8225132593 216801.876598324, 53811.934863381 216801.715953096, 53812.0137143974 216801.5364762, 53812.0560361081 216801.345064831, 53812.0602021135 216801.149074822, 53812.0260523163 216800.956037959, 53811.954899074 216800.77337254, 53811.849476766 216800.608098295, 53809.2248898358 216797.26772279))"^^ . -_:Bcf8a743100ba6da35e3a732f75f53f85 . -_:B53c5097a2f61ccdea461bd3a0b6eee4b "Politiezone Leuven"^^ . -_:B53c5097a2f61ccdea461bd3a0b6eee4b . -_:B53c5097a2f61ccdea461bd3a0b6eee4b . -_:Bbfb354120b354dc8a79cba5fd1357dc5 "Stad Aalst"^^ . -_:Bbfb354120b354dc8a79cba5fd1357dc5 . -_:Bbfb354120b354dc8a79cba5fd1357dc5 . -_:B19b841376c34fba55937c402d01c8b93 "Politiezone Leuven"^^ . -_:B19b841376c34fba55937c402d01c8b93 . -_:B19b841376c34fba55937c402d01c8b93 . -_:B243bf07a6efe3e9fc5f440c071527975 "https://gipod.vlaanderen.be"@nl-BE . -_:B243bf07a6efe3e9fc5f440c071527975 "10590501"^^ . -_:B243bf07a6efe3e9fc5f440c071527975 . -_:B7df343ae36c5af9123f57be1918c642d "Politiezone Leuven"^^ . -_:B7df343ae36c5af9123f57be1918c642d . -_:B7df343ae36c5af9123f57be1918c642d . -_:Baaf2d9d6d6397d6d47ad98e513487ce9 "2021-01-07T06:00:00Z"^^ . -_:Baaf2d9d6d6397d6d47ad98e513487ce9 "2021-01-08T16:00:00Z"^^ . -_:Baaf2d9d6d6397d6d47ad98e513487ce9 . - "2021-01-06T14:57:23.113Z"^^ . - "10590408"^^ . - . - "2021-01-06T18:04:42.86Z"^^ . - . - . - "Container"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Beef7c7125df3a7bea16fa10512f7d563 . - "2021-01-06T14:49:02.737Z"^^ . - _:B53a42ffec0b3813bdff4a2d4087b59bb . - _:Bfe00918355244ef278a7837952e4315e . - . - _:Bb1ded4e9eee70602ca136aaee21f021f . - _:B089c7f3c53964b2f76adb504bd359e4a . -_:B8ae71616b81e940d4c871b1ce7c84b2c "Stad Tongeren"^^ . -_:B8ae71616b81e940d4c871b1ce7c84b2c . -_:B8ae71616b81e940d4c871b1ce7c84b2c . -_:Bb18716d994dc14d13f3bcac58c05f7e8 "Gemeente Schoten"^^ . -_:Bb18716d994dc14d13f3bcac58c05f7e8 . -_:Bb18716d994dc14d13f3bcac58c05f7e8 . - "2021-01-06T18:05:19.167Z"^^ . - _:B1ea587aa44c902705429318bbf1fce0c . - . - . - "10590506"^^ . - . - "9600 Ronse - Politiekegevangenenstraat 14 - parkeerverbod"^^ . - _:B0bdbddc985144e2f1094b3ef725d6f41 . - _:B80926c102fab102feeb95363551b05b7 . - . - _:Bf0617b52f987877b3573e05769e60456 . - "2021-01-06T13:29:10.453Z"^^ . - _:Baa3125e939935cb01eb3bf19c8f47535 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T13:28:53.733Z"^^ . -_:B63699ede0572cd20d6ccde8902e67f9b "https://gipod.vlaanderen.be"@nl-BE . -_:B63699ede0572cd20d6ccde8902e67f9b "10590419"^^ . -_:B63699ede0572cd20d6ccde8902e67f9b . -_:B8aee7861fd2ed37be417707ff482da36 "https://gipod.vlaanderen.be"@nl-BE . -_:B8aee7861fd2ed37be417707ff482da36 "10590335"^^ . -_:B8aee7861fd2ed37be417707ff482da36 . - . - _:B9017c213345c889314b4cb9ca6bcb31e . - "2021-01-06T13:49:53.777Z"^^ . - "10590485"^^ . - "2021-01-06T13:49:03.047Z"^^ . - _:Bdc53cf7bab7a76c237a9a55afc92be38 . - _:B052fae9cb6328933b4ed34ecfd2ace06 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - "2900 Schoten, Venstraat 153-159: Parkeerverbod laden en lossen"^^ . - "2021-01-06T18:05:07.533Z"^^ . - _:B373138be1b56ee161539c56baa213097 . - _:Bb18716d994dc14d13f3bcac58c05f7e8 . - . -_:B08d6acae7ebe70d02b212a828e43039b " POLYGON ((174567.1850626267 174617.0511024017, 174569.09421506757 174611.8953328682, 174566.74437327374 174611.02979852632, 174564.83522284334 174616.1855697576, 174562.92607615938 174621.3413366098, 174565.27591393222 174622.20686755795, 174567.1850626267 174617.0511024017))"^^ . -_:B08d6acae7ebe70d02b212a828e43039b . - . - . - "9197222"^^ . -_:Ba7a127d0251a5c6f24c9f2e3f2210d61 "Politiezone Leuven"^^ . -_:Ba7a127d0251a5c6f24c9f2e3f2210d61 . -_:Ba7a127d0251a5c6f24c9f2e3f2210d61 . -_:Bc701119bbef792536286af46c7ccd13e "Gemeente Beernem"^^ . -_:Bc701119bbef792536286af46c7ccd13e . -_:Bc701119bbef792536286af46c7ccd13e . -_:Bbc29b6270de0c3d39e094fc5b939877a "Stad Lokeren"^^ . -_:Bbc29b6270de0c3d39e094fc5b939877a . -_:Bbc29b6270de0c3d39e094fc5b939877a . -_:B7b7abffcd390d12abdce19a622606739 "Gemeente Willebroek"^^ . -_:B7b7abffcd390d12abdce19a622606739 . -_:B7b7abffcd390d12abdce19a622606739 . -_:Bc8619ae7511313a970f228c4317bc6dc "https://gipod.vlaanderen.be"@nl-BE . -_:Bc8619ae7511313a970f228c4317bc6dc "10590372"^^ . -_:Bc8619ae7511313a970f228c4317bc6dc . -_:Bd003eaf6d1520c22372f357e4e2b6d52 " POLYGON ((172905.37410646555 174526.0187510047, 172909.63325681008 174544.7690166086, 172912.42995982573 174574.14923581947, 172914.24927826138 174589.688281456, 172917.71686136458 174595.2570371274, 172921.84756530094 174600.2639407916, 172922.98754902222 174598.5746614011, 172918.94791313956 174594.32117444836, 172916.4232849798 174588.94481601473, 172913.8460498277 174574.06133080367, 172911.6168692303 174544.40121916495, 172907.26293288014 174525.74466275238, 172905.37410646555 174526.0187510047))"^^ . -_:Bd003eaf6d1520c22372f357e4e2b6d52 . -_:B0055edc2a598971f57c3e3943a778d93 "Politiezone Brugge"^^ . -_:B0055edc2a598971f57c3e3943a778d93 . -_:B0055edc2a598971f57c3e3943a778d93 . -_:B4f3f67b6fd78be8a19b7f3d7ffda991d "2021-01-20T05:00:00Z"^^ . -_:B4f3f67b6fd78be8a19b7f3d7ffda991d "2021-02-24T19:00:00Z"^^ . -_:B4f3f67b6fd78be8a19b7f3d7ffda991d . - . - _:B33e084e8a903a18cb8b2425254328472 . - . -_:B82b045c6adf2930094670bbc20033382 "Gemeente Brasschaat"^^ . -_:B82b045c6adf2930094670bbc20033382 . -_:B82b045c6adf2930094670bbc20033382 . -_:B8734503d07333eb32d193999b41a0320 "Gemeente Gavere"^^ . -_:B8734503d07333eb32d193999b41a0320 . -_:B8734503d07333eb32d193999b41a0320 . -_:B9cd130008b4ad197c1b6b700a1624ea9 "https://gipod.vlaanderen.be"@nl-BE . -_:B9cd130008b4ad197c1b6b700a1624ea9 "10590526"^^ . -_:B9cd130008b4ad197c1b6b700a1624ea9 . - . - . - "9197029"^^ . -_:B232b35ff7aa28024e17a9b8b22e52546 "Stad Tongeren"^^ . -_:B232b35ff7aa28024e17a9b8b22e52546 . -_:B232b35ff7aa28024e17a9b8b22e52546 . -_:B42c065c163b5ed0edcf9b0461903cd02 "2021-01-08T06:00:00Z"^^ . -_:B42c065c163b5ed0edcf9b0461903cd02 "2021-01-08T16:00:00Z"^^ . -_:B42c065c163b5ed0edcf9b0461903cd02 . - . - . - "9197323"^^ . -_:Bd1113f9d873e3398068f0741247f4789 "2021-01-08T08:00:00Z"^^ . -_:Bd1113f9d873e3398068f0741247f4789 "2021-01-08T12:00:00Z"^^ . -_:Bd1113f9d873e3398068f0741247f4789 . -_:B4bbc057628364cdc723560a8f45327cf "Stad Ronse"^^ . -_:B4bbc057628364cdc723560a8f45327cf . -_:B4bbc057628364cdc723560a8f45327cf . -_:Bd662bb83abcce314c54556dca4fe0ed2 "Gemeente Ingelmunster"^^ . -_:Bd662bb83abcce314c54556dca4fe0ed2 . -_:Bd662bb83abcce314c54556dca4fe0ed2 . - . - . - "9196939"^^ . -_:B58d0336c7731a7f900d6bd147f83da52 "Stad Dendermonde"^^ . -_:B58d0336c7731a7f900d6bd147f83da52 . -_:B58d0336c7731a7f900d6bd147f83da52 . -_:B22d23b7f12d46e394eae2661389ab6ee "2021-01-20T06:00:00Z"^^ . -_:B22d23b7f12d46e394eae2661389ab6ee "2021-01-20T18:00:00Z"^^ . -_:B22d23b7f12d46e394eae2661389ab6ee . -_:B2df1fa890222ea735237d476654f3ecd " MULTIPOLYGON (((176794.05731899955 174438.22933374438, 176794.9036039167 174438.8455313621, 176792.7674633279 174441.28195887897, 176792.06250806717 174440.71355321445, 176794.05731899955 174438.22933374438)), ((176795.26694753752 174430.59253915027, 176797.19164701737 174432.19153461512, 176793.66453851928 174436.4144451823, 176790.13743571652 174440.637354712, 176788.21273721557 174439.03836440947, 176791.73983952892 174434.8154523028, 176795.26694753752 174430.59253915027)))"^^ . -_:B2df1fa890222ea735237d476654f3ecd . -_:B5e1b5015b72a26c1a2a3a9284b2d2c8f "https://gipod.vlaanderen.be"@nl-BE . -_:B5e1b5015b72a26c1a2a3a9284b2d2c8f "10590589"^^ . -_:B5e1b5015b72a26c1a2a3a9284b2d2c8f . -_:Bcda4a9667802ccaaf1311ca46f4b7185 "Politiezone Brugge"^^ . -_:Bcda4a9667802ccaaf1311ca46f4b7185 . -_:Bcda4a9667802ccaaf1311ca46f4b7185 . - "2021-01-06T18:05:34.637Z"^^ . - . - _:Bf2c5a929c9ab619cfb643fb4b4caa8c5 . - . - "Wegeniswerken"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B9bc74760910b9e4af03cd6e116f2e8d3 . - "10590556"^^ . - "2021-01-06T13:10:35.033Z"^^ . - _:B3f29778ff784c7de6c24d2c508bfa6f7 . - _:B602ef67f7648ab07568212d6e3e3c891 . - "2021-01-06T13:00:11.577Z"^^ . - . - . - _:B5864fc2cc3a83fe99051c621069b0af2 . -_:B5862e6ef8ee611411ab0f51c0e7db0c6 "https://gipod.vlaanderen.be"@nl-BE . -_:B5862e6ef8ee611411ab0f51c0e7db0c6 "10590355"^^ . -_:B5862e6ef8ee611411ab0f51c0e7db0c6 . -_:B449f4c1f172e3bb625bc872f105e860b "2021-01-25T06:00:00Z"^^ . -_:B449f4c1f172e3bb625bc872f105e860b "2021-02-26T18:00:00Z"^^ . -_:B449f4c1f172e3bb625bc872f105e860b . -_:B75bef9dbeb51ccea94ae7fa51663fec4 " POLYGON ((95881.47271207768 159547.32625130867, 95881.61066609151 159547.33085662738, 95881.74797391014 159547.34496626354, 95881.88398151864 159547.3685130112, 95882.0180410951 159547.40138471406, 95882.14951409638 159547.4434248, 95882.27777429952 159547.49443302662, 95882.40221078454 159547.5541664351, 95882.5222308443 159547.62234050749, 95882.63726280771 159547.6986305218, 95882.74675876259 159547.78267309887, 95882.8501971655 159547.87406793292, 95882.94708532593 159547.97237969856, 95883.036961753 159548.07714012405, 95883.11939835359 159548.18785022193, 95883.19400247151 159548.30398266565, 95883.26041875768 159548.42498430127, 95883.30217940189 159548.5129754871, 95883.33960670732 159548.6028954348, 95883.37261191141 159548.69453089024, 95883.40111673901 159548.78766453074, 95883.42505358806 159548.88207548056, 95883.44436568991 159548.97753983468, 95883.45900724402 159549.07383118986, 95883.46894352644 159549.1707211815, 95883.4741509723 159549.2679800253, 95883.47461723162 159549.36537706217, 95883.47034119863 159549.4626813053, 95883.46133301435 159549.55966198794, 95883.4476140426 159549.65608911068, 95883.4292168193 159549.75173398698, 95883.40618497529 159549.84636978546, 95883.37857313291 159549.9397720678, 95883.3464467764 159550.03171932118, 95883.30988209663 159550.1219934835, 95883.26896581038 159550.21038046054, 95883.22379495473 159550.29667063372, 95883.17447665689 159550.3806593573, 95883.12112788013 159550.46214744358, 95883.06387514641 159550.54094163544, 95883.00285423631 159550.61685506455, 95882.93820986705 159550.68970769463, 95882.8700953492 159550.75932674838, 95882.79867222313 159550.82554711725, 95882.72410987597 159550.88821175302, 95882.64658513977 159550.94717204018, 95882.56628187219 159551.0022881486, 95882.48339052047 159551.05342936484, 95882.39810766975 159551.10047440242, 95882.37626569877 159551.1116687577, 95882.37626569877 159551.1116687577, 95843.25126569877 159570.8616687577, 95843.25126569877 159570.8616687577, 95843.25126569875 159570.8616687577, 95843.1625737386 159570.90374115438, 95843.07192421716 159570.94141096485, 95842.97953551704 159570.97458743915, 95842.8856302107 159571.0031906523, 95842.79043452429 159571.02715169662, 95842.69417779251 159571.0464128479, 95842.5970919063 159571.0609277043, 95842.49941075404 159571.07066129826, 95842.40136965818 159571.07559018073, 95842.30320480833 159571.0757024776, 95842.20515269217 159571.0709979183, 95842.10744952588 159571.06148783653, 95842.01033068493 159571.04719514295, 95841.91403013711 159571.02815426988, 95841.81877987887 159571.00441108845, 95841.72480937642 159570.97602279807, 95841.63234501296 159570.94305778862, 95841.54160954322 159570.9055954757, 95841.4528215569 159570.8637261093, 95841.36619495202 159570.81755055638, 95841.28193841969 159570.7671800579, 95841.20025494124 159570.7127359608, 95841.12134129935 159570.6543494257, 95841.0453876039 159570.59216111084, 95840.97257683397 159570.52632083333, 95840.9030843971 159570.4569872082, 95840.83707770664 159570.3843272662, 95840.7747157785 159570.30851605145, 95840.71614884805 159570.22973619986, 95840.66151800811 159570.148177499, 95840.6109548692 159570.0640364309, 95840.56458124233 159569.97751569876, 95840.52282059813 159569.88952451292, 95840.48539329269 159569.79960456523, 95840.4523880886 159569.7079691098, 95840.423883261 159569.61483546929, 95840.39994641196 159569.52042451946, 95840.3806343101 159569.42496016534, 95840.365992756 159569.32866881017, 95840.35605647357 159569.23177881853, 95840.35084902772 159569.13451997473, 95840.35038276839 159569.03712293785, 95840.35465880139 159568.93981869472, 95840.36366698566 159568.8428380121, 95840.37738595741 159568.74641088935, 95840.3957831807 159568.65076601304, 95840.41881502472 159568.55613021457, 95840.4464268671 159568.46272793223, 95840.47855322361 159568.37078067884, 95840.51511790339 159568.28050651652, 95840.55603418963 159568.19211953948, 95840.60120504528 159568.1058293663, 95840.65052334312 159568.02184064273, 95840.70387211988 159567.94035255644, 95840.7611248536 159567.8615583646, 95840.8221457637 159567.78564493547, 95840.88679013296 159567.7127923054, 95840.95490465082 159567.64317325165, 95841.02632777688 159567.57695288278, 95841.10089012404 159567.514288247, 95841.17841486025 159567.45532795985, 95841.25871812782 159567.40021185143, 95841.34160947954 159567.3490706352, 95841.42689233026 159567.3020255976, 95841.44873430124 159567.29083124234, 95841.44873430124 159567.29083124234, 95880.57373430124 159547.54083124234, 95880.57373430124 159547.54083124234, 95880.57373430126 159547.54083124234, 95880.67928045877 159547.4913575204, 95880.78752960407 159547.44811676332, 95880.89811402452 159547.41125585607, 95881.01065807478 159547.38090001183, 95881.12477945283 159547.35715234667, 95881.24009049861 159547.3400935293, 95881.35619951085 159547.32978150697, 95881.47271207768 159547.32625130867))"^^ . -_:B75bef9dbeb51ccea94ae7fa51663fec4 . -_:B5daf0259cc7670a34548691ecbbe3d9f " POLYGON ((217541.47222381283 180017.40833712462, 217539.0695473713 180016.40383364167, 217537.132961741 180021.01189606078, 217539.5356364116 180022.01639779191, 217541.93831016924 180023.02090045065, 217544.34098301435 180024.0254040314, 217546.2775739581 180019.4173468668, 217543.87489934175 180018.41284153424, 217541.47222381283 180017.40833712462))"^^ . -_:B5daf0259cc7670a34548691ecbbe3d9f . -_:Bc0ae83908b98817795f241010067b11b "https://gipod.vlaanderen.be"@nl-BE . -_:Bc0ae83908b98817795f241010067b11b "10590554"^^ . -_:Bc0ae83908b98817795f241010067b11b . - . - _:Be061b52d42196486c12a33ad40a2dc08 . - . - _:Be71420d1950409879598226239777998 . - . - "2021-01-06T13:03:51.107Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Be1a4a91cdf362f795f68512a47c30f43 . - "10590560"^^ . - . - . - "2021-01-06T12:58:25.483Z"^^ . - "2021-01-06T18:05:35.713Z"^^ . - _:Bf266a50528ceb0a7c12262a1a1185b97 . - . - _:B5be6e2c6855c7513994e8afc3df71b2d . - "2930 Brasschaat, Kasteellei 27: Huisaansluitingen/herstel kolken"^^ . - _:B7c61e3880ca6576368edc137a7160f1b . -_:Bf57ccb8d13ae1bda8b4cb280fbcda52b "https://gipod.vlaanderen.be"@nl-BE . -_:Bf57ccb8d13ae1bda8b4cb280fbcda52b "10590517"^^ . -_:Bf57ccb8d13ae1bda8b4cb280fbcda52b . -_:Bde2223a30da28e19d640b8eaa7085ae8 "2021-01-11T05:00:00Z"^^ . -_:Bde2223a30da28e19d640b8eaa7085ae8 "2021-01-18T18:00:00Z"^^ . -_:Bde2223a30da28e19d640b8eaa7085ae8 . - . - . - "9197109"^^ . -_:B205ccd1aac196f1e67116ff80182fdc5 "Stad Tielt"^^ . -_:B205ccd1aac196f1e67116ff80182fdc5 . -_:B205ccd1aac196f1e67116ff80182fdc5 . -_:B22bef797dfc603dc747542d467fc6dd3 " POLYGON ((171088.24058634826 173503.28748832457, 171087.53622004075 173502.39024670795, 171086.77761133027 173503.2344986247, 171087.71911423164 173503.85025914572, 171088.24058634826 173503.28748832457))"^^ . -_:B22bef797dfc603dc747542d467fc6dd3 . -_:B785cb56d7d1967873b3a296aa8e09dc2 " POLYGON ((77132.1989004824 188154.725852623, 77132.4710017058 188154.443578499, 77132.6828056306 188154.113643878, 77132.826172751 188153.748727962, 77132.8955935488 188153.362854265, 77132.8884002218 188152.970851698, 77132.8048692055 188152.587784699, 77132.6482105499 188152.228374317, 77132.4244445594 188151.906432493, 77132.1421704355 188151.634331269, 77131.8122358144 188151.422527345, 77131.4473198986 188151.279160224, 77131.0614462022 188151.209739426, 77130.6694436348 188151.216932753, 77130.2863766354 188151.30046377, 77129.9269662538 188151.457122425, 77129.6050244294 188151.680888416, 77123.162888118 188157.168671514, 77122.8907868947 188157.450945638, 77122.6789829698 188157.780880259, 77122.5356158494 188158.145796174, 77122.4661950516 188158.531669871, 77122.4733883786 188158.923672438, 77122.5569193949 188159.306739438, 77122.7135780505 188159.666149819, 77122.937344041 188159.988091644, 77123.2196181649 188160.260192867, 77123.549552786 188160.471996792, 77123.9144687018 188160.615363912, 77124.3003423982 188160.68478471, 77124.6923449656 188160.677591383, 77125.075411965 188160.594060367, 77125.4348223466 188160.437401711, 77125.756764171 188160.213635721, 77132.1989004824 188154.725852623))"^^ . -_:B785cb56d7d1967873b3a296aa8e09dc2 . -_:Bf0a04db3f557fb15fd6ca279acdae8a4 "https://gipod.vlaanderen.be"@nl-BE . -_:Bf0a04db3f557fb15fd6ca279acdae8a4 "10590350"^^ . -_:Bf0a04db3f557fb15fd6ca279acdae8a4 . -_:B928a41e281fc8b018c5efd475c90abbe " POLYGON ((174191.3894077481 174368.24801226612, 174190.8263896183 174367.53941342887, 174192.38893511918 174366.41708203964, 174192.9519531588 174367.12568119168, 174191.3894077481 174368.24801226612))"^^ . -_:B928a41e281fc8b018c5efd475c90abbe . -_:Bb39d60a483a56971a305870639928784 "https://gipod.vlaanderen.be"@nl-BE . -_:Bb39d60a483a56971a305870639928784 "10590421"^^ . -_:Bb39d60a483a56971a305870639928784 . -_:B00d497007e4f44fd4a97f0789cb17795 " POLYGON ((68520.40472029004 179360.71906294208, 68518.34998572961 179355.61931990366, 68516.02563640152 179356.5509911757, 68518.08037289396 179361.6507324269, 68520.13510543837 179366.75046946388, 68522.45945090259 179365.81880177278, 68520.40472029004 179360.71906294208))"^^ . -_:B00d497007e4f44fd4a97f0789cb17795 . -_:B2a5ab523cbc62df14a4785c8d37fcca6 "https://gipod.vlaanderen.be"@nl-BE . -_:B2a5ab523cbc62df14a4785c8d37fcca6 "10590559"^^ . -_:B2a5ab523cbc62df14a4785c8d37fcca6 . - "2021-01-06T18:04:56.08Z"^^ . - _:B9a8d7b4d9d224982671e3eb860f54824 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B0f94dd5e70be878162d2f30756c2779b . - _:B0e05600695c89310970109cffae18501 . - _:Bff1a408e4952ed83b56cff9782d36357 . - "10590452"^^ . - "2021-01-06T14:14:46.913Z"^^ . - . - . - . - _:Bd9778cd8e5b43be2c6a012854d777ef3 . - "2021-01-06T14:39:43.927Z"^^ . - . - "Verhuiswagen"^^ . - . - _:B3ecb70a472774fdffdf568dc8fcfc945 . - . - _:B19b841376c34fba55937c402d01c8b93 . - _:B0acc8fb377efd68aab75543c706628a6 . - "Wegeniswerken Werken in opdracht van Proximus: aanleggen van ondergrondse leidingen.\nGraafwerken in de Fonteinstraat tussen de huisnummers 131-139."^^ . - . - _:Bf0e298b05b0cd7ce154e1ce97882292a . - _:B0f795455c27ebc3c2da91f040512823e . - "2021-01-06T12:52:03.727Z"^^ . - "2021-01-06T18:05:39.513Z"^^ . - _:Bd1da7ee37c9f2312d2632c3039f6cb85 . - . - "2021-01-06T13:12:40.803Z"^^ . - "10590576"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . -_:Bcef58f5944fdbfea27742ee59a6ad1b0 "Stad Turnhout"^^ . -_:Bcef58f5944fdbfea27742ee59a6ad1b0 . -_:Bcef58f5944fdbfea27742ee59a6ad1b0 . -_:B98021c0dc6abfb9b4f4d50e9e457086c "Gemeente Deerlijk"^^ . -_:B98021c0dc6abfb9b4f4d50e9e457086c . -_:B98021c0dc6abfb9b4f4d50e9e457086c . -_:B4964418fc655cbdffd242f3b419513a0 "Gemeente Beveren"^^ . -_:B4964418fc655cbdffd242f3b419513a0 . -_:B4964418fc655cbdffd242f3b419513a0 . -_:B0d2fea95dcced889bf72ae4f0dcc9d31 "Politiezone Leuven"^^ . -_:B0d2fea95dcced889bf72ae4f0dcc9d31 . -_:B0d2fea95dcced889bf72ae4f0dcc9d31 . -_:B738fe87482258b7467c9b27f5cfa4182 " POLYGON ((95709.59942575457 159869.45180216053, 95709.6729915256 159869.45447872087, 95709.74616106699 159869.4625598628, 95709.81853786667 159869.4760017939, 95709.88972970846 159869.4947316712, 95709.9361612089 159869.5100425452, 95709.98178887989 159869.52760451366, 95710.02650365727 159869.54737559805, 95710.07019865901 159869.56930853942, 95710.11276944065 159869.59335091134, 95710.1541142449 159869.6194452451, 95710.19413424503 159869.6475291673, 95710.23273378093 159869.6775355487, 95710.26982058786 159869.7093926648, 95710.30530601695 159869.74302436737, 95710.33910524713 159869.77835026628, 95710.37113748788 159869.8152859218, 95710.40132617229 159869.85374304635, 95710.42959914013 159869.8936297156, 95710.45588881033 159869.93485058818, 95710.48013234252 159869.97730713352, 95710.50227178719 159870.02089786745, 95710.52225422428 159870.06551859473, 95710.54003188963 159870.1110626581, 95710.55556228916 159870.15742119332, 95710.56880830042 159870.20448338919, 95710.57973826141 159870.25213675262, 95710.58832604617 159870.3002673775, 95710.59455112723 159870.34876021676, 95710.59839862474 159870.39749935767, 95710.59985934201 159870.44636829873, 95710.59892978748 159870.49525022815, 95710.59561218305 159870.54402830312, 95710.58991445885 159870.59258592903, 95710.58185023414 159870.64080703823, 95710.57143878494 159870.68857636754, 95710.55870499779 159870.7357797335, 95710.55694449382 159870.7416576635, 95708.90069449382 159876.2104076635, 95708.8988979567 159876.21627468054, 95708.88330247259 159876.26261136116, 95708.86546086862 159876.308130415, 95708.8454157917 159876.35272303756, 95708.8232151557 159876.39628263877, 95708.79891202698 159876.43870509777, 95708.77256449747 159876.4798890119, 95708.74423554585 159876.519735939, 95708.71399288703 159876.55815063254, 95708.68190881023 159876.59504126973, 95708.64806000628 159876.63031967057, 95708.61252738419 159876.66390150887, 95708.57539587785 159876.69570651368, 95708.53675424296 159876.72565866134, 95708.49669484489 159876.75368635694, 95708.4553134379 159876.77972260572, 95708.41270893627 159876.80370517308, 95708.36898317785 159876.82557673324, 95708.3242406806 159876.84528500654, 95708.27858839286 159876.8627828841, 95708.2321354376 159876.87802854064, 95708.18499285166 159876.89098553435, 95708.1372733203 159876.90162289407, 95708.08909090784 159876.9099151932, 95708.04056078506 159876.9158426106, 95707.99179895382 159876.9193909779, 95707.94292196991 159876.92055181353, 95707.89404666433 159876.91932234258, 95707.84528986404 159876.91570550398, 95707.79676811279 159876.90970994302, 95707.74859739246 159876.90134999098, 95707.70089284588 159876.89064563066, 95707.65376850154 159876.8776224488, 95707.6073370011 159876.8623115748, 95707.56170933011 159876.84474960636, 95707.51699455273 159876.82497852197, 95707.47329955098 159876.8030455806, 95707.43072876935 159876.77900320868, 95707.3893839651 159876.7529088749, 95707.34936396497 159876.72482495272, 95707.31076442907 159876.69481857133, 95707.27367762214 159876.6629614552, 95707.23819219305 159876.62932975264, 95707.20439296287 159876.59400385374, 95707.17236072212 159876.55706819822, 95707.14217203771 159876.51861107367, 95707.11389906987 159876.4787244044, 95707.08760939966 159876.43750353184, 95707.06336586748 159876.3950469865, 95707.0412264228 159876.35145625257, 95707.02124398571 159876.3068355253, 95707.00346632037 159876.2612914619, 95706.98793592084 159876.2149329267, 95706.97468990958 159876.16787073083, 95706.96375994859 159876.1202173674, 95706.95517216383 159876.07208674253, 95706.94894708277 159876.02359390326, 95706.94509958525 159875.97485476235, 95706.94363886799 159875.9259858213, 95706.94456842252 159875.87710389186, 95706.94788602694 159875.8283258169, 95706.95358375115 159875.779768191, 95706.96164797586 159875.73154708178, 95706.97205942505 159875.68377775248, 95706.9847932122 159875.6365743865, 95706.98655371618 159875.63069645653, 95708.64280371618 159870.16194645653, 95708.6446002533 159870.15607943948, 95708.6710594672 159870.08125736818, 95708.70336875728 159870.00876914753, 95708.74132462563 159869.93907133973, 95708.78468800982 159869.8726029317, 95708.83318578848 159869.80978257017, 95708.88651250163 159869.75100592498, 95708.9443322746 159869.69664319683, 95709.00628093343 159869.64703678573, 95709.07196829871 159869.60249913426, 95709.14098064299 159869.5633107598, 95709.21288329671 159869.5297184877, 95709.28722338585 159869.50193389662, 95709.3635326844 159869.4801319859, 95709.4413305634 159869.46445007343, 95709.52012701817 159869.45498693065, 95709.59942575457 159869.45180216053))"^^ . -_:B738fe87482258b7467c9b27f5cfa4182 . -_:B14da98d5abe8e909ec149aad423c20e2 "Gemeente Beveren"^^ . -_:B14da98d5abe8e909ec149aad423c20e2 . -_:B14da98d5abe8e909ec149aad423c20e2 . -_:Bf0617b52f987877b3573e05769e60456 "2021-01-14T00:00:00Z"^^ . -_:Bf0617b52f987877b3573e05769e60456 "2021-01-15T00:00:00Z"^^ . -_:Bf0617b52f987877b3573e05769e60456 . - . - _:B08d6acae7ebe70d02b212a828e43039b . - . -_:B3116cdf962227edf601b9edad0a3b920 " POLYGON ((94351.8840847089 208323.761665583, 94353.0961087595 208325.948214851, 94346.9737708095 208329.341882193, 94345.7617467589 208327.155332925, 94351.8840847089 208323.761665583))"^^ . -_:B3116cdf962227edf601b9edad0a3b920 . - _:B19437d4952a0913cee4a441cd474b1bd . - "2021-01-06T18:05:34.92Z"^^ . - . - _:B56cc145d4861dd139d0205ab2d155d2e . - "10590557"^^ . - . - . - "Verhuiswagen 7u - 18u"^^ . - "2021-01-06T13:00:09.02Z"^^ . - _:B49136a5a48f17a05bbde08c76e0a04bc . - . - _:B5e298795be82e27cfd9cff2ff66cf6d5 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bab86dc31f176dc6eb0f88d451f5f02e0 . - "2021-01-06T14:56:19.34Z"^^ . -_:Bcaa6988d7d511281fa8e7ab378d264cd "https://gipod.vlaanderen.be"@nl-BE . -_:Bcaa6988d7d511281fa8e7ab378d264cd "10590391"^^ . -_:Bcaa6988d7d511281fa8e7ab378d264cd . - . - "10590372"^^ . - "2021-01-06T15:17:40.663Z"^^ . - . - _:B82b045c6adf2930094670bbc20033382 . - _:Bc8619ae7511313a970f228c4317bc6dc . - _:B291299e8a658cc0a1855bc84d03acadc . - . - _:B9719549b387d7e8909cfd26c7f7e40ef . - _:Bdfb6587c8512afff810811f99296faca . - "2021-01-06T15:23:39.977Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:30.76Z"^^ . - . - "2930 Brasschaat, Lage Kaart 178: Parkeerverbod"^^ . -_:Bbbdfa8aa8df793047dd4fb79e6a73a63 "Politiezone Leuven"^^ . -_:Bbbdfa8aa8df793047dd4fb79e6a73a63 . -_:Bbbdfa8aa8df793047dd4fb79e6a73a63 . -_:Bebcc1fa52a1d5312b02f11a4df937f07 "Gemeente Hemiksem"^^ . -_:Bebcc1fa52a1d5312b02f11a4df937f07 . -_:Bebcc1fa52a1d5312b02f11a4df937f07 . -_:Bf93ec36bf8f839dbbafe4139b7fd8ec8 "Politiezone Leuven"^^ . -_:Bf93ec36bf8f839dbbafe4139b7fd8ec8 . -_:Bf93ec36bf8f839dbbafe4139b7fd8ec8 . -_:B05c0e6fd593ba5ad69fda1653ab0937b "2021-01-14T06:00:00Z"^^ . -_:B05c0e6fd593ba5ad69fda1653ab0937b "2021-01-14T16:00:00Z"^^ . -_:B05c0e6fd593ba5ad69fda1653ab0937b . - "2021-01-06T16:20:02.927Z"^^ . - . - "2021-01-06T16:10:41.617Z"^^ . - _:Bbc29b6270de0c3d39e094fc5b939877a . - _:B7163545dc583a3b50abd3fb0ff148539 . - "10590348"^^ . - _:B5ee22c6a64b51f6d71eba15c322df445 . - . - "2021-01-06T18:04:18.51Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "9160 Lokeren, Eksaarde-dorp 74: Stelling"^^ . - . - _:B7a06567d7b71f145186e4e8d37238a77 . - . - _:B52b9cb23789072d466fb172f96660dd6 . -_:Ba5b7839048a4b77d54513101517f90dc "2021-01-09T05:00:00Z"^^ . -_:Ba5b7839048a4b77d54513101517f90dc "2021-01-22T18:00:00Z"^^ . -_:Ba5b7839048a4b77d54513101517f90dc . - . - . - _:B13a02aedc9a75b04ea57efaba1fe173e . - . -_:B0a8172fcbe75ef027c26e7e0d68da676 " POLYGON ((172914.5563226305 175196.32643701695, 172915.2037441763 175195.5637636492, 172919.02741263463 175198.79230315145, 172918.37999092648 175199.55497557763, 172914.5563226305 175196.32643701695))"^^ . -_:B0a8172fcbe75ef027c26e7e0d68da676 . -_:B0bb31d5873d93cea29cc79f0e14da762 "2021-02-09T05:00:00Z"^^ . -_:B0bb31d5873d93cea29cc79f0e14da762 "2021-02-15T18:00:00Z"^^ . -_:B0bb31d5873d93cea29cc79f0e14da762 . -_:Bbdb7411539917c7989616215cc879d78 " POLYGON ((217917.83618633472 180690.54738314077, 217918.67536173694 180692.36240330245, 217914.1258174657 180694.45442769583, 217913.28664083692 180692.6394090047, 217917.83618633472 180690.54738314077))"^^ . -_:Bbdb7411539917c7989616215cc879d78 . - . - . - . - . - . - _:Bca5e765fd113d3a3e8bbc6be9c7b720d . - . -_:Bca18ed5f789a175741c5261cabde0525 "Stad Turnhout"^^ . -_:Bca18ed5f789a175741c5261cabde0525 . -_:Bca18ed5f789a175741c5261cabde0525 . -_:B542295ae8b3acf587c59a171b2d13932 "2021-03-28T12:00:00Z"^^ . -_:B542295ae8b3acf587c59a171b2d13932 "2021-03-28T16:00:00Z"^^ . -_:B542295ae8b3acf587c59a171b2d13932 . - . - . - "9197184"^^ . -_:Bc91983e5d5167edf5c99eebdb7df282f "https://gipod.vlaanderen.be"@nl-BE . -_:Bc91983e5d5167edf5c99eebdb7df282f "10590346"^^ . -_:Bc91983e5d5167edf5c99eebdb7df282f . - . - _:B75bef9dbeb51ccea94ae7fa51663fec4 . - . -_:Bd47dd681ab36e8118690338c179a8936 "Stad Turnhout"^^ . -_:Bd47dd681ab36e8118690338c179a8936 . -_:Bd47dd681ab36e8118690338c179a8936 . - . - _:B4a5b84a05510f5e6e1fbbf03ccece0b6 . - . - "Wisselend verkeer via verkeersborden"@nl-BE . -_:B9bc74760910b9e4af03cd6e116f2e8d3 "https://gipod.vlaanderen.be"@nl-BE . -_:B9bc74760910b9e4af03cd6e116f2e8d3 "10590556"^^ . -_:B9bc74760910b9e4af03cd6e116f2e8d3 . -_:Bed0dcf7cc620a57b844e6506eeff3ac5 "https://gipod.vlaanderen.be"@nl-BE . -_:Bed0dcf7cc620a57b844e6506eeff3ac5 "10590537"^^ . -_:Bed0dcf7cc620a57b844e6506eeff3ac5 . -_:B85673478c049f1f0a8a484d58c96ef05 "Gemeente Beveren"^^ . -_:B85673478c049f1f0a8a484d58c96ef05 . -_:B85673478c049f1f0a8a484d58c96ef05 . - . - "2021-01-06T14:14:52.36Z"^^ . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B9da030f9f5d2538c86b4d8043903a27f . - _:Bf040d48e716a50378e3a458c0e48e047 . - "2021-01-06T18:04:55.827Z"^^ . - "8000 Brugge, Potterierei 23: Doorlopende vergunning"^^ . - . - "2021-01-06T14:14:52.36Z"^^ . - _:Be3f9fd636e29e599d0dc48a50208a65b . - _:B90957ccea685a12c61253aaa65f64370 . - "10590451"^^ . - _:Bbb219cc7d3ad42689784723f5bb230db . -_:B6a7387773f916dd7f787bdce6c90cc7f "Politiezone Brugge"^^ . -_:B6a7387773f916dd7f787bdce6c90cc7f . -_:B6a7387773f916dd7f787bdce6c90cc7f . - . - . - "9197272"^^ . -_:B446ad098c4f693f9e264b7da6625d488 "2021-01-13T23:00:00Z"^^ . -_:B446ad098c4f693f9e264b7da6625d488 "2021-01-14T22:30:00Z"^^ . -_:B446ad098c4f693f9e264b7da6625d488 . - . - _:B5fa870dd2dc6d91b04aeb096d1b98c23 . - . -_:Bec004dc9f2d430c6c5e2af72e0f55b64 "Politiezone Brugge"^^ . -_:Bec004dc9f2d430c6c5e2af72e0f55b64 . -_:Bec004dc9f2d430c6c5e2af72e0f55b64 . -_:Bb997ce0622948a9144f3a55d0a69164a "Gemeente Brasschaat"^^ . -_:Bb997ce0622948a9144f3a55d0a69164a . -_:Bb997ce0622948a9144f3a55d0a69164a . - . - . - "9197032"^^ . -_:B1e2cdac0b2a4abadd46af68544ac7a17 "Politiezone Leuven"^^ . -_:B1e2cdac0b2a4abadd46af68544ac7a17 . -_:B1e2cdac0b2a4abadd46af68544ac7a17 . - . - . - "9197011"^^ . - . - _:B785cb56d7d1967873b3a296aa8e09dc2 . - . - . - . - . - _:Bde9543222a08124bf455d729c055d030 . - . -_:Bdfc0a7787135f967dfa4e3177dd3a822 "https://gipod.vlaanderen.be"@nl-BE . -_:Bdfc0a7787135f967dfa4e3177dd3a822 "10590423"^^ . -_:Bdfc0a7787135f967dfa4e3177dd3a822 . -_:B414ca49d17bb153735adff686583c531 "Stad Hasselt"^^ . -_:B414ca49d17bb153735adff686583c531 . -_:B414ca49d17bb153735adff686583c531 . -_:Beaf8dace6a39b48f9dd90fd9e4445c86 " POLYGON ((173804.66027183106 174267.86463133618, 173802.0782463079 174264.88764456753, 173804.7774286735 174262.87609610893, 173807.12435311993 174265.6637453083, 173804.66027183106 174267.86463133618))"^^ . -_:Beaf8dace6a39b48f9dd90fd9e4445c86 . - . - . - "9197024"^^ . - _:B6470b2e30fe79019e6f213303d3c9c11 . - _:B8aee7861fd2ed37be417707ff482da36 . - . - "2021-01-06T18:04:14.85Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B6eae231f45c832a1d5228086f91d81db . - . - "Stelling Promostand constructie uit scaff/truss materiaal met een bedrukte beursballon op tvv Ekonomika LCC"^^ . - _:B231efb1aa701fd438d0f131ce31c9c5c . - "2021-01-06T16:49:39.123Z"^^ . - . - . - "10590335"^^ . - _:B632997c520c8674af167f131a5ab31c7 . - "2021-01-06T16:49:39.123Z"^^ . -_:B273c08cfe90e6c30a274f729cc85b7d7 "Stad Tielt"^^ . -_:B273c08cfe90e6c30a274f729cc85b7d7 . -_:B273c08cfe90e6c30a274f729cc85b7d7 . - . - _:B1adb4e80e880d229954b49f393f03106 . - . -_:Ba1e1f76239a60fdb9dbed73297db918c "2021-01-27T23:00:00Z"^^ . -_:Ba1e1f76239a60fdb9dbed73297db918c "2021-01-28T22:30:00Z"^^ . -_:Ba1e1f76239a60fdb9dbed73297db918c . - "2021-01-06T16:05:37.427Z"^^ . - _:Bd662bb83abcce314c54556dca4fe0ed2 . - . - "2021-01-06T18:04:19.083Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - _:B082b3c66d0399557d861cff7107a5f9c . - "8770 Ingelmunster, Kortrijkstraat: Container/Werfkeet/Werfvoertuigen"^^ . - _:B5b79b2110a2493e0f1ef78a16a8b6e86 . - _:B3a65f94be4764d7596a634d1d42278ce . - "10590349"^^ . - _:B3e28b351247991999af12953754cc8fb . - "2021-01-06T16:05:37.427Z"^^ . - . -_:B1c50cfe5f97d54aaac1dd3937addbb82 "Gemeente Beveren"^^ . -_:B1c50cfe5f97d54aaac1dd3937addbb82 . -_:B1c50cfe5f97d54aaac1dd3937addbb82 . -_:B6ee5e3dd0a877a618286d888fbc51600 "Politiezone Brugge"^^ . -_:B6ee5e3dd0a877a618286d888fbc51600 . -_:B6ee5e3dd0a877a618286d888fbc51600 . - . - _:B893cd035b61ca31120a60cb26dba1105 . - . -_:Be478da6448e8aaed339edc3c37f5113d "Stad Mechelen"^^ . -_:Be478da6448e8aaed339edc3c37f5113d . -_:Be478da6448e8aaed339edc3c37f5113d . - . - _:Be2f45c5a405d04b9351b4748412721ac . - . -_:B44c24c77b503a37ce686089fc777ff24 " MULTIPOLYGON (((71098.7379638828 210659.290238118, 71099.1298183932 210659.30319186, 71099.5116163794 210659.392343722, 71099.8686855588 210659.554267648, 71106.5076281872 210663.390101167, 71168.3192576188 210692.583063501, 71168.6556573047 210692.784441275, 71168.94630631 210693.047577956, 71169.1800351566 210693.362361346, 71169.3478617758 210693.716694498, 71169.4433366849 210694.096960587, 71169.4627908366 210694.488546201, 71169.4054766188 210694.876402923, 71169.2735965847 210695.245625639, 71169.0722188101 210695.582025325, 71168.8090821299 210695.87267433, 71168.4942987392 210696.106403176, 71168.1399655872 210696.274229796, 71167.7596994981 210696.369704705, 71167.3681138845 210696.389158856, 71166.980257162 210696.331844639, 71166.6110344468 210696.199964605, 71104.724596397 210666.971670971, 71104.5781527872 210666.894950566, 71097.8675751673 210663.017727941, 71097.5489567629 210662.789254597, 71097.2810334602 210662.503011936, 71097.0741014014 210662.170000105, 71096.9361128694 210661.803016561, 71096.8723706863 210661.416164275, 71096.8853244283 210661.024309765, 71096.9744762904 210660.642511778, 71097.1364002166 210660.285442599, 71097.3648735611 210659.966824195, 71097.6511162215 210659.698900892, 71097.9841280528 210659.491968833, 71098.3511115972 210659.353980301, 71098.7379638828 210659.290238118)), ((71028.70657972 210614.251909277, 71029.097906611 210614.276013658, 71029.477011734 210614.375998969, 71029.8293262919 210614.548022831, 71086.1981782988 210649.293902507, 71086.5101630406 210649.531354139, 71086.7698285676 210649.825108409, 71086.9671960794 210650.163876504, 71087.094680853 210650.534639756, 71087.1473837202 210650.923149942, 71087.1232793393 210651.314476833, 71087.0232940281 210651.693581956, 71086.8512701662 210652.045896514, 71086.6138185339 210652.357881256, 71086.3200642644 210652.617546783, 71085.9812961696 210652.814914294, 71085.6105329173 210652.942399068, 71085.2220227314 210652.995101935, 71084.8306958404 210652.970997554, 71084.4515907173 210652.871012243, 71084.0992761595 210652.698988381, 71027.7304241526 210617.953108705, 71027.4184394108 210617.715657073, 71027.1587738838 210617.421902803, 71026.961406372 210617.083134708, 71026.8339215984 210616.712371456, 71026.7812187312 210616.32386127, 71026.8053231121 210615.932534379, 71026.9053084233 210615.553429256, 71027.0773322852 210615.201114698, 71027.3147839175 210614.889129957, 71027.6085381869 210614.62946443, 71027.9473062818 210614.432096918, 71028.3180695341 210614.304612144, 71028.70657972 210614.251909277)))"^^ . -_:B44c24c77b503a37ce686089fc777ff24 . - . - _:Be95c81506ffbb01b5ed528af8ba00887 . - . -_:Bc6a037e9a6db8a8450d073084368e015 "Stad Hasselt"^^ . -_:Bc6a037e9a6db8a8450d073084368e015 . -_:Bc6a037e9a6db8a8450d073084368e015 . -_:B9269de8ac563a30ccf7b7ce5e2eb0e79 "https://gipod.vlaanderen.be"@nl-BE . -_:B9269de8ac563a30ccf7b7ce5e2eb0e79 "10590381"^^ . -_:B9269de8ac563a30ccf7b7ce5e2eb0e79 . -_:B14c5091b1b6bf6312621f1196d4d46ae "https://gipod.vlaanderen.be"@nl-BE . -_:B14c5091b1b6bf6312621f1196d4d46ae "10590567"^^ . -_:B14c5091b1b6bf6312621f1196d4d46ae . -_:B350c7f0abc650b45fba3af67a9021cf9 "2021-01-18T08:00:00Z"^^ . -_:B350c7f0abc650b45fba3af67a9021cf9 "2021-01-18T12:00:00Z"^^ . -_:B350c7f0abc650b45fba3af67a9021cf9 . - . - _:B09d8f38501bb6602a10c04d250cf9e6e . - . - "10590546"^^ . - "2021-01-06T18:05:31.25Z"^^ . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B3b9131646e8134379924ca8dc82908ca . - . - "2021-01-06T13:07:06.46Z"^^ . - _:B906f41c78f27e038eb636ecc533ce1b3 . - _:B75cfecdee28a4cc2d8bc6936098785ff . - "9890 Gavere, Onderstraat 110: Laattijdige aanvraag"^^ . - _:B8734503d07333eb32d193999b41a0320 . - _:B3aa11492cc0ff08fcfef33311fed33da . - . - "2021-01-06T13:07:06.46Z"^^ . - . - _:Bf6bb695d6221acc6250aea322a721f65 . - . -_:B1ea8d63399b224f04af8dc2c7b06ea23 "2021-01-20T05:30:00Z"^^ . -_:B1ea8d63399b224f04af8dc2c7b06ea23 "2021-02-19T18:00:00Z"^^ . -_:B1ea8d63399b224f04af8dc2c7b06ea23 . -_:B77e7c7a24be86eadeb335db97e11fef3 " POLYGON ((158722.048311066 216158.12569574, 158723.338544081 216156.597527305, 158734.799807348 216166.274274916, 158733.509574333 216167.802443352, 158722.048311066 216158.12569574))"^^ . -_:B77e7c7a24be86eadeb335db97e11fef3 . -_:B524d26653889ac657c519464212d5b24 "Stad Mechelen"^^ . -_:B524d26653889ac657c519464212d5b24 . -_:B524d26653889ac657c519464212d5b24 . - . - . - "9197125"^^ . -_:Bbe82dd83c7b37e7e1eb1a78c75376466 "Politiezone Leuven"^^ . -_:Bbe82dd83c7b37e7e1eb1a78c75376466 . -_:Bbe82dd83c7b37e7e1eb1a78c75376466 . - _:Bda652be0c673821eedde8b8e5191ab80 . - "Container"^^ . - _:B89e48d84e85dd0301e9cddda0951eff5 . - . - _:B474cccd608b1809a1885195ec224500b . - "2021-01-06T18:04:15.35Z"^^ . - . - _:B881e9d09ef8771b20c21ea1684ce431a . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B4895b09e9d7f2738250d0a6adcb95693 . - "2021-01-06T16:45:10.993Z"^^ . - "10590337"^^ . - "2021-01-06T16:45:10.993Z"^^ . - . -_:B90d371b504770ee2cc24ce847bad4b40 "Politiezone Leuven"^^ . -_:B90d371b504770ee2cc24ce847bad4b40 . -_:B90d371b504770ee2cc24ce847bad4b40 . -_:B314af7fb2e14261df9489ba0c801880f "Politiezone Brugge"^^ . -_:B314af7fb2e14261df9489ba0c801880f . -_:B314af7fb2e14261df9489ba0c801880f . - . - . - "9197192"^^ . -_:Bfa3ad8539cc2af07b3ad054b1bd79d3a "Stad Lokeren"^^ . -_:Bfa3ad8539cc2af07b3ad054b1bd79d3a . -_:Bfa3ad8539cc2af07b3ad054b1bd79d3a . - . - . - "9197138"^^ . - . - . - "9197117"^^ . - . - _:Bd6f06861a4222e76fe9d45816bcbc242 . - . -_:B62ca47ea90f2325137ab476fb29f6a95 "Gemeente Kapellen"^^ . -_:B62ca47ea90f2325137ab476fb29f6a95 . -_:B62ca47ea90f2325137ab476fb29f6a95 . -_:Bd85e2db30c9e7afd92b54ef8fb50d326 "https://gipod.vlaanderen.be"@nl-BE . -_:Bd85e2db30c9e7afd92b54ef8fb50d326 "10590534"^^ . -_:Bd85e2db30c9e7afd92b54ef8fb50d326 . -_:B2a0b7ae51f90d0be034e384d5ba17d89 "https://gipod.vlaanderen.be"@nl-BE . -_:B2a0b7ae51f90d0be034e384d5ba17d89 "10590539"^^ . -_:B2a0b7ae51f90d0be034e384d5ba17d89 . - "2800 Mechelen, Schuttersvest 5: Verhuis"^^ . - _:B30158b77d17b9dfcd02da1cc4fdf877e . - _:Be478da6448e8aaed339edc3c37f5113d . - _:B916c3fa133826b761aaf7e6fa1dee17c . - "10590461"^^ . - _:B3568fbe4d682666665932ca93847bed2 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:11:40.437Z"^^ . - . - . - "2021-01-06T18:05:00.23Z"^^ . - . - "2021-01-06T14:10:30.477Z"^^ . - . - _:Bf97303c8aa55aac4b88f238213041db9 . -_:B52cfba17ee38fd79ee713c96ed96f012 "2021-01-14T06:00:00Z"^^ . -_:B52cfba17ee38fd79ee713c96ed96f012 "2021-01-14T16:00:00Z"^^ . -_:B52cfba17ee38fd79ee713c96ed96f012 . -_:B36c086481ee8771d8f33f6fe8ffee4bb "Politiezone Leuven"^^ . -_:B36c086481ee8771d8f33f6fe8ffee4bb . -_:B36c086481ee8771d8f33f6fe8ffee4bb . -_:B7163545dc583a3b50abd3fb0ff148539 "Stad Lokeren"^^ . -_:B7163545dc583a3b50abd3fb0ff148539 . -_:B7163545dc583a3b50abd3fb0ff148539 . - . - . - "9197280"^^ . -_:B9e3b8a7140e95a264a962e02368fa878 " POLYGON ((176791.7191854729 174434.84084967244, 176788.30413388685 174439.15439939033, 176790.2701403684 174440.70259499922, 176793.6851925787 174436.3890478285, 176797.10025041996 174432.07549932506, 176795.13424268976 174430.52729861345, 176791.7191854729 174434.84084967244))"^^ . -_:B9e3b8a7140e95a264a962e02368fa878 . - "10590391"^^ . - "2021-01-06T14:58:57.523Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bcaa6988d7d511281fa8e7ab378d264cd . - . - _:Bfb4e959b95a12092c457085807e3173d . - "2811 Mechelen, Kapellebaan 38: Nutswerken / Verlenging"^^ . - _:B7287ebd16c0effc733bbab41dad55fbf . - "2021-01-06T15:00:06.85Z"^^ . - _:B9cbdb1cf3440ec0d4eab55b2d5a66324 . - "2021-01-06T18:04:37.64Z"^^ . - . - . - _:Bc18884e2413f8e292f0d31c9b68381a2 . - . -_:B1c927bfb741d9ec081eaf2a47c522c2e "Stad Izegem"^^ . -_:B1c927bfb741d9ec081eaf2a47c522c2e . -_:B1c927bfb741d9ec081eaf2a47c522c2e . - "Onbekend"@nl-BE . -_:B961716da1d25bb3e1ecd92f0b3e56575 " POLYGON ((68808.07225351872 179476.44845454302, 68809.90169435472 179481.63284581713, 68812.26461285593 179480.80330736842, 68810.435174101 179475.61891447753, 68808.60573178384 179470.4345170539, 68806.24280912029 179471.2640587287, 68808.07225351872 179476.44845454302))"^^ . -_:B961716da1d25bb3e1ecd92f0b3e56575 . -_:B684ad70c617f15e86d92c5859f951fee " POLYGON ((141219.496072711 210840.917393481, 141219.275496844 210840.59325764, 141218.995923514 210840.318382195, 141218.668096569 210840.103330456, 141218.304614213 210839.956366739, 141217.91944487 210839.88313878, 141217.527390382 210839.886460686, 141217.143517183 210839.966204799, 141216.782577304 210840.119306597, 141216.458441463 210840.339882464, 141216.183566018 210840.619455794, 141215.968514278 210840.947282739, 141215.821550562 210841.310765095, 141215.748322602 210841.695934438, 141215.751644508 210842.087988926, 141215.831388621 210842.471862125, 141215.984490419 210842.832802004, 141216.879234102 210844.473165422, 141217.099809969 210844.797301263, 141217.379383299 210845.072176708, 141217.707210244 210845.287228448, 141218.0706926 210845.434192164, 141218.455861943 210845.507420124, 141218.847916431 210845.504098218, 141219.23178963 210845.424354105, 141219.592729509 210845.271252307, 141219.91686535 210845.050676439, 141220.191740795 210844.77110311, 141220.406792535 210844.443276164, 141220.553756251 210844.079793809, 141220.626984211 210843.694624466, 141220.623662305 210843.302569978, 141220.543918192 210842.918696778, 141220.390816394 210842.557756899, 141219.496072711 210840.917393481))"^^ . -_:B684ad70c617f15e86d92c5859f951fee . - . - "2021-01-06T13:23:46.657Z"^^ . - . - _:B0debbf3fddd4c425ad290d0d40857c38 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B2f1fd2bcf0cad9ce676210938b66bc27 . - _:B0129b437a37beb381d231ac2959a2986 . - "2021-01-06T18:05:22.777Z"^^ . - . - . - "2021-01-06T13:22:58.707Z"^^ . - "10590518"^^ . - "9120 Beveren, Albert Panisstraat 109: parkeerverbod voor werfvoertuigen"^^ . - _:B58406db8069692dc4bfa5ea27c21179a . - _:Bfeb4e2a8976e8d9f99aa826242fe6e41 . -_:B9238c6d216e37761d86c833d0ca89583 "2021-01-11T06:00:00Z"^^ . -_:B9238c6d216e37761d86c833d0ca89583 "2021-01-11T18:00:00Z"^^ . -_:B9238c6d216e37761d86c833d0ca89583 . -_:Bf31a9f0ea5369bf2a27df78fe880140f "Stad Kortrijk"^^ . -_:Bf31a9f0ea5369bf2a27df78fe880140f . -_:Bf31a9f0ea5369bf2a27df78fe880140f . -_:B8960eb842c90fbcc78959fa71e484da6 " POLYGON ((68095.3328868692 211331.866564061, 68099.7469611647 211335.922737242, 68108.4557942147 211310.750616791, 68105.1154232606 211305.859344044, 68095.3328868692 211331.866564061))"^^ . -_:B8960eb842c90fbcc78959fa71e484da6 . - . - _:B1a605cebe5af4bdcbecafa42d82c1af5 . - _:B5ed60047910d786058a4cdf96b6a8899 . - . - _:Bdfad8bc5392978b7a06327f830efc645 . - "2021-01-06T14:04:10.113Z"^^ . - . - . - "2021-01-06T18:05:06.327Z"^^ . - _:Bc862238d8ddc1885c53c44895c71eb82 . - "2930 Brasschaat, Molenweg 8: Verhuis met/zonder ladderlift"^^ . - "10590481"^^ . - "2021-01-06T13:51:28.127Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bd279c21fe103b5919dd6abf3bc45cf9b . - "2021-01-06T18:04:21.887Z"^^ . - "10590357"^^ . - . - . - "2021-01-06T15:50:30.58Z"^^ . - . - _:Be683844eb1c966774dd5b06eef703107 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2880 Bornem, Lindestraat 89: Container"^^ . - "2021-01-06T15:49:59.013Z"^^ . - _:B80f7698cc4a53b775869eaceb67223db . - _:B06a23e77a887a71a4d6547661e6ce81f . - _:B8971e76f175d56203b5eacef190d4dc9 . - . - _:B493b230cb18fcfaf5dad5c888ae4c1c0 . -_:B0e05600695c89310970109cffae18501 "https://gipod.vlaanderen.be"@nl-BE . -_:B0e05600695c89310970109cffae18501 "10590452"^^ . -_:B0e05600695c89310970109cffae18501 . -_:B097747e7f3b0c83434db8fcd0df9630a "2021-02-26T23:00:00Z"^^ . -_:B097747e7f3b0c83434db8fcd0df9630a "2021-02-27T22:30:00Z"^^ . -_:B097747e7f3b0c83434db8fcd0df9630a . - . - . - "9197360"^^ . - . - . - "9197045"^^ . -_:Ba0becedce673b730180685ed722187b5 "https://gipod.vlaanderen.be"@nl-BE . -_:Ba0becedce673b730180685ed722187b5 "10590512"^^ . -_:Ba0becedce673b730180685ed722187b5 . -_:B4b1df86a842da75755f71cceb6b73799 "Gemeente Ingelmunster"^^ . -_:B4b1df86a842da75755f71cceb6b73799 . -_:B4b1df86a842da75755f71cceb6b73799 . -_:B11f25870b71146e6a5e7e003b38af672 "https://gipod.vlaanderen.be"@nl-BE . -_:B11f25870b71146e6a5e7e003b38af672 "10590404"^^ . -_:B11f25870b71146e6a5e7e003b38af672 . -_:B2ad3a31d2b10d3f1a056dc56d81b14ee " POLYGON ((173424.48040871465 174590.13333670888, 173426.62177617787 174591.42966707423, 173423.50236304651 174596.55512105487, 173421.36099692143 174595.25879322644, 173424.48040871465 174590.13333670888))"^^ . -_:B2ad3a31d2b10d3f1a056dc56d81b14ee . -_:B4dd1eaae9e68b94b6d1edd6c185475d3 "Gemeente Tessenderlo"^^ . -_:B4dd1eaae9e68b94b6d1edd6c185475d3 . -_:B4dd1eaae9e68b94b6d1edd6c185475d3 . -_:B787b37ddbce483ccbc034b28899e20f3 "Gemeente Asse"^^ . -_:B787b37ddbce483ccbc034b28899e20f3 . -_:B787b37ddbce483ccbc034b28899e20f3 . -_:B03d19bae1a3213e4fef09ac6bab7f16b "Gemeente Kapellen"^^ . -_:B03d19bae1a3213e4fef09ac6bab7f16b . -_:B03d19bae1a3213e4fef09ac6bab7f16b . - . - . - "9197352"^^ . - . - _:B0f37adbf06d1fb29d5291a503803ed64 . - . -_:B87d0721a98b0c09191544d5ffb819183 "2021-01-31T23:00:00Z"^^ . -_:B87d0721a98b0c09191544d5ffb819183 "2021-02-19T22:30:00Z"^^ . -_:B87d0721a98b0c09191544d5ffb819183 . -_:B5e69612ab5b53ba72b0d3e948af99838 "Gemeente Brasschaat"^^ . -_:B5e69612ab5b53ba72b0d3e948af99838 . -_:B5e69612ab5b53ba72b0d3e948af99838 . -_:B51207760bc8c1ab4ff4bd95d867e5bef "Gemeente Brasschaat"^^ . -_:B51207760bc8c1ab4ff4bd95d867e5bef . -_:B51207760bc8c1ab4ff4bd95d867e5bef . - . - _:B208176cbe7ad80a85aea2af7af433ee2 . - . -_:B84fcc60a8a2dc896daf705cca3505ea1 "https://gipod.vlaanderen.be"@nl-BE . -_:B84fcc60a8a2dc896daf705cca3505ea1 "10590352"^^ . -_:B84fcc60a8a2dc896daf705cca3505ea1 . -_:B8896060a4f5e386e46e973e5ffbc8fbc "Gemeente Rumst"^^ . -_:B8896060a4f5e386e46e973e5ffbc8fbc . -_:B8896060a4f5e386e46e973e5ffbc8fbc . -_:Bc2930f3c909be5a7a0ce3f142621e2da "Stad Turnhout"^^ . -_:Bc2930f3c909be5a7a0ce3f142621e2da . -_:Bc2930f3c909be5a7a0ce3f142621e2da . -_:B3f29778ff784c7de6c24d2c508bfa6f7 "Politiezone Leuven"^^ . -_:B3f29778ff784c7de6c24d2c508bfa6f7 . -_:B3f29778ff784c7de6c24d2c508bfa6f7 . -_:B0f5098c18fc6ce7e31b389fdf69f1c82 "Gemeente Beveren"^^ . -_:B0f5098c18fc6ce7e31b389fdf69f1c82 . -_:B0f5098c18fc6ce7e31b389fdf69f1c82 . -_:B12ca310fX2D6c7eX2D4721X2Db672X2D83964b1650df . -_:B12ca310fX2D6c7eX2D4721X2Db672X2D83964b1650df . -_:B12ca310fX2D6c7eX2D4721X2Db672X2D83964b1650df . -_:B12ca310fX2D6c7eX2D4721X2Db672X2D83964b1650df "2022-09-29T07:43:07.480Z"^^ . -_:Baec52d8f79d4071c70618f47807d0de6 "Stad Turnhout"^^ . -_:Baec52d8f79d4071c70618f47807d0de6 . -_:Baec52d8f79d4071c70618f47807d0de6 . -_:B7b825a853d895934d03713edb9a1224f "Gemeente Hamme"^^ . -_:B7b825a853d895934d03713edb9a1224f . -_:B7b825a853d895934d03713edb9a1224f . -_:B94722e065d79885f7f72d8f29a87c085 "https://gipod.vlaanderen.be"@nl-BE . -_:B94722e065d79885f7f72d8f29a87c085 "10590418"^^ . -_:B94722e065d79885f7f72d8f29a87c085 . -_:Bb1ded4e9eee70602ca136aaee21f021f "https://gipod.vlaanderen.be"@nl-BE . -_:Bb1ded4e9eee70602ca136aaee21f021f "10590408"^^ . -_:Bb1ded4e9eee70602ca136aaee21f021f . -_:Be061b52d42196486c12a33ad40a2dc08 " POLYGON ((125551.999350704 171001.026644657, 125563.929266473 170990.289720466, 125562.736274896 170974.780829966, 125541.262426512 170981.938779428, 125551.999350704 171001.026644657))"^^ . -_:Be061b52d42196486c12a33ad40a2dc08 . -_:B98809bbe17e7bbcb37bca25b53db2cab "Stad Tielt"^^ . -_:B98809bbe17e7bbcb37bca25b53db2cab . -_:B98809bbe17e7bbcb37bca25b53db2cab . -_:B63d6622f2b43aa7181ba0bea6ba7c713 " POLYGON ((191027.8775073127 223613.56497392897, 191027.8730313409 223608.06794982962, 191025.36780654537 223608.06987539958, 191025.37228517752 223613.56689947285, 191025.37676375353 223619.06391773745, 191027.88198322846 223619.06199222244, 191027.8775073127 223613.56497392897))"^^ . -_:B63d6622f2b43aa7181ba0bea6ba7c713 . -_:B1d3fc62a8603e7d996cae306f0c10d01 " MULTIPOLYGON (((171528.0021595258 173514.87355595827, 171530.00963273703 173516.367872715, 171526.7134129993 173520.7724177977, 171524.70594054784 173519.27810355742, 171528.0021595258 173514.87355595827)), ((171537.07681124695 173514.0301360488, 171539.43788564694 173515.88559537008, 171536.33724306148 173519.81011610758, 171533.97616934526 173517.95465956908, 171537.07681124695 173514.0301360488)), ((171531.41874114936 173510.4627770558, 171533.42621337553 173511.95709510054, 171530.12999079633 173516.36163799185, 171528.1225193299 173514.8673224626, 171531.41874114936 173510.4627770558)), ((171534.83571730694 173505.9578523934, 171536.84318854765 173507.45217172615, 171533.54696312742 173511.8567124214, 171531.5394926465 173510.36239560414, 171534.83571730694 173505.9578523934)))"^^ . -_:B1d3fc62a8603e7d996cae306f0c10d01 . -_:B158a639da1b9d7235c1a54cebbf1b6df " MULTIPOLYGON (((127302.832919357 181495.830587254, 127304.832919357 181495.830587254, 127304.832919357 181501.830587254, 127302.832919357 181501.830587254, 127302.832919357 181500.247264751, 127302.832919357 181495.830587254)), ((127305.383373629 181490.532306867, 127306.383373629 181490.532306867, 127306.383373629 181498.032306867, 127305.383373629 181498.032306867, 127305.383373629 181495.51257943, 127305.383373629 181494.841521668, 127305.383373629 181490.532306867)), ((127309.195904208 181485.52629641, 127309.92340506 181486.212403187, 127306.149817782 181490.213657873, 127305.42231693 181489.527551095, 127309.195904208 181485.52629641)))"^^ . -_:B158a639da1b9d7235c1a54cebbf1b6df . -_:B912ebcb729714aed1f9d10b1da9a5d33 "Politiezone Brugge"^^ . -_:B912ebcb729714aed1f9d10b1da9a5d33 . -_:B912ebcb729714aed1f9d10b1da9a5d33 . -_:B42f7795bf143926e2e499dd8e81068c7 " POLYGON ((157864.213491076 219657.710040906, 157864.727969604 219656.323188198, 157868.370321102 219657.691400413, 157867.799921549 219659.096893387, 157864.213491076 219657.710040906))"^^ . -_:B42f7795bf143926e2e499dd8e81068c7 . - . - _:Be27c4de21f3486f879630c45129d96ad . - _:B51e1909d0818161791126c3e74667d6f . - . - _:Bfb6120e528186856cd92b3d1ea3cc5f3 . - _:Bc6a037e9a6db8a8450d073084368e015 . - "2021-01-06T16:35:17.237Z"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:12:55.007Z"^^ . - _:Bd355519e1d0a10e5abad297af8552e63 . - "2021-01-06T18:04:56.687Z"^^ . - "Verhuiswagen"^^ . - . - "10590454"^^ . -_:Bd792879a900fa0f16f83b2d4a0a157f2 "https://gipod.vlaanderen.be"@nl-BE . -_:Bd792879a900fa0f16f83b2d4a0a157f2 "10590382"^^ . -_:Bd792879a900fa0f16f83b2d4a0a157f2 . -_:B7e8bde071d030b1b4a4beb0d6434faee "Gemeente Hamme"^^ . -_:B7e8bde071d030b1b4a4beb0d6434faee . -_:B7e8bde071d030b1b4a4beb0d6434faee . - "2021-01-06T14:59:20.987Z"^^ . - "2021-01-06T18:04:37.45Z"^^ . - . - _:Bbe82dd83c7b37e7e1eb1a78c75376466 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:Bb0e140fb560c96d9ac0b48d1aecc675a . - "Wegeniswerken "^^ . - _:Bc91c190ef80262af53242ae7a152dd13 . - "2021-01-06T14:59:20.987Z"^^ . - "10590390"^^ . - _:B9711230236f8575d244a4374a075e956 . - _:B5ad0cdf27cfd4f9551c4e5962eaab833 . - . - . -_:B5abafb94c4b55d9436cdc2faeed82de8 " MULTIPOLYGON (((217408.3601595613 180821.9204968214, 217411.69678686402 180826.29508959316, 217409.7031205176 180827.80755238328, 217406.3664925439 180823.43296215497, 217408.3601595613 180821.9204968214)), ((217402.77978942276 180814.68460214138, 217406.00046431436 180819.14479392022, 217403.96778160695 180820.60468908586, 217400.74710591178 180816.1444998132, 217402.77978942276 180814.68460214138)))"^^ . -_:B5abafb94c4b55d9436cdc2faeed82de8 . - . - . - "9197226"^^ . - . - . - _:B6f9a25668b1b580a5b23f0a6ce7813b3 . - . -_:B432ad1c603c1a0f3e0211ccf0804d74e "Gemeente Beveren"^^ . -_:B432ad1c603c1a0f3e0211ccf0804d74e . -_:B432ad1c603c1a0f3e0211ccf0804d74e . -_:B9caf9acacb7c3acb0c9e1f8fbe6e118c "Politiezone Leuven"^^ . -_:B9caf9acacb7c3acb0c9e1f8fbe6e118c . -_:B9caf9acacb7c3acb0c9e1f8fbe6e118c . -_:B921b9fc836a6a386afd93ab85ea1dc1d " MULTIPOLYGON (((71423.3059177901 179976.797021095, 71423.3059177901 179980.674243719, 71417.9374556942 179981.270739508, 71417.0427120116 179977.393516883, 71423.3059177901 179976.797021095)), ((71421.2181825306 179960.393386913, 71422.1129262133 179962.481122172, 71416.147968329 179964.867105326, 71415.8497204347 179960.989882701, 71421.2181825306 179960.393386913)), ((71363.9545868411 179953.83193324, 71363.3580910527 179959.49864323, 71358.287876851 179959.49864323, 71358.287876851 179954.130181134, 71363.9545868411 179953.83193324)), ((71390.7968973206 179950.551206404, 71394.077624157 179950.551206404, 71395.2706157338 179955.621420605, 71391.393393109 179955.621420605, 71390.7968973206 179950.551206404)))"^^ . -_:B921b9fc836a6a386afd93ab85ea1dc1d . -_:Beb5066e252fe14bdea3fc1bc41dc5011 "Stad Turnhout"^^ . -_:Beb5066e252fe14bdea3fc1bc41dc5011 . -_:Beb5066e252fe14bdea3fc1bc41dc5011 . -_:Bb39d4ebdf8790ac12f48da09c105b601 "Gemeente Meise"^^ . -_:Bb39d4ebdf8790ac12f48da09c105b601 . -_:Bb39d4ebdf8790ac12f48da09c105b601 . -_:B553ba70919b0b534e3ad64ed3d1ca4f5 "Gemeente Beveren"^^ . -_:B553ba70919b0b534e3ad64ed3d1ca4f5 . -_:B553ba70919b0b534e3ad64ed3d1ca4f5 . -_:B6f9a25668b1b580a5b23f0a6ce7813b3 " POLYGON ((145609.193537362 182832.818856109, 145612.10145433 182831.402178612, 145611.654082489 182829.91093914, 145608.224231705 182831.103930717, 145609.193537362 182832.818856109))"^^ . -_:B6f9a25668b1b580a5b23f0a6ce7813b3 . -_:B882658eee13a34c675dba589a362700a "2021-01-27T05:00:00Z"^^ . -_:B882658eee13a34c675dba589a362700a "2021-01-27T21:00:00Z"^^ . -_:B882658eee13a34c675dba589a362700a . - "10590467"^^ . - . - "2021-01-06T14:04:04.177Z"^^ . - _:Bcd86c157f68a5a339d557ad72334d31f . - _:B03fcf811581adfc0a28f54759586289f . - "3980 Tessenderlo, Grondgebied Tessenderlo: Cat. 6 - Weinig hinder"^^ . - _:B140a80b0fabc672e6951d5427cb02cba . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B3cab4ebd0d8d33dea0f28adea685edc4 . - . - "2021-01-06T18:05:02.727Z"^^ . - . - _:Be76a140233050d4064e40f3d87fe6dc7 . - "2021-01-06T14:34:47.637Z"^^ . -_:Bd1ab2c286e86691ed753e647dd9b11f8 "2021-01-07T06:00:00Z"^^ . -_:Bd1ab2c286e86691ed753e647dd9b11f8 "2021-01-14T17:00:00Z"^^ . -_:Bd1ab2c286e86691ed753e647dd9b11f8 . -_:B7c26155ba3970a308e9251fec9088a26 "https://gipod.vlaanderen.be"@nl-BE . -_:B7c26155ba3970a308e9251fec9088a26 "10590343"^^ . -_:B7c26155ba3970a308e9251fec9088a26 . -_:B3cab4ebd0d8d33dea0f28adea685edc4 "https://gipod.vlaanderen.be"@nl-BE . -_:B3cab4ebd0d8d33dea0f28adea685edc4 "10590467"^^ . -_:B3cab4ebd0d8d33dea0f28adea685edc4 . - . - _:Baa7ec2b64eb8f550188010191dd58cd1 . - . - . - _:B928a41e281fc8b018c5efd475c90abbe . - . - . - _:Bd82438e74e68143ab48f0511ba0b8852 . - . -_:Be683844eb1c966774dd5b06eef703107 "Gemeente Bornem"^^ . -_:Be683844eb1c966774dd5b06eef703107 . -_:Be683844eb1c966774dd5b06eef703107 . -_:Bcc5ba14c9580b5a0959be48792bd908f "Stad Hasselt"^^ . -_:Bcc5ba14c9580b5a0959be48792bd908f . -_:Bcc5ba14c9580b5a0959be48792bd908f . - . - _:Bc1d583beecfbfde59626d70dab957fc5 . - . -_:B54601af375152e3e62fe87126907b81b "Politiezone Brugge"^^ . -_:B54601af375152e3e62fe87126907b81b . -_:B54601af375152e3e62fe87126907b81b . -_:B05771377074bb3ba81d154182dfb6ee8 "Stad Lokeren"^^ . -_:B05771377074bb3ba81d154182dfb6ee8 . -_:B05771377074bb3ba81d154182dfb6ee8 . -_:B4316d24aa51b3f37f671c0f394c9a126 " MULTIPOLYGON (((173314.44313881168 174620.30062304344, 173316.9189078221 174620.6809627572, 173316.08004583928 174626.11305889394, 173313.60427934502 174625.73271995876, 173314.44313881168 174620.30062304344)), ((173311.73003775682 174619.0875444105, 173314.2149398364 174619.4031180553, 173313.5189457481 174624.8552566236, 173311.03404622234 174624.53968362696, 173311.73003775682 174619.0875444105)))"^^ . -_:B4316d24aa51b3f37f671c0f394c9a126 . -_:B4895b09e9d7f2738250d0a6adcb95693 "2021-01-15T23:00:00Z"^^ . -_:B4895b09e9d7f2738250d0a6adcb95693 "2021-01-17T22:30:00Z"^^ . -_:B4895b09e9d7f2738250d0a6adcb95693 . - . - . - "9197146"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:05:08.08Z"^^ . - . - _:Bc1dc021dc3655c1011ecc901aa27c78b . - _:B5c1cfface6721055632727e33dc62f18 . - . - _:Bc8049be4948328970f111ce187111d3f . - "8211 Zedelgem, Dorpwegel 7: Andere / Verlenging"^^ . - _:B5cd443fcf222b3e5a025f8c30d395958 . - . - "2021-01-06T13:49:19.427Z"^^ . - "2021-01-06T13:48:11.14Z"^^ . - _:B49ed45c5e9dd746503df8219b6274672 . - . - "10590487"^^ . -_:B19da948e16c0b0070aec46aaf0de492a "Stad Kortrijk"^^ . -_:B19da948e16c0b0070aec46aaf0de492a . -_:B19da948e16c0b0070aec46aaf0de492a . -_:B49136a5a48f17a05bbde08c76e0a04bc "2021-01-26T23:00:00Z"^^ . -_:B49136a5a48f17a05bbde08c76e0a04bc "2021-01-27T22:30:00Z"^^ . -_:B49136a5a48f17a05bbde08c76e0a04bc . -_:B680316401a5de79f8192e92573a8a2a8 "Politiezone Leuven"^^ . -_:B680316401a5de79f8192e92573a8a2a8 . -_:B680316401a5de79f8192e92573a8a2a8 . -_:Bfb6120e528186856cd92b3d1ea3cc5f3 "Stad Hasselt"^^ . -_:Bfb6120e528186856cd92b3d1ea3cc5f3 . -_:Bfb6120e528186856cd92b3d1ea3cc5f3 . -_:Bc18884e2413f8e292f0d31c9b68381a2 "Stad Mechelen"^^ . -_:Bc18884e2413f8e292f0d31c9b68381a2 . -_:Bc18884e2413f8e292f0d31c9b68381a2 . -_:B630785e0041e925bbdef55777ba4ffa0 " POLYGON ((133536.89214655093 198142.4052475067, 133538.98542641528 198143.7776222136, 133542.0127572853 198139.18456584495, 133539.98177446786 198137.85303197615, 133540.0133189403 198137.80694566946, 133542.00324974195 198139.08690256532, 133544.99028041356 198134.46767547913, 133542.88507176575 198133.11356826872, 133542.27809676493 198134.05221126787, 133540.17182720057 198132.61819596123, 133540.84996831638 198131.6274357289, 133538.78102153254 198130.21883177198, 133535.67378169112 198134.75849885494, 133537.57445008607 198136.05253187474, 133533.2241194349 198142.40835758112, 133535.70685391387 198144.09867745265, 133537.57327658564 198141.37183750514, 133536.89214655093 198142.4052475067))"^^ . -_:B630785e0041e925bbdef55777ba4ffa0 . - . - _:Bcf8a743100ba6da35e3a732f75f53f85 . - . -_:Bdb93f09f475997306ffe4e509792953e "Politiezone Brugge"^^ . -_:Bdb93f09f475997306ffe4e509792953e . -_:Bdb93f09f475997306ffe4e509792953e . -_:Bd1da7ee37c9f2312d2632c3039f6cb85 "2021-01-25T06:00:00Z"^^ . -_:Bd1da7ee37c9f2312d2632c3039f6cb85 "2021-01-29T15:00:00Z"^^ . -_:Bd1da7ee37c9f2312d2632c3039f6cb85 . - . - _:Bb78c619c91dd4508a71b03326eefd0c0 . - _:B11f026cb629a637854612b7589793e0f . - "2021-01-06T18:05:19.637Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - "2021-01-06T13:27:13.107Z"^^ . - _:B1c71eac8ecbc3ca28e99442f93fffed3 . - _:B38fb4e8605ecce97331864416378a99e . - "2021-01-06T13:26:52.043Z"^^ . - _:B7035fb41f08094e3157166f72bb7d032 . - . - "9600 Ronse - Hoogstraat 21 - kraan"^^ . - "10590508"^^ . - "2021-01-06T13:23:31.293Z"^^ . - _:Bdb72d87646d206dbf48de3c911a2343d . - "2021-01-06T18:05:25.163Z"^^ . - _:Ba95736f2a9d7a28a279bfc9350edf44c . - . - _:Baee2868ba5fa433271fade2e3c0c1324 . - "10590524"^^ . - . - . - "9900 Eeklo, Stationsstraat 99: Container enkel op parkeerplaats"^^ . - . - _:B2e413b2e3c7375032680f9f4bbe118f7 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T13:20:50.923Z"^^ . - _:B94934b6cb6874d475a3d48582bde4d5b . - "2021-01-06T13:34:10.337Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T13:34:10.337Z"^^ . - _:B542295ae8b3acf587c59a171b2d13932 . - "2021-01-06T18:05:16.787Z"^^ . - _:B7aa5d977c7133a2f934d19d25cb345f4 . - _:Be136a6a7dae50c7a12eb63ff3ac524b5 . - . - . - . - _:B8fbba5a8ccd752ce1c9c7cc4bf22ac33 . - . - "Jaarlijkse loopwedstrijd met 3 omlopen."^^ . - _:B243bf07a6efe3e9fc5f440c071527975 . - "10590501"^^ . -_:B9806f746bd99d8384391f355586c1314 "Stad Lokeren"^^ . -_:B9806f746bd99d8384391f355586c1314 . -_:B9806f746bd99d8384391f355586c1314 . -_:B3255d16cc35f70132d8cb90dea964b9c "Gemeente Beveren"^^ . -_:B3255d16cc35f70132d8cb90dea964b9c . -_:B3255d16cc35f70132d8cb90dea964b9c . -_:B8fa944b644f797af268e14ea83064e0c "Stad Waregem"^^ . -_:B8fa944b644f797af268e14ea83064e0c . -_:B8fa944b644f797af268e14ea83064e0c . -_:Bb60b70834d2311f1f33e14f4ecf5c9d7 "Gemeente Zedelgem"^^ . -_:Bb60b70834d2311f1f33e14f4ecf5c9d7 . -_:Bb60b70834d2311f1f33e14f4ecf5c9d7 . -_:Bfb03ece294fa9000c0411fd82d779737 "Politiezone Leuven"^^ . -_:Bfb03ece294fa9000c0411fd82d779737 . -_:Bfb03ece294fa9000c0411fd82d779737 . - . - _:B0008ed5f728bb5452d9b7be214d97aed . - . - . - _:Bbeca0dae26a4816e2b26179c5647c4f3 . - . -_:B98b35b4f952250f8ee90a9249a188cd2 "2021-01-08T23:00:00Z"^^ . -_:B98b35b4f952250f8ee90a9249a188cd2 "2021-01-22T22:30:00Z"^^ . -_:B98b35b4f952250f8ee90a9249a188cd2 . - . - _:B6083a6814d1ea9811439254eead4d696 . - . -_:B715ef0ae88d3af0daefc86ae70936d9a " POLYGON ((159744.181811281 221290.61726174, 159742.233879722 221289.284466463, 159744.554621149 221285.919857406, 159746.344108514 221287.485658851, 159744.181811281 221290.61726174))"^^ . -_:B715ef0ae88d3af0daefc86ae70936d9a . -_:Bd3c96c1926075c20c9098eddc372854f " POLYGON ((164495.06898784518 202400.2534018159, 164489.90143470347 202402.1639060704, 164490.77218589847 202404.5065880809, 164495.93973703598 202402.59608554933, 164501.10729198423 202400.68558745552, 164500.2365447977 202398.3429019926, 164495.06898784518 202400.2534018159))"^^ . -_:Bd3c96c1926075c20c9098eddc372854f . -_:B2f0c66eb76b307f0a89fae86b7101617 " POLYGON ((121375.213186373 204233.932491256, 121375.490501848 204232.971712339, 121384.1375121 204235.467551618, 121383.860196625 204236.428330535, 121375.213186373 204233.932491256))"^^ . -_:B2f0c66eb76b307f0a89fae86b7101617 . -_:B3ee148ba5e6217c46f122ac88b04acec "Politiezone Leuven"^^ . -_:B3ee148ba5e6217c46f122ac88b04acec . -_:B3ee148ba5e6217c46f122ac88b04acec . - _:B602e07c828ea80361f7393412b16af96 . - "2930 Brasschaat, Donksesteenweg 59: Huisaansluitingen/herstel kolken"^^ . - "10590588"^^ . - _:Bb01aaba24cf044a697091c08b4a982b3 . - _:Bcb0787f28ce58c830826a7b88a525bce . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B51207760bc8c1ab4ff4bd95d867e5bef . - "2021-01-06T12:55:37.867Z"^^ . - . - . - "2021-01-06T12:45:43.72Z"^^ . - . - _:Be1a330d7240da6a6bdef6a49eda146a4 . - "2021-01-06T18:05:42.393Z"^^ . - . - "10590421"^^ . - . - _:Bb39d60a483a56971a305870639928784 . - "8430 Middelkerke, Leopoldlaan 140B: Verhuis"^^ . - "2021-01-06T18:04:46.81Z"^^ . - . - _:Bc96207a3959f74c41bbca13979584dc7 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Be8b9ba04f025f5ee5e251db847913e8f . - "2021-01-06T14:39:04.097Z"^^ . - . - _:B659b8bf6f40854874ab134ba915f61fb . - _:B0e69fc45882de35840c4393147f63ab0 . - "2021-01-06T14:39:23.103Z"^^ . - . -_:B1d62eafd52a7793019a580d3051c6701 "Stad Aalst"^^ . -_:B1d62eafd52a7793019a580d3051c6701 . -_:B1d62eafd52a7793019a580d3051c6701 . -_:Beac0e11ff396fea86e1bd52eecb6709f "Stad Aalst"^^ . -_:Beac0e11ff396fea86e1bd52eecb6709f . -_:Beac0e11ff396fea86e1bd52eecb6709f . -_:B21f8fd37585dd79d4622563de24c74f0 "Politiezone Leuven"^^ . -_:B21f8fd37585dd79d4622563de24c74f0 . -_:B21f8fd37585dd79d4622563de24c74f0 . - . - . - "9197162"^^ . -_:Bff8544336f6c9d1dbe97b56c8e25b4a5 "2021-01-23T06:00:00Z"^^ . -_:Bff8544336f6c9d1dbe97b56c8e25b4a5 "2021-01-23T17:00:00Z"^^ . -_:Bff8544336f6c9d1dbe97b56c8e25b4a5 . -_:B049135c7c92210bac6e13db8f0a7e6bd "Stad Hasselt"^^ . -_:B049135c7c92210bac6e13db8f0a7e6bd . -_:B049135c7c92210bac6e13db8f0a7e6bd . - _:Bd42539aa93615e17339515791ffa41a6 . - . - _:B88e4564ffe820294460761093a1f5a46 . - . - "2021-01-06T13:13:43.9Z"^^ . - _:B53de1467045aa611a97540f9e496ce05 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:32:46.257Z"^^ . - "10590535"^^ . - . - "2021-01-06T18:05:28.32Z"^^ . - _:Bf22c531d78edb483d385379ca85b8490 . - "Vrachtwagen/werfwagen Kleine vrachtwagen voor verhuis"^^ . - _:Bc2930f3c909be5a7a0ce3f142621e2da . - . - _:Bff35057c02222d06f2d3153eb7a47c0b . - . -_:B2329a7fb326b012014a9918b901f4d5f "https://gipod.vlaanderen.be"@nl-BE . -_:B2329a7fb326b012014a9918b901f4d5f "10590395"^^ . -_:B2329a7fb326b012014a9918b901f4d5f . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:43.353Z"^^ . - "2021-01-06T14:47:14.857Z"^^ . - _:B373d6d425e61d247097526fdedfe5bc4 . - _:Baec52d8f79d4071c70618f47807d0de6 . - "2021-01-06T14:47:14.857Z"^^ . - _:Bef514783f93c7d47b956b4d42119ec96 . - . - _:Bcbf97350e14fddf633678992c9e8c01b . - "Wegeniswerken Plaatsen van signalisatie voor nutswerken.\n\nDeze aanvraag betreft pagina 2 van 4 pagina's !"^^ . - "10590409"^^ . - . - _:B3587a82cb3cd257da5e626691f0193c8 . -_:Bd44374711b33f21b96a7596116f19e00 "Stad Dendermonde"^^ . -_:Bd44374711b33f21b96a7596116f19e00 . -_:Bd44374711b33f21b96a7596116f19e00 . - . - . - "9197167"^^ . - _:Bf1e9ef27044da4e27548e862f8c5e2fc . - "2021-01-06T18:05:25.52Z"^^ . - "2021-01-06T13:19:45.87Z"^^ . - _:B662e0f78865efc22cb5eee0a86434dec . - _:B6c5dbf5e491ce25fe09907d13b87ce50 . - "2021-01-06T13:20:23.61Z"^^ . - . - . - "9600 Ronse - Ninovestraat 249 - parkeerverbod"^^ . - . - . - "10590525"^^ . - _:B570b365c2b175789276ce7715ee4152e . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B1b1f21395f26d312d80ce9dfab5e28a6 . - _:B680316401a5de79f8192e92573a8a2a8 . - . - "2021-01-06T13:14:07.553Z"^^ . - "Voertuig Werken in opdracht van Proximus: aanleggen van ondergrondse leidingen.\nParkeerplaatsen om de voertuigen en doorgang te kunnen garanderen voor omstaanders en voertuigen."^^ . - "2021-01-06T18:05:29.92Z"^^ . - . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B63927cf530abd8cf7baa444faa10899c . - _:Bf472d9bfe6c24bcfa732d28be18e2225 . - _:B1e2cdac0b2a4abadd46af68544ac7a17 . - _:B491da6c1584d4f3a873ec326ed8e1827 . - "10590541"^^ . - "2021-01-06T13:09:46.09Z"^^ . -_:Bcc4d4a3eaa26248c013f1feb70cea61e "https://gipod.vlaanderen.be"@nl-BE . -_:Bcc4d4a3eaa26248c013f1feb70cea61e "10590532"^^ . -_:Bcc4d4a3eaa26248c013f1feb70cea61e . -_:Bfddb67940b887bf8a545b36d7fcb1694 "Stad Tongeren"^^ . -_:Bfddb67940b887bf8a545b36d7fcb1694 . -_:Bfddb67940b887bf8a545b36d7fcb1694 . -_:B49c1dc268446ec1952d55d136a72b37b "Gemeente Beveren"^^ . -_:B49c1dc268446ec1952d55d136a72b37b . -_:B49c1dc268446ec1952d55d136a72b37b . -_:B4d8e8a079f1831cf4bae349bf914ce67 "Politiezone Leuven"^^ . -_:B4d8e8a079f1831cf4bae349bf914ce67 . -_:B4d8e8a079f1831cf4bae349bf914ce67 . -_:B183efe1939299fa8e55e27be381b8e50 " POLYGON ((73199.2282164012 162122.1743938811, 73451.15188194429 161956.17149926443, 73539.92009264902 161710.25788302626, 73611.56261202159 161483.4601950869, 73611.2194415076 161407.96032686252, 73725.76358039584 161163.1593894353, 73812.88022788789 161062.21991093736, 73917.96893615203 161051.6324281199, 73974.95208617524 161013.0503994869, 74033.58133654378 160983.50624391995, 74080.84798018869 160901.26867105067, 74140.76366726644 160855.84878417477, 74155.49216474127 160774.83604578022, 73987.28194279136 160714.5950484611, 73988.63180409587 160703.24818634614, 73977.21064189037 160698.88286971115, 73979.79922674655 160720.74475871678, 74139.6493441159 160778.8409830192, 74135.35534660319 160848.37573119625, 74074.6826151166 160893.80670740176, 74027.39411642477 160974.53454117104, 73915.5555502371 161041.85109529458, 73809.76453041745 161056.22436767444, 73713.64115305094 161162.58069998398, 73602.89321477749 161408.0816705348, 73600.27484549473 161488.15496196784, 73485.65156366459 161830.3402157817, 73444.98682876029 161948.7117755087, 73196.8471300298 162114.65974535514, 73199.2282164012 162122.1743938811))"^^ . -_:B183efe1939299fa8e55e27be381b8e50 . -_:B412f6d53ac90e44a211dd5f0103f317b "Politiezone Leuven"^^ . -_:B412f6d53ac90e44a211dd5f0103f317b . -_:B412f6d53ac90e44a211dd5f0103f317b . -_:B9c22509ea25e80228e802f7b72681d20 "https://gipod.vlaanderen.be"@nl-BE . -_:B9c22509ea25e80228e802f7b72681d20 "10590336"^^ . -_:B9c22509ea25e80228e802f7b72681d20 . -_:Be95c81506ffbb01b5ed528af8ba00887 " POLYGON ((121365.897582206 204223.154807761, 121366.41921764 204221.224031628, 121378.003874436 204224.353844229, 121377.482239003 204226.284620361, 121365.897582206 204223.154807761))"^^ . -_:Be95c81506ffbb01b5ed528af8ba00887 . -_:Bf472d9bfe6c24bcfa732d28be18e2225 "Politiezone Leuven"^^ . -_:Bf472d9bfe6c24bcfa732d28be18e2225 . -_:Bf472d9bfe6c24bcfa732d28be18e2225 . - . - _:B954b1356ca3be49980358b266be7185b . - . - . - _:Bf42bc4ea28e38acc088cc65fedcc9001 . - . -_:B35895785f93ef41711750264d57ce890 "Gemeente Ranst"^^ . -_:B35895785f93ef41711750264d57ce890 . -_:B35895785f93ef41711750264d57ce890 . - _:B25dbeb7324f866fbe9db5009cc452556 . - "10590578"^^ . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - "2021-01-06T12:51:31.803Z"^^ . - _:B9e6d0f18186056f19fad6d06e04c70e2 . - _:B53dfba31b6a890c1cc16ce5b28b0c92e . - . - _:B3063d33d42d5efc671446108ea112f6a . - "2021-01-06T18:05:39.943Z"^^ . - _:Bb76536cae2c41f21473e9dfff7529a21 . - "2021-01-06T12:51:31.803Z"^^ . - "9600 Ronse - Franklin Rooseveltplein 34 - parkeerverbod"^^ . - . - _:B32172f5de00abe13b33b52aed59506ea . - . -_:B461855ec4d7f09b839a94408be4a4180 "2021-01-25T05:00:00Z"^^ . -_:B461855ec4d7f09b839a94408be4a4180 "2021-01-27T16:00:00Z"^^ . -_:B461855ec4d7f09b839a94408be4a4180 . - "10590437"^^ . - . - "2021-01-06T15:29:10.54Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "Vrachtwagen/werfwagen plaatsen van vrachtwagen of camionette of hoogtewerker / werfkeet"^^ . - "2021-01-06T18:04:51.087Z"^^ . - . - . - _:Bb946b430f5b074e786fb21c812fb69c5 . - . - "2021-01-06T14:30:13.667Z"^^ . - _:Bce5b425eac609233920d77c1d61152ec . - _:Bff4aa0386076a33940ed0e19fc284405 . - _:Bd26ae5037e00afe7b14cc1119bc3a482 . - _:B986e931f3e6efded7c740b08f1b24cc2 . -_:B60b0ee02f25a5b2940cb07050434b964 "https://gipod.vlaanderen.be"@nl-BE . -_:B60b0ee02f25a5b2940cb07050434b964 "10590401"^^ . -_:B60b0ee02f25a5b2940cb07050434b964 . - . - . - "9197015"^^ . -_:B856004f48d67d5c45e69202c88f5dc60 "Politiezone Leuven"^^ . -_:B856004f48d67d5c45e69202c88f5dc60 . -_:B856004f48d67d5c45e69202c88f5dc60 . -_:B767244b5d4c1537596d769a39a81e810 "Politiezone Leuven"^^ . -_:B767244b5d4c1537596d769a39a81e810 . -_:B767244b5d4c1537596d769a39a81e810 . - . - _:Bd003eaf6d1520c22372f357e4e2b6d52 . - . -_:B004ffa730c22d1ffff9352b0c35d95ed "Politiezone Brugge"^^ . -_:B004ffa730c22d1ffff9352b0c35d95ed . -_:B004ffa730c22d1ffff9352b0c35d95ed . - _:B25b670b707244697bb633a7092843b46 . - "2021-01-06T18:04:31.507Z"^^ . - _:Bf94f4cbc04d3160ee698b8eeee6a42a3 . - "2021-01-06T15:15:02.487Z"^^ . - "2021-01-06T15:16:40.677Z"^^ . - . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:Bf9cf6564d762a860cd71e47118c406db . - "9400 Ninove, Van der Schuerenstraat 60: Nutswerken"^^ . - _:B40a82eb79311df8355d4a82ee16ce25c . - "10590374"^^ . - _:Bc7e3e692e991734d7c6f576d169efc1b . - . - _:B36bfc5b4d9d4a0a16a81b6b2c7f852a7 . - . -_:B935ca386770ee81a1b877e9b9e1cfb86 "Politiezone Leuven"^^ . -_:B935ca386770ee81a1b877e9b9e1cfb86 . -_:B935ca386770ee81a1b877e9b9e1cfb86 . - . - . - "9196992"^^ . -_:B0e8cae372528e2c29871ce7c636e4514 "Politiezone Leuven"^^ . -_:B0e8cae372528e2c29871ce7c636e4514 . -_:B0e8cae372528e2c29871ce7c636e4514 . - . - . - "9196938"^^ . -_:Bf6bb695d6221acc6250aea322a721f65 " POLYGON ((73424.459139781 169335.03058234882, 73419.38022623501 169337.16398182977, 73420.35237867649 169339.46631340962, 73425.43129035611 169337.3329157764, 73430.51020611869 169335.19952227268, 73429.53805740982 169332.8971869927, 73424.459139781 169335.03058234882))"^^ . -_:Bf6bb695d6221acc6250aea322a721f65 . -_:B079946227c9438a37a5295f02c985530 "https://gipod.vlaanderen.be"@nl-BE . -_:B079946227c9438a37a5295f02c985530 "10590358"^^ . -_:B079946227c9438a37a5295f02c985530 . - . - "2021-01-06T13:21:13.3Z"^^ . - "Vrachtwagen/werfwagen 49/51/53"^^ . - "2021-01-06T13:03:39.017Z"^^ . - "2021-01-06T18:05:33.29Z"^^ . - _:B32f7c8b789520dfb0222de53bdf3630e . - _:Bc07e00f3580b097f29436861469b6bad . - "10590552"^^ . - _:B621b8f532ecf61433b83c9163099742c . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B554d0e38d7b7e0ee0b2a88c7ec1a68fe . - _:B25e024da598c0cc368a5cd7101324920 . - . -_:Be290dead4fe3a05c6272637dadeb5498 "Stad Turnhout"^^ . -_:Be290dead4fe3a05c6272637dadeb5498 . -_:Be290dead4fe3a05c6272637dadeb5498 . -_:B300a7648b6857257faf71224236e1d77 "Stad Turnhout"^^ . -_:B300a7648b6857257faf71224236e1d77 . -_:B300a7648b6857257faf71224236e1d77 . - . - . - "9197170"^^ . -_:B95a6b931f69326cbcaff2c0002697de9 "Gemeente Tervuren"^^ . -_:B95a6b931f69326cbcaff2c0002697de9 . -_:B95a6b931f69326cbcaff2c0002697de9 . -_:Bfa2bb3fa7998c572d70e577cc2b8a4a1 "https://gipod.vlaanderen.be"@nl-BE . -_:Bfa2bb3fa7998c572d70e577cc2b8a4a1 "10590356"^^ . -_:Bfa2bb3fa7998c572d70e577cc2b8a4a1 . -_:B8ed3c39143bfaaf2c5495d962535bd81 "Stad Izegem"^^ . -_:B8ed3c39143bfaaf2c5495d962535bd81 . -_:B8ed3c39143bfaaf2c5495d962535bd81 . -_:Bb908ce178ecde0c7f95d025ff1f591ac "Politiezone Brugge"^^ . -_:Bb908ce178ecde0c7f95d025ff1f591ac . -_:Bb908ce178ecde0c7f95d025ff1f591ac . - . - . - "9197183"^^ . - . - _:B921b9fc836a6a386afd93ab85ea1dc1d . - . -_:Bd08cf8345059db10e694953707018dff "https://gipod.vlaanderen.be"@nl-BE . -_:Bd08cf8345059db10e694953707018dff "10590464"^^ . -_:Bd08cf8345059db10e694953707018dff . -_:Bca57f89b9749ddef02740c70ec9b725b "Stad Dendermonde"^^ . -_:Bca57f89b9749ddef02740c70ec9b725b . -_:Bca57f89b9749ddef02740c70ec9b725b . -_:B69b6248920f6e5d18c94c86d620c7007 "Gemeente Koksijde"^^ . -_:B69b6248920f6e5d18c94c86d620c7007 . -_:B69b6248920f6e5d18c94c86d620c7007 . - . - . - _:Bdfbd4fbcd994b458a7a7201e84d89aea . - . -_:B25b670b707244697bb633a7092843b46 "Stad Ninove"^^ . -_:B25b670b707244697bb633a7092843b46 . -_:B25b670b707244697bb633a7092843b46 . -_:B00b97a7cdf667cf216efb0ad7a497599 "https://gipod.vlaanderen.be"@nl-BE . -_:B00b97a7cdf667cf216efb0ad7a497599 "10590460"^^ . -_:B00b97a7cdf667cf216efb0ad7a497599 . -_:Ba47dc84160bcd5bee505b255a83438c3 "Stad Dendermonde"^^ . -_:Ba47dc84160bcd5bee505b255a83438c3 . -_:Ba47dc84160bcd5bee505b255a83438c3 . -_:Be74e41b5751eb2f7b7c46cbba93b0351 "Stad Aalst"^^ . -_:Be74e41b5751eb2f7b7c46cbba93b0351 . -_:Be74e41b5751eb2f7b7c46cbba93b0351 . -_:Bd9618a16b393e48f0be7ba0fc74ce62e "Gemeente Kapellen"^^ . -_:Bd9618a16b393e48f0be7ba0fc74ce62e . -_:Bd9618a16b393e48f0be7ba0fc74ce62e . -_:B02cd47933012cf30d82b5e00e54599d7 "Politiezone Brugge"^^ . -_:B02cd47933012cf30d82b5e00e54599d7 . -_:B02cd47933012cf30d82b5e00e54599d7 . -_:B6083a6814d1ea9811439254eead4d696 " POLYGON ((172882.6172546916 174636.26013488788, 172877.3542058738 174637.88978501596, 172878.09700008878 174640.27569561824, 172883.36004674144 174638.64604698215, 172888.62309669796 174637.01640313212, 172887.880306813 174634.63048953284, 172882.6172546916 174636.26013488788))"^^ . -_:B6083a6814d1ea9811439254eead4d696 . -_:B5dc832538b43fe489f1679381d017614 "Stad Kortrijk"^^ . -_:B5dc832538b43fe489f1679381d017614 . -_:B5dc832538b43fe489f1679381d017614 . - . - . - "10590558"^^ . - . - "2021-01-06T13:00:05.96Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bb6c0a53495559dd7ef2b60c2bbe0eebb . - . - _:B519b9f0052ff7c515a6c316251947623 . - "2021-01-06T18:05:35.2Z"^^ . - "2021-01-06T14:32:52.097Z"^^ . - _:Bbbdfa8aa8df793047dd4fb79e6a73a63 . - _:B22d23b7f12d46e394eae2661389ab6ee . - _:B28abfda81fb56f2c37bf137c2e2fd4af . - "Verhuiswagen eerste drie plaatsen thv 79 ( drie plaatsen )"^^ . -_:B07470dd5bd6f124ed74be612c385a0c6 "Gemeente Zedelgem"^^ . -_:B07470dd5bd6f124ed74be612c385a0c6 . -_:B07470dd5bd6f124ed74be612c385a0c6 . -_:B36bfc5b4d9d4a0a16a81b6b2c7f852a7 " POLYGON ((121637.283703504 171157.084855306, 121636.426240808 171156.00370669, 121638.1411662 171154.288781298, 121639.259595803 171155.258086954, 121637.283703504 171157.084855306))"^^ . -_:B36bfc5b4d9d4a0a16a81b6b2c7f852a7 . -_:Bff35057c02222d06f2d3153eb7a47c0b " POLYGON ((123358.497931704 200606.305616136, 123386.53323376 200622.411002424, 123406.814090567 200589.007238272, 123469.446148353 200558.585953062, 123466.46366941 200537.708600466, 123427.094947374 200530.550651005, 123379.971780088 200599.744162463, 123358.497931704 200606.305616136))"^^ . -_:Bff35057c02222d06f2d3153eb7a47c0b . - _:B4951b41db983a5f2c428808ada86d0da . - . - _:Bbe0c84ea49e82f7c6e3ba743c0b6a94d . - "2021-01-06T14:26:27.777Z"^^ . - . - "2021-01-06T14:26:27.777Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - _:B319b035f61155439460c9b744d8ed1c7 . - "2021-01-06T18:04:51.86Z"^^ . - "2150 Borsbeek, Herentalsebaan 63: Stelling"^^ . - _:B24916225ce8ba57d38ba10fac44844c0 . - "10590440"^^ . - _:B303014beaec855cbb8505e361aaaacce . -_:Bc8d6e752a870ff96c6a39a08d245b4c4 "Gemeente Rumst"^^ . -_:Bc8d6e752a870ff96c6a39a08d245b4c4 . -_:Bc8d6e752a870ff96c6a39a08d245b4c4 . -_:B09c1e67c591f98911e3ddf7edf01ccd4 "Politiezone Brugge"^^ . -_:B09c1e67c591f98911e3ddf7edf01ccd4 . -_:B09c1e67c591f98911e3ddf7edf01ccd4 . - . - _:B44c24c77b503a37ce686089fc777ff24 . - . -_:Bd355519e1d0a10e5abad297af8552e63 "https://gipod.vlaanderen.be"@nl-BE . -_:Bd355519e1d0a10e5abad297af8552e63 "10590454"^^ . -_:Bd355519e1d0a10e5abad297af8552e63 . -_:B420af317b4876b51efaff104e2bcb547 "https://gipod.vlaanderen.be"@nl-BE . -_:B420af317b4876b51efaff104e2bcb547 "10590489"^^ . -_:B420af317b4876b51efaff104e2bcb547 . - . - . - "9196920"^^ . - . - _:B91bab7ca269f434f9e25d87b5cf4bb7a . - . - . - . - "9197090"^^ . -_:Be44364fa7a9adb79b1f41b5b498b6e00 " POLYGON ((174781.43063241738 174885.35569961555, 174775.9770479803 174884.56485890318, 174775.6166752273 174887.0371200107, 174781.0702571351 174887.8279599864, 174786.52383741853 174888.61880554445, 174786.8842152303 174886.1465459047, 174781.43063241738 174885.35569961555))"^^ . -_:Be44364fa7a9adb79b1f41b5b498b6e00 . - "Verhuiswagen Moving furnitures to an apartment with a moving company."^^ . - "10590373"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:31.04Z"^^ . - "2021-01-06T15:17:15.467Z"^^ . - _:B412f6d53ac90e44a211dd5f0103f317b . - _:B08673ce26078022606c67e5827d150e5 . - . - . - "2021-01-06T15:17:15.467Z"^^ . - _:B748bd33cb97bd5bf416bab7eb2f7abd6 . - . - _:B49b7f1d8c80a05c6e4b0fce117feede4 . - _:B9b28b8b62803bb7a2c1b3ee468fc5f67 . - . -_:B6155538a0d00bdcec5dcd6162c42a95f "2021-01-21T00:00:00Z"^^ . -_:B6155538a0d00bdcec5dcd6162c42a95f "2021-01-22T00:00:00Z"^^ . -_:B6155538a0d00bdcec5dcd6162c42a95f . -_:B34f6d2384772f14827f6a4d4f83a9d01 "2021-01-13T06:00:00Z"^^ . -_:B34f6d2384772f14827f6a4d4f83a9d01 "2021-02-12T18:00:00Z"^^ . -_:B34f6d2384772f14827f6a4d4f83a9d01 . - . - . - "9197330"^^ . -_:Bb7de050393a63c7d8f269d2248e066ab "Stad Hasselt"^^ . -_:Bb7de050393a63c7d8f269d2248e066ab . -_:Bb7de050393a63c7d8f269d2248e066ab . -_:Bc866e111ddf3ae37a30fbf408683d5a5 "Stad Hasselt"^^ . -_:Bc866e111ddf3ae37a30fbf408683d5a5 . -_:Bc866e111ddf3ae37a30fbf408683d5a5 . -_:B255256009a1a29660f1a6941c46701d8 "2021-01-07T06:30:00Z"^^ . -_:B255256009a1a29660f1a6941c46701d8 "2021-01-07T16:00:00Z"^^ . -_:B255256009a1a29660f1a6941c46701d8 . -_:B373d6d425e61d247097526fdedfe5bc4 "Stad Turnhout"^^ . -_:B373d6d425e61d247097526fdedfe5bc4 . -_:B373d6d425e61d247097526fdedfe5bc4 . -_:B5ee22c6a64b51f6d71eba15c322df445 "https://gipod.vlaanderen.be"@nl-BE . -_:B5ee22c6a64b51f6d71eba15c322df445 "10590348"^^ . -_:B5ee22c6a64b51f6d71eba15c322df445 . -_:B0bdbddc985144e2f1094b3ef725d6f41 "Stad Ronse"^^ . -_:B0bdbddc985144e2f1094b3ef725d6f41 . -_:B0bdbddc985144e2f1094b3ef725d6f41 . -_:B1f799de34684d804ce4f1c183d309ba3 "Stad Kortrijk"^^ . -_:B1f799de34684d804ce4f1c183d309ba3 . -_:B1f799de34684d804ce4f1c183d309ba3 . - . - . - "9197322"^^ . -_:B9144611b8cbf661261d5e44435006937 "https://gipod.vlaanderen.be"@nl-BE . -_:B9144611b8cbf661261d5e44435006937 "10590439"^^ . -_:B9144611b8cbf661261d5e44435006937 . -_:B07b01fc2567337d912a97a3571b68193 "Gemeente Tervuren"^^ . -_:B07b01fc2567337d912a97a3571b68193 . -_:B07b01fc2567337d912a97a3571b68193 . -_:B21f174142b436abc2c98ead817cdc538 " POLYGON ((70409.5716473723 212316.47420313, 70411.5716473723 212316.47420313, 70411.5716473723 212346.47420313, 70409.5716473723 212346.47420313, 70409.5716473723 212316.47420313))"^^ . -_:B21f174142b436abc2c98ead817cdc538 . -_:Bb038c2f0789f8e7807c90707694654a7 "2021-01-06T05:00:00Z"^^ . -_:Bb038c2f0789f8e7807c90707694654a7 "2021-01-06T21:00:00Z"^^ . -_:Bb038c2f0789f8e7807c90707694654a7 . - . - . - "9196959"^^ . -_:B11f026cb629a637854612b7589793e0f "2021-01-07T00:00:00Z"^^ . -_:B11f026cb629a637854612b7589793e0f "2021-01-08T00:00:00Z"^^ . -_:B11f026cb629a637854612b7589793e0f . -_:B6a7c202cef47f44b7fd913ec41c56e6b "Stad Kortrijk"^^ . -_:B6a7c202cef47f44b7fd913ec41c56e6b . -_:B6a7c202cef47f44b7fd913ec41c56e6b . - . - . - "9197335"^^ . -_:B25bdd7350edd64f8c051b2a0270da481 "https://gipod.vlaanderen.be"@nl-BE . -_:B25bdd7350edd64f8c051b2a0270da481 "10590520"^^ . -_:B25bdd7350edd64f8c051b2a0270da481 . - _:B1b68cc2867ff82a27fa057b1e25d7582 . - "10590548"^^ . - _:B35895785f93ef41711750264d57ce890 . - . - _:Bc1087bbdaf430b6217b863df91868224 . - "2520 Ranst, Berkenlaan: Verhuis"^^ . - "2021-01-06T18:05:31.737Z"^^ . - "2021-01-06T13:05:53.937Z"^^ . - . - _:B97402900c6591564bf5f9b523210c9ae . - . - . - _:B440446dbdd3217dbcfb90003a6b1d88e . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T13:10:45.28Z"^^ . -_:B91bab7ca269f434f9e25d87b5cf4bb7a " POLYGON ((189253.57923384116 223748.99448567163, 189254.14901808344 223743.5269308407, 189251.65721345745 223743.2685189573, 189251.08743182293 223748.73607431352, 189250.51765134826 223754.20362397656, 189249.94787203366 223759.67116794921, 189252.43966883677 223759.92957825586, 189253.00945075898 223754.46203480847, 189253.57923384116 223748.99448567163))"^^ . -_:B91bab7ca269f434f9e25d87b5cf4bb7a . -_:B757a1734d7d0639b3bf201f4f71bc1dc "2021-02-05T06:00:00Z"^^ . -_:B757a1734d7d0639b3bf201f4f71bc1dc "2021-02-06T18:00:00Z"^^ . -_:B757a1734d7d0639b3bf201f4f71bc1dc . - . - "Stelling "^^ . - _:Bfc079d72f15166ee6447dab568b37def . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - _:B61739fe94ac52f08fb1de62893976ac2 . - "2021-01-06T18:05:00.757Z"^^ . - "10590463"^^ . - "2021-01-06T14:08:52.74Z"^^ . - _:B61b04bcf4117bd895aec6cca0bd695e5 . - . - _:B3a033a5e9bba7ce83aad2bb0189aa427 . - "2021-01-06T14:29:15.793Z"^^ . - _:B856004f48d67d5c45e69202c88f5dc60 . -_:B434701ba97b1bfc7b73eaffed47ffe81 "https://gipod.vlaanderen.be"@nl-BE . -_:B434701ba97b1bfc7b73eaffed47ffe81 "10590420"^^ . -_:B434701ba97b1bfc7b73eaffed47ffe81 . -_:Be8b9ba04f025f5ee5e251db847913e8f "Gemeente Middelkerke"^^ . -_:Be8b9ba04f025f5ee5e251db847913e8f . -_:Be8b9ba04f025f5ee5e251db847913e8f . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:05:35.443Z"^^ . - . - _:B58a3e6b48c9df8309e0e8be501cfa665 . - "2021-01-06T12:59:49.32Z"^^ . - _:B3acee27b13f6222134eef287b1416aa8 . - _:B086928356da6493dc3bbf59abe7f0ffc . - "2021-01-06T12:59:49.32Z"^^ . - _:B2a5ab523cbc62df14a4785c8d37fcca6 . - . - . - . - "10590559"^^ . - " Pieter Goruslaan 1-31 : paddenoverzet - Parkeerverbod"^^ . - _:Bca57f89b9749ddef02740c70ec9b725b . -_:B58406db8069692dc4bfa5ea27c21179a "Gemeente Beveren"^^ . -_:B58406db8069692dc4bfa5ea27c21179a . -_:B58406db8069692dc4bfa5ea27c21179a . -_:B926dd8f966712dffa78cb69a6a549bae "Stad Lokeren"^^ . -_:B926dd8f966712dffa78cb69a6a549bae . -_:B926dd8f966712dffa78cb69a6a549bae . -_:Beef7c7125df3a7bea16fa10512f7d563 "Politiezone Leuven"^^ . -_:Beef7c7125df3a7bea16fa10512f7d563 . -_:Beef7c7125df3a7bea16fa10512f7d563 . -_:B8a4a07f866cbb21ea3ed57ea3ac66e0f "Politiezone Brugge"^^ . -_:B8a4a07f866cbb21ea3ed57ea3ac66e0f . -_:B8a4a07f866cbb21ea3ed57ea3ac66e0f . -_:B39fdc655ba17cd3685e22bc45db6858b "https://gipod.vlaanderen.be"@nl-BE . -_:B39fdc655ba17cd3685e22bc45db6858b "10590447"^^ . -_:B39fdc655ba17cd3685e22bc45db6858b . -_:B77e450b21365060ec31549ece2907809 "2021-01-25T06:00:00Z"^^ . -_:B77e450b21365060ec31549ece2907809 "2021-01-29T15:00:00Z"^^ . -_:B77e450b21365060ec31549ece2907809 . -_:Bf2c5a929c9ab619cfb643fb4b4caa8c5 "Politiezone Leuven"^^ . -_:Bf2c5a929c9ab619cfb643fb4b4caa8c5 . -_:Bf2c5a929c9ab619cfb643fb4b4caa8c5 . - "2800 Mechelen, Hombeeksesteenweg 104: Werf met combinatie van types"^^ . - _:Bd974be5c3b318144a8c9065f67973cab . - . - _:Bc8bae1b4948beef89da065899e4a8a9f . - "2021-01-06T18:05:09.173Z"^^ . - "10590489"^^ . - "2021-01-06T13:47:12.423Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - "2021-01-06T13:48:51.24Z"^^ . - _:B420af317b4876b51efaff104e2bcb547 . - . - . - _:B52fbb0f63ff4c0e62658df850abb23ef . - _:B229f66aea275390235ca619d73ff522e . -_:B21d0538d4cbd99a1b7ea4e88a41bc43b "2021-01-20T06:00:00Z"^^ . -_:B21d0538d4cbd99a1b7ea4e88a41bc43b "2021-01-20T10:00:00Z"^^ . -_:B21d0538d4cbd99a1b7ea4e88a41bc43b . -_:B9b0ec8b90cb5b71a380d9c99f7c8556e " POLYGON ((67068.80947604017 179769.44212733675, 67071.31413817937 179769.4023604067, 67071.40932240577 179775.39749080595, 67068.90466314307 179775.43725769036, 67068.80947604017 179769.44212733675))"^^ . -_:B9b0ec8b90cb5b71a380d9c99f7c8556e . - . - . - "9197271"^^ . -_:B92ec5b469640d1aaf193d00495630564 " POLYGON ((219968.60862241837 187078.6710365573, 219966.69958973772 187083.82694098633, 219969.0494992562 187084.69254046492, 219970.95853396674 187079.53663772251, 219972.8675723938 187074.38073055726, 219974.77661453665 187069.224818971, 219972.42669892823 187068.35921443813, 219970.51765881525 187073.5151277082, 219968.60862241837 187078.6710365573))"^^ . -_:B92ec5b469640d1aaf193d00495630564 . -_:B4e9e6ebb29887b478ee37897f7cf4dc0 "2021-01-27T05:00:00Z"^^ . -_:B4e9e6ebb29887b478ee37897f7cf4dc0 "2021-01-27T21:00:00Z"^^ . -_:B4e9e6ebb29887b478ee37897f7cf4dc0 . -_:Bd37747a48a87d8ab475ffeb8c278cd59 "Stad Kortrijk"^^ . -_:Bd37747a48a87d8ab475ffeb8c278cd59 . -_:Bd37747a48a87d8ab475ffeb8c278cd59 . - "2021-01-06T15:17:55.717Z"^^ . - "2021-01-06T18:05:06.87Z"^^ . - "Sint-Jorisgilde 53: Laden en lossen - Parkeerverbod"^^ . - . - _:B1a27ba56de51a73dccfb0d93c2d62b4b . - . - . - "2021-01-06T13:50:59.787Z"^^ . - _:Bdc4ad06a5be1b8bfe242d93a7142a124 . - _:B58d0336c7731a7f900d6bd147f83da52 . - _:B1a43aa0753bc3e7ed5c9036993c9cc80 . - "10590483"^^ . - . - _:B42c065c163b5ed0edcf9b0461903cd02 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . -_:B1856c7bc97848261a248b5b4c7a8dcee "Stad Kortrijk"^^ . -_:B1856c7bc97848261a248b5b4c7a8dcee . -_:B1856c7bc97848261a248b5b4c7a8dcee . -_:Baabe4573e6f71f18838e6aa06c05c0f4 "https://gipod.vlaanderen.be"@nl-BE . -_:Baabe4573e6f71f18838e6aa06c05c0f4 "10590495"^^ . -_:Baabe4573e6f71f18838e6aa06c05c0f4 . -_:B880ee73f963dc1266a94aedab96b2c6b "Gemeente Ingelmunster"^^ . -_:B880ee73f963dc1266a94aedab96b2c6b . -_:B880ee73f963dc1266a94aedab96b2c6b . - . - . - "9197010"^^ . -_:Bc4366e513a0f23205bad1fb7ca60c332 " MULTIPOLYGON (((138225.650190721 210455.811403548, 138226.042113978 210455.822076783, 138226.424424294 210455.90900537, 138226.782429698 210456.06884869, 138227.102372244 210456.295464056, 138227.371956719 210456.580142765, 138227.580823144 210456.911944775, 138227.720944897 210457.27811912, 138227.786937179 210457.664593926, 138227.776263944 210458.056517182, 138227.689335358 210458.438827498, 138227.529492037 210458.796832902, 138227.302876672 210459.116775448, 138227.018197962 210459.386359924, 138226.686395953 210459.595226348, 138224.896908587 210460.48997003, 138224.530734242 210460.630091784, 138224.144259436 210460.696084066, 138223.75233618 210460.685410831, 138223.370025864 210460.598482244, 138223.01202046 210460.438638924, 138222.692077914 210460.212023558, 138222.422493438 210459.927344849, 138222.213627014 210459.595542839, 138222.073505261 210459.229368494, 138222.007512979 210458.842893689, 138222.018186214 210458.450970432, 138222.1051148 210458.068660116, 138222.264958121 210457.710654712, 138222.491573486 210457.390712166, 138222.776252196 210457.12112769, 138223.108054205 210456.912261266, 138224.897541571 210456.017517584, 138225.263715916 210455.87739583, 138225.650190721 210455.811403548)), ((138219.33455301 210444.929775539, 138219.726621406 210444.93013488, 138220.111086215 210445.006976066, 138220.473172668 210445.157346133, 138220.798965986 210445.375466445, 138221.075946116 210445.652954759, 138221.293468865 210445.979147356, 138221.443174957 210446.341508837, 138221.519311271 210446.726113853, 138221.51895193 210447.11818225, 138221.442110744 210447.502647058, 138221.291740676 210447.864733512, 138221.073620365 210448.19052683, 138220.79613205 210448.46750696, 138220.469939454 210448.685029709, 138218.233080247 210449.878021286, 138217.870718766 210450.027727378, 138217.48611375 210450.103863691, 138217.094045353 210450.103504351, 138216.709580545 210450.026663164, 138216.347494092 210449.876293097, 138216.021700773 210449.658172785, 138215.744720643 210449.380684471, 138215.527197894 210449.054491874, 138215.377491802 210448.692130393, 138215.301355489 210448.307525377, 138215.301714829 210447.91545698, 138215.378556016 210447.530992172, 138215.528926083 210447.168905719, 138215.747046395 210446.8431124, 138216.024534709 210446.566132271, 138216.350727306 210446.348609521, 138218.587586512 210445.155617944, 138218.949947993 210445.005911852, 138219.33455301 210444.929775539)))"^^ . -_:Bc4366e513a0f23205bad1fb7ca60c332 . -_:Bf13648086f1c2a910e208ce8c2424b3d "Politiezone Leuven"^^ . -_:Bf13648086f1c2a910e208ce8c2424b3d . -_:Bf13648086f1c2a910e208ce8c2424b3d . -_:Bb13984d1fa35f1bc19bd5ce86f66b428 "Politiezone Leuven"^^ . -_:Bb13984d1fa35f1bc19bd5ce86f66b428 . -_:Bb13984d1fa35f1bc19bd5ce86f66b428 . - _:B9269de8ac563a30ccf7b7ce5e2eb0e79 . - . - . - "8670 Koksijde, Zeedijk 107: IOD - Verhuis"^^ . - _:B73bb3af5dd354c14f15736993a33488b . - "2021-01-06T15:05:53.037Z"^^ . - . - _:Bd5f357a9cc8ba09c2806ced075cc785d . - "10590381"^^ . - "2021-01-06T18:04:34.037Z"^^ . - "2021-01-06T15:05:53.037Z"^^ . - _:Bbe36c650174a119a64c38d4f52772c00 . - _:B94151381a44e8cf8395c93aa0a7c5de3 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B43160946bc918cc0a82fdea8494fd098 . - . -_:B1b1f21395f26d312d80ce9dfab5e28a6 "Stad Ronse"^^ . -_:B1b1f21395f26d312d80ce9dfab5e28a6 . -_:B1b1f21395f26d312d80ce9dfab5e28a6 . - . - . - "9197297"^^ . -_:Bb7057d4e6693feac6667c19035d3d3d6 " POLYGON ((95613.32575906996 159762.30125829173, 95613.4483891962 159762.30537520075, 95613.57053609448 159762.31700413182, 95613.57053609507 159762.3170041319, 95625.94553609389 159763.87950413176, 95625.94553609448 159763.87950413182, 95626.04259664283 159763.89418746636, 95626.13881980041 159763.91361564957, 95626.23397375723 159763.93774187722, 95626.32782927906 159763.96650802714, 95626.42016025972 159763.99984479917, 95626.5107442658 159764.03767188205, 95626.5993630725 159764.0798981471, 95626.68580318934 159764.1264218675, 95626.7698563745 159764.17713096354, 95626.85132013653 159764.23190327256, 95626.92999822205 159764.29060684328, 95627.0057010887 159764.35310025368, 95627.0782463616 159764.4192329516, 95627.14745927288 159764.48884561763, 95627.21317308253 159764.56177054875, 95627.27522948026 159764.6378320624, 95627.33347896676 159764.71684691976, 95627.38778121393 159764.79862476708, 95627.43800540286 159764.88296859438, 95627.48403053911 159764.96967520998, 95627.5257457441 159765.0585357301, 95627.56305052224 159765.14933608187, 95627.59585500303 159765.24185751937, 95627.62408015765 159765.33587715036, 95627.64765798919 159765.43116847324, 95627.6665316966 159765.52750192292, 95627.68065581146 159765.62464542367, 95627.68999630756 159765.72236494828, 95627.69453068281 159765.82042508188, 95627.6942480135 159765.91858958898, 95627.68914898063 159766.01662198274, 95627.67924586819 159766.11428609447, 95627.66456253365 159766.2113466428, 95627.64513435046 159766.3075698004, 95627.62100812279 159766.40272375723, 95627.59224197287 159766.49657927905, 95627.55890520086 159766.5889102597, 95627.52107811795 159766.6794942658, 95627.47885185291 159766.7681130725, 95627.43232813252 159766.85455318933, 95627.38161903649 159766.9386063745, 95627.32684672746 159767.02007013652, 95627.26814315673 159767.09874822205, 95627.20564974635 159767.17445108868, 95627.1395170484 159767.2469963616, 95627.06990438237 159767.31620927286, 95626.99697945126 159767.38192308252, 95626.9209179376 159767.44397948025, 95626.84190308025 159767.50222896674, 95626.76012523293 159767.5565312139, 95626.67578140563 159767.60675540284, 95626.58907479001 159767.6527805391, 95626.50021426992 159767.69449574407, 95626.40941391813 159767.73180052222, 95626.31689248061 159767.76460500303, 95626.22287284966 159767.79283015762, 95626.12758152676 159767.81640798916, 95626.03124807708 159767.83528169658, 95625.93410457633 159767.84940581143, 95625.83638505172 159767.85874630752, 95625.73832491813 159767.8632806828, 95625.64016041101 159767.86299801347, 95625.54212801727 159767.8578989806, 95625.44446390553 159767.84799586816, 95625.44446390495 159767.84799586807, 95613.06946390613 159766.28549586824, 95613.06946390553 159766.28549586816, 95612.97240335718 159766.27081253362, 95612.8761801996 159766.2513843504, 95612.78102624278 159766.22725812276, 95612.68717072095 159766.19849197284, 95612.5948397403 159766.1651552008, 95612.50425573421 159766.12732811793, 95612.41563692752 159766.0851018529, 95612.32919681068 159766.0385781325, 95612.2451436255 159765.98786903644, 95612.16367986349 159765.9330967274, 95612.08500177796 159765.8743931567, 95612.00929891132 159765.8118997463, 95611.93675363841 159765.7457670484, 95611.86754072714 159765.67615438235, 95611.80182691748 159765.60322945123, 95611.73977051975 159765.52716793757, 95611.68152103326 159765.44815308021, 95611.62721878609 159765.3663752329, 95611.57699459716 159765.2820314056, 95611.5309694609 159765.19532479, 95611.48925425591 159765.1064642699, 95611.45194947778 159765.0156639181, 95611.41914499698 159764.9231424806, 95611.39091984236 159764.82912284962, 95611.36734201082 159764.73383152674, 95611.34846830342 159764.63749807706, 95611.33434418855 159764.5403545763, 95611.32500369246 159764.4426350517, 95611.3204693172 159764.3445749181, 95611.32075198651 159764.246410411, 95611.32585101938 159764.14837801724, 95611.33575413183 159764.0507139055, 95611.34911893622 159763.96120907238, 95611.36651898811 159763.87240045037, 95611.38791866205 159763.78446986922, 95611.41327414363 159763.6975973609, 95611.4425335192 159763.61196079108, 95611.47563688215 159763.52773549495, 95611.51251645554 159763.44509391816, 95611.55309673089 159763.36420526382, 95611.59729462281 159763.28523514606, 95611.64501963907 159763.20834525095, 95611.69617406587 159763.1336930054, 95611.75065316795 159763.0614312549, 95611.80834540297 159762.99170795057, 95611.86913264992 159762.92466584622, 95611.93289045099 159762.8604422061, 95611.99948826632 159762.79916852378, 95612.06878974132 159762.7409702531, 95612.14065298587 159762.68596655113, 95612.21493086473 159762.63427003424, 95612.29147129894 159762.5859865476, 95612.37011757704 159762.5412149485, 95612.45070867604 159762.5000469037, 95612.53307959103 159762.4625667021, 95612.61706167305 159762.4288510819, 95612.70248297442 159762.39896907355, 95612.78916860069 159762.3729818585, 95612.87694106884 159762.35094264382, 95612.96562067058 159762.33289655336, 95613.05502584037 159762.31888053525, 95613.14497352707 159762.3089232864, 95613.2352795688 159762.30304519355, 95613.32575906996 159762.30125829173))"^^ . -_:Bb7057d4e6693feac6667c19035d3d3d6 . -_:B140a80b0fabc672e6951d5427cb02cba "Gemeente Tessenderlo"^^ . -_:B140a80b0fabc672e6951d5427cb02cba . -_:B140a80b0fabc672e6951d5427cb02cba . -_:B23c04038d01e34b66befba2717a27bab "https://gipod.vlaanderen.be"@nl-BE . -_:B23c04038d01e34b66befba2717a27bab "10590453"^^ . -_:B23c04038d01e34b66befba2717a27bab . - . - . - "9196954"^^ . -_:Bfbf685aae6b77ce77407688760d1892c " POLYGON ((70835.9142131199 213911.056576799, 70842.532843149 213908.777599718, 70845.1373883847 213916.341748323, 70838.5187583556 213918.620725404, 70835.9142131199 213911.056576799))"^^ . -_:Bfbf685aae6b77ce77407688760d1892c . - . - . - "9196933"^^ . - . - . - "9197289"^^ . - . - . - "9197057"^^ . - . - _:Be44364fa7a9adb79b1f41b5b498b6e00 . - . - . - . - "9197036"^^ . -_:B6c22b03c4ccf6d0758e7390a411b45aa "https://gipod.vlaanderen.be"@nl-BE . -_:B6c22b03c4ccf6d0758e7390a411b45aa "10590504"^^ . -_:B6c22b03c4ccf6d0758e7390a411b45aa . -_:B9e568be89baf8414b6d79b0af884ce6f "Gemeente Beveren"^^ . -_:B9e568be89baf8414b6d79b0af884ce6f . -_:B9e568be89baf8414b6d79b0af884ce6f . - "2021-01-06T18:05:32.65Z"^^ . - "2021-01-06T13:05:10.027Z"^^ . - . - _:B8b393797ec177d413efa54f4f47bcf9d . - _:B92e1a072781d87f2d4bfab96810b5263 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "10590549"^^ . - . - _:Bb8ed70fd711578272bc97111c690df6b . - . - _:Bade44b89c57951fbfb70ebffa1d92b1a . - _:Baefd00198bce6e80c82a6fba6594ad62 . - "2220 Heist-op-den-Berg, Hulshoutsesteenweg 35: Werken i.f.v. Lokaal Bestuur (o.a. nuts- en wegenwerken)"^^ . - . - "2021-01-06T13:05:10.027Z"^^ . - "Bestelwagen In het kader van de reeds lopende werken"^^ . - _:B9caf9acacb7c3acb0c9e1f8fbe6e118c . - _:Bca1df3d66a570a55e52d17d760c0908d . - _:B5b7916b34c838724b909519aed62afbc . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:12.97Z"^^ . - . - "2021-01-06T16:56:54.81Z"^^ . - _:B6df4668f97c6741c302bf4be16b76599 . - _:B05c0e6fd593ba5ad69fda1653ab0937b . - . - . - "10590332"^^ . - "2021-01-06T16:56:54.81Z"^^ . -_:B4b342cd7b7bec4e53cb20c8baaef8285 " POLYGON ((156569.258415376 218419.123817213, 156570.525968926 218419.981279909, 156573.583009842 218414.277288932, 156572.203613331 218413.49438821, 156569.258415376 218419.123817213))"^^ . -_:B4b342cd7b7bec4e53cb20c8baaef8285 . -_:B40a82eb79311df8355d4a82ee16ce25c "https://gipod.vlaanderen.be"@nl-BE . -_:B40a82eb79311df8355d4a82ee16ce25c "10590374"^^ . -_:B40a82eb79311df8355d4a82ee16ce25c . - _:Bb9d69c81e8ee598f5b3115041d7ac73c . - "Wegeniswerken In opdracht van de Watergroep mogen wij een huisaansluiting op de waterleiding maken. We willen graag parkeerverbod plaatsen zodat er ruimte is voor ons voertuig met materiaal."^^ . - "2021-01-06T16:01:20.95Z"^^ . - "10590351"^^ . - _:Bf56f2d86166aacecdbe10e22fff05133 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - "2021-01-06T18:04:19.793Z"^^ . - . - _:Bff90fcbb5238b08a09d2d007ea28dde6 . - . - "2021-01-06T16:01:20.95Z"^^ . - _:Bb7de050393a63c7d8f269d2248e066ab . - _:B049135c7c92210bac6e13db8f0a7e6bd . -_:Ba026b1c494721a683b3b512c36ae0be7 "https://gipod.vlaanderen.be"@nl-BE . -_:Ba026b1c494721a683b3b512c36ae0be7 "10590383"^^ . -_:Ba026b1c494721a683b3b512c36ae0be7 . - . - . - "9197124"^^ . -_:B94151381a44e8cf8395c93aa0a7c5de3 "Gemeente Koksijde"^^ . -_:B94151381a44e8cf8395c93aa0a7c5de3 . -_:B94151381a44e8cf8395c93aa0a7c5de3 . -_:B1f05de6ef503c1ffc22dad39bb29541f "Stad Lokeren"^^ . -_:B1f05de6ef503c1ffc22dad39bb29541f . -_:B1f05de6ef503c1ffc22dad39bb29541f . -_:B906f41c78f27e038eb636ecc533ce1b3 "https://gipod.vlaanderen.be"@nl-BE . -_:B906f41c78f27e038eb636ecc533ce1b3 "10590546"^^ . -_:B906f41c78f27e038eb636ecc533ce1b3 . - . - . - "9197191"^^ . -_:B8cd71a2f253e285f4042ca9301922791 "2021-01-12T23:00:00Z"^^ . -_:B8cd71a2f253e285f4042ca9301922791 "2021-01-14T22:30:00Z"^^ . -_:B8cd71a2f253e285f4042ca9301922791 . -_:B52fbb0f63ff4c0e62658df850abb23ef "Stad Mechelen"^^ . -_:B52fbb0f63ff4c0e62658df850abb23ef . -_:B52fbb0f63ff4c0e62658df850abb23ef . -_:B6c8da483c2d2667f1a18dd003a9f800b "Gemeente Brasschaat"^^ . -_:B6c8da483c2d2667f1a18dd003a9f800b . -_:B6c8da483c2d2667f1a18dd003a9f800b . -_:B05151737ca5da6e236e0c93f66b7e60f "Stad Dendermonde"^^ . -_:B05151737ca5da6e236e0c93f66b7e60f . -_:B05151737ca5da6e236e0c93f66b7e60f . - . - _:B4f7d32f9b8f72e1aa14df44a9c536c10 . - . -_:Bd057f23c8937d0aae52b0e6341ada615 " MULTIPOLYGON (((150619.161664406 189143.871286085, 150619.4599123 189145.138839636, 150615.508127701 189146.108145292, 150615.135317834 189144.989715689, 150619.161664406 189143.871286085)), ((150615.135317834 189132.537866105, 150615.880937569 189133.730857682, 150611.481781129 189134.998411233, 150610.959847315 189133.730857682, 150615.135317834 189132.537866105)))"^^ . -_:Bd057f23c8937d0aae52b0e6341ada615 . -_:B0d8a0c2f042f44af45521045af6814a2 "Stad Ronse"^^ . -_:B0d8a0c2f042f44af45521045af6814a2 . -_:B0d8a0c2f042f44af45521045af6814a2 . -_:B6436f390ec06baf12906abbd2a7aa143 "Stad Aalst"^^ . -_:B6436f390ec06baf12906abbd2a7aa143 . -_:B6436f390ec06baf12906abbd2a7aa143 . - . - "Verhuiswagen"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Ba671bf0bf242444d10cecc1b5d2d54a4 . - "10590392"^^ . - . - _:B8b9256c0063bcf4e2c812bde90c14b42 . - _:B912e9ffc5b68382ef6e70bdb52cf65cc . - "2021-01-06T14:58:03.277Z"^^ . - "2021-01-06T18:04:37.877Z"^^ . - . - _:Bff79189426d8be21c66736851c89986c . - "2021-01-06T15:26:08.937Z"^^ . - . - _:Ba1e1f76239a60fdb9dbed73297db918c . -_:Bdbd8dbb74f77acbdcefc50e5af39080b "2021-01-22T05:00:00Z"^^ . -_:Bdbd8dbb74f77acbdcefc50e5af39080b "2021-01-22T13:00:00Z"^^ . -_:Bdbd8dbb74f77acbdcefc50e5af39080b . -_:B57ef8e0e9496a0b9bfc945ddbc5b61db "2021-02-16T05:00:00Z"^^ . -_:B57ef8e0e9496a0b9bfc945ddbc5b61db "2021-02-16T19:00:00Z"^^ . -_:B57ef8e0e9496a0b9bfc945ddbc5b61db . - . - _:B9b0ec8b90cb5b71a380d9c99f7c8556e . - . - . - . - "9197217"^^ . -_:B755f29f5030f578fae5540e3ef1bf516 "Stad Lier"^^ . -_:B755f29f5030f578fae5540e3ef1bf516 . -_:B755f29f5030f578fae5540e3ef1bf516 . -_:B0f795455c27ebc3c2da91f040512823e "Politiezone Leuven"^^ . -_:B0f795455c27ebc3c2da91f040512823e . -_:B0f795455c27ebc3c2da91f040512823e . - "2021-01-06T18:04:40.26Z"^^ . - . - "10590401"^^ . - "2021-01-06T14:51:58.107Z"^^ . - "2021-01-06T15:07:08.143Z"^^ . - "Verhuiswagen Verhuiswagen en lift om spullen van eerste verdiep te halen."^^ . - _:B60b0ee02f25a5b2940cb07050434b964 . - _:B5dc832538b43fe489f1679381d017614 . - . - . - _:B8fd98df698a7b354fa59984538285c4d . - _:B0124a7da98549c06fce1de016028fa69 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bd37747a48a87d8ab475ffeb8c278cd59 . - . -_:Bb01aaba24cf044a697091c08b4a982b3 "Gemeente Brasschaat"^^ . -_:Bb01aaba24cf044a697091c08b4a982b3 . -_:Bb01aaba24cf044a697091c08b4a982b3 . -_:B9e1970d85418ade96041828d039a5f6f "Stad Dendermonde"^^ . -_:B9e1970d85418ade96041828d039a5f6f . -_:B9e1970d85418ade96041828d039a5f6f . -_:Bfb4e959b95a12092c457085807e3173d "Stad Mechelen"^^ . -_:Bfb4e959b95a12092c457085807e3173d . -_:Bfb4e959b95a12092c457085807e3173d . -_:Bdc4ad06a5be1b8bfe242d93a7142a124 "Stad Dendermonde"^^ . -_:Bdc4ad06a5be1b8bfe242d93a7142a124 . -_:Bdc4ad06a5be1b8bfe242d93a7142a124 . - . - . - "9197209"^^ . - . - _:B92ec5b469640d1aaf193d00495630564 . - . -_:Bbe0c84ea49e82f7c6e3ba743c0b6a94d "2020-12-29T06:00:00Z"^^ . -_:Bbe0c84ea49e82f7c6e3ba743c0b6a94d "2021-02-06T19:00:00Z"^^ . -_:Bbe0c84ea49e82f7c6e3ba743c0b6a94d . -_:B3587a82cb3cd257da5e626691f0193c8 "https://gipod.vlaanderen.be"@nl-BE . -_:B3587a82cb3cd257da5e626691f0193c8 "10590409"^^ . -_:B3587a82cb3cd257da5e626691f0193c8 . -_:Be79329ea18e3c8a5f3d24c69c32d397d "Gemeente Hamme"^^ . -_:Be79329ea18e3c8a5f3d24c69c32d397d . -_:Be79329ea18e3c8a5f3d24c69c32d397d . -_:Bdf6c8eae91e970b0f77422db3f2113e0 "Stad Aalst"^^ . -_:Bdf6c8eae91e970b0f77422db3f2113e0 . -_:Bdf6c8eae91e970b0f77422db3f2113e0 . -_:B28abfda81fb56f2c37bf137c2e2fd4af "Politiezone Leuven"^^ . -_:B28abfda81fb56f2c37bf137c2e2fd4af . -_:B28abfda81fb56f2c37bf137c2e2fd4af . -_:B0f94dd5e70be878162d2f30756c2779b "Stad Kortrijk"^^ . -_:B0f94dd5e70be878162d2f30756c2779b . -_:B0f94dd5e70be878162d2f30756c2779b . -_:Bdaf4a1dcff3de3b14e47d2a0a3edf153 " POLYGON ((77072.23660894507 202169.48247884715, 77078.3143381737 202166.142102887, 77064.36286635812 202136.0787124195, 77057.80141268537 202139.18049324988, 77072.23660894507 202169.48247884715))"^^ . -_:Bdaf4a1dcff3de3b14e47d2a0a3edf153 . -_:B18eb15d95f42fdb7b892c279d5121640 "2021-01-25T06:00:00Z"^^ . -_:B18eb15d95f42fdb7b892c279d5121640 "2021-01-29T15:00:00Z"^^ . -_:B18eb15d95f42fdb7b892c279d5121640 . - . - _:B43a945c27023c1c748b052119a09d2f5 . - "10590433"^^ . - "2021-01-06T18:04:50.15Z"^^ . - . - _:Bef1ed512a983ef627525bb7c5e40f702 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "Bestelwagen"^^ . - . - "2021-01-06T14:32:17.933Z"^^ . - _:B007a310d7331ec2253e6cd3cfc1fde8b . - . - "2021-01-06T16:40:05.75Z"^^ . - _:Bcc5ba14c9580b5a0959be48792bd908f . - _:Bd73840cade6318e39b3a373f2858c52e . -_:B881e9d09ef8771b20c21ea1684ce431a "Stad Kortrijk"^^ . -_:B881e9d09ef8771b20c21ea1684ce431a . -_:B881e9d09ef8771b20c21ea1684ce431a . -_:B6c5dbf5e491ce25fe09907d13b87ce50 "https://gipod.vlaanderen.be"@nl-BE . -_:B6c5dbf5e491ce25fe09907d13b87ce50 "10590525"^^ . -_:B6c5dbf5e491ce25fe09907d13b87ce50 . -_:Be7eff8a28e3b3b986b1a0878d3e07fe5 "Stad Lier"^^ . -_:Be7eff8a28e3b3b986b1a0878d3e07fe5 . -_:Be7eff8a28e3b3b986b1a0878d3e07fe5 . - . - . - "9196967"^^ . -_:B2f078c9a786f4349ac56cb65aad30cb1 " POLYGON ((175238.868935342 173322.17748553026, 175241.21740834697 173327.14964674413, 175238.951298044 173328.21421776153, 175236.6028233716 173323.24205858074, 175238.868935342 173322.17748553026))"^^ . -_:B2f078c9a786f4349ac56cb65aad30cb1 . -_:Bc2a8b850fd36ae0c4ac6ab3e80324276 " POLYGON ((70053.0832590336 211955.917317463, 70053.9600013272 211954.119729371, 70062.9479417901 211958.503440839, 70062.0711994966 211960.301028931, 70053.0832590336 211955.917317463))"^^ . -_:Bc2a8b850fd36ae0c4ac6ab3e80324276 . -_:B931ff6808c325f325acb22c10c673790 "Gemeente Bredene"^^ . -_:B931ff6808c325f325acb22c10c673790 . -_:B931ff6808c325f325acb22c10c673790 . -_:B3b4f7f432f3cd8b7600c0faedfd1f484 "https://gipod.vlaanderen.be"@nl-BE . -_:B3b4f7f432f3cd8b7600c0faedfd1f484 "10590577"^^ . -_:B3b4f7f432f3cd8b7600c0faedfd1f484 . - . - . - _:B630785e0041e925bbdef55777ba4ffa0 . - . -_:B109ab38a98a8649687b300fd086ca7e2 "https://gipod.vlaanderen.be"@nl-BE . -_:B109ab38a98a8649687b300fd086ca7e2 "10590538"^^ . -_:B109ab38a98a8649687b300fd086ca7e2 . -_:Bb9241c13d523c613db57dc309c836b23 "Politiezone Leuven"^^ . -_:Bb9241c13d523c613db57dc309c836b23 . -_:Bb9241c13d523c613db57dc309c836b23 . -_:Ba615b3630c4a9958fffeef2f77908ec3 "Stad Aalst"^^ . -_:Ba615b3630c4a9958fffeef2f77908ec3 . -_:Ba615b3630c4a9958fffeef2f77908ec3 . -_:Bd974be5c3b318144a8c9065f67973cab "2021-01-11T06:00:00Z"^^ . -_:Bd974be5c3b318144a8c9065f67973cab "2021-01-23T17:00:00Z"^^ . -_:Bd974be5c3b318144a8c9065f67973cab . -_:B234d77df8372d53e841ee55caae75d23 " POLYGON ((68479.3072352306 212816.634296053, 68484.2585755744 212817.330161558, 68483.7018831705 212821.291233833, 68478.7505428268 212820.595368328, 68479.3072352306 212816.634296053))"^^ . -_:B234d77df8372d53e841ee55caae75d23 . -_:Ba19308a7c2bc284ac2c05b2607ffe98e "https://gipod.vlaanderen.be"@nl-BE . -_:Ba19308a7c2bc284ac2c05b2607ffe98e "10590582"^^ . -_:Ba19308a7c2bc284ac2c05b2607ffe98e . -_:Bc96207a3959f74c41bbca13979584dc7 "Gemeente Middelkerke"^^ . -_:Bc96207a3959f74c41bbca13979584dc7 . -_:Bc96207a3959f74c41bbca13979584dc7 . -_:B1968f916fa99c456e63ddb93469c3828 "Stad Lier"^^ . -_:B1968f916fa99c456e63ddb93469c3828 . -_:B1968f916fa99c456e63ddb93469c3828 . -_:B25b38574c76efbd0f0dde29df5e9d16b "https://gipod.vlaanderen.be"@nl-BE . -_:B25b38574c76efbd0f0dde29df5e9d16b "10590521"^^ . -_:B25b38574c76efbd0f0dde29df5e9d16b . -_:Bcd8a9500cf54a7d5300ec25340213365 "https://gipod.vlaanderen.be"@nl-BE . -_:Bcd8a9500cf54a7d5300ec25340213365 "10590436"^^ . -_:Bcd8a9500cf54a7d5300ec25340213365 . -_:B2ef9ba39a4cdc6523dfc2d80dc09cbb5 "Stad Turnhout"^^ . -_:B2ef9ba39a4cdc6523dfc2d80dc09cbb5 . -_:B2ef9ba39a4cdc6523dfc2d80dc09cbb5 . - . - _:B747a72281dc774b82cf59dd894426daa . - . -_:B09d8f38501bb6602a10c04d250cf9e6e " POLYGON ((174552.75525013 173683.37048900966, 174547.58434142772 173685.2709641494, 174548.45057192128 173687.6151069561, 174553.62147862726 173685.71463352907, 174558.7923891149 173683.81416451558, 174563.9633033837 173681.9136999091, 174563.09707887872 173679.56955196336, 174557.92616261373 173681.47001828067, 174552.75525013 173683.37048900966))"^^ . -_:B09d8f38501bb6602a10c04d250cf9e6e . - . - _:B1f7f00bc4bb20e1856dac2349160dda3 . - . -_:B797eb69a758ef5685769affe866fab48 "Stad Mechelen"^^ . -_:B797eb69a758ef5685769affe866fab48 . -_:B797eb69a758ef5685769affe866fab48 . -_:B493b230cb18fcfaf5dad5c888ae4c1c0 "2021-01-20T05:00:00Z"^^ . -_:B493b230cb18fcfaf5dad5c888ae4c1c0 "2021-02-03T19:00:00Z"^^ . -_:B493b230cb18fcfaf5dad5c888ae4c1c0 . -_:Bf98377530dc27f02f2295ef190ff5c77 " POLYGON ((157638.745539246 190103.148123839, 157658.280776317 190100.613016738, 157657.982528423 190098.003347664, 157636.806927934 190100.687578712, 157637.105175828 190103.073561865, 157638.745539246 190103.148123839))"^^ . -_:Bf98377530dc27f02f2295ef190ff5c77 . -_:Bd9778cd8e5b43be2c6a012854d777ef3 "Stad Kortrijk"^^ . -_:Bd9778cd8e5b43be2c6a012854d777ef3 . -_:Bd9778cd8e5b43be2c6a012854d777ef3 . - . - _:B449d569f3e3c8d24db0f59b4b516a714 . - . -_:Bf8f71247ff26446e438299dd1195bc99 "2021-01-11T05:00:00Z"^^ . -_:Bf8f71247ff26446e438299dd1195bc99 "2021-01-24T21:00:00Z"^^ . -_:Bf8f71247ff26446e438299dd1195bc99 . -_:B4951b41db983a5f2c428808ada86d0da "Gemeente Borsbeek"^^ . -_:B4951b41db983a5f2c428808ada86d0da . -_:B4951b41db983a5f2c428808ada86d0da . -_:B6eae231f45c832a1d5228086f91d81db "2021-02-09T06:00:00Z"^^ . -_:B6eae231f45c832a1d5228086f91d81db "2021-02-09T20:00:00Z"^^ . -_:B6eae231f45c832a1d5228086f91d81db . -_:Bb6c0a53495559dd7ef2b60c2bbe0eebb "Politiezone Leuven"^^ . -_:Bb6c0a53495559dd7ef2b60c2bbe0eebb . -_:Bb6c0a53495559dd7ef2b60c2bbe0eebb . -_:Bc7e3e692e991734d7c6f576d169efc1b "Stad Ninove"^^ . -_:Bc7e3e692e991734d7c6f576d169efc1b . -_:Bc7e3e692e991734d7c6f576d169efc1b . - _:B9cd130008b4ad197c1b6b700a1624ea9 . - "2930 Brasschaat, Heislag 19: Huisaansluitingen/herstel kolken"^^ . - . - . - _:B5e69612ab5b53ba72b0d3e948af99838 . - "2021-01-06T13:37:09.463Z"^^ . - "10590526"^^ . - . - _:B6c8da483c2d2667f1a18dd003a9f800b . - _:Bb997ce0622948a9144f3a55d0a69164a . - . - _:Bbfaa89dfe34b30010ef1f7aa141e9fe8 . - "2021-01-06T13:19:39.98Z"^^ . - "2021-01-06T18:05:25.817Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B4316d24aa51b3f37f671c0f394c9a126 . - . -_:B4065ba40b0720e7aaebb0b73b4c3193d "Stad Turnhout"^^ . -_:B4065ba40b0720e7aaebb0b73b4c3193d . -_:B4065ba40b0720e7aaebb0b73b4c3193d . - _:Bddf481b0440495144801050e1d456c7e . - . - "2021-01-06T18:05:17.45Z"^^ . - "2021-01-06T13:33:41.213Z"^^ . - "2021-01-06T13:33:41.213Z"^^ . - . - _:B94c24ee23fed3c5d8c10e41abee43e4c . - _:B0004900853979b1ece37f53ac1710889 . - . - "Astridlaan 55, 8792 DES // Container + parkeerverbod // Zone 50\nPlaatsen van container voor bouwafval en leeghalen van de woonst."^^ . - "10590503"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B8fa944b644f797af268e14ea83064e0c . - _:B0e35bf97d997a2a3aea79f5de267fd44 . -_:B49b7f1d8c80a05c6e4b0fce117feede4 "Politiezone Leuven"^^ . -_:B49b7f1d8c80a05c6e4b0fce117feede4 . -_:B49b7f1d8c80a05c6e4b0fce117feede4 . -_:B3acee27b13f6222134eef287b1416aa8 "Stad Dendermonde"^^ . -_:B3acee27b13f6222134eef287b1416aa8 . -_:B3acee27b13f6222134eef287b1416aa8 . - . - _:Bbbf4bd0e7c094b3f4e7f071c9b137c25 . - . - . - . - . - _:Bc62ccceb9774caaaaf750f128eb04743 . - . - . - . - "9197073"^^ . -_:B6ea3bf49a1f6bde11ee6074771b4a3e0 "2021-01-13T06:00:00Z"^^ . -_:B6ea3bf49a1f6bde11ee6074771b4a3e0 "2021-01-30T15:00:00Z"^^ . -_:B6ea3bf49a1f6bde11ee6074771b4a3e0 . -_:B34c942b37ddb828c17e2d737d5bd3111 "https://gipod.vlaanderen.be"@nl-BE . -_:B34c942b37ddb828c17e2d737d5bd3111 "10590449"^^ . -_:B34c942b37ddb828c17e2d737d5bd3111 . -_:B88e4564ffe820294460761093a1f5a46 "Stad Turnhout"^^ . -_:B88e4564ffe820294460761093a1f5a46 . -_:B88e4564ffe820294460761093a1f5a46 . -_:B183b69d54c69f07163e8e39193104835 "Politiezone Leuven"^^ . -_:B183b69d54c69f07163e8e39193104835 . -_:B183b69d54c69f07163e8e39193104835 . - _:B4e10943cbccd17faa0c88928e1045280 . - _:Bdfc0a7787135f967dfa4e3177dd3a822 . - "2021-01-06T14:38:50.44Z"^^ . - "2021-01-06T14:38:50.44Z"^^ . - _:B300a7648b6857257faf71224236e1d77 . - _:B8c5c205ad2b8bb45016fdf302a0419b7 . - "Wegeniswerken Aanleg nutsleidingen - glasvezel in opdracht van Fluvius.\n=> deze werken zijn reeds uitgevoerd geweest. Maar ze dienen de klinkers en boordstenen opnieuw te plaatsen. In bijlage vindt u de foto's terug.\nGraag zouden ze dit in de loop van volgende maand doen, wanneer ze een gaatje vinde"^^ . - . - . - "10590423"^^ . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Beb5066e252fe14bdea3fc1bc41dc5011 . - "2021-01-06T18:04:47.303Z"^^ . - . - . - "9196983"^^ . -_:B8c9d115755ee1c69e713241bf442d469 " POLYGON ((65368.1055183203 202989.511806749, 65360.8357258988 202989.605009216, 65360.8357258988 202989.605009216, 65361.0221308326 202988.113769745, 65368.0123158533 202988.113769745, 65368.1055183203 202989.511806749))"^^ . -_:B8c9d115755ee1c69e713241bf442d469 . - . - _:Bee96dfbd126d199414a65f9c233c1ec3 . - . -_:B82e436e7b145dcb0b36242ba53e43006 "Gemeente Beveren"^^ . -_:B82e436e7b145dcb0b36242ba53e43006 . -_:B82e436e7b145dcb0b36242ba53e43006 . - . - _:B13ec1f1ccbeaec9a24cb2059f06c4755 . - . - . - _:B158a639da1b9d7235c1a54cebbf1b6df . - . - _:Bbd1593202edc05fc4b7df0334e6ff9fc . - . - _:B5a43357e16bf05741b36522ff1ea50b9 . - . - "10590398"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:39.337Z"^^ . - "plaatsen van een container"^^ . - _:B2875372ad8817c68a6307051a6285cf8 . - "2021-01-06T14:54:38.827Z"^^ . - . - "2021-01-06T14:54:38.827Z"^^ . - . - _:B824ed89c77a1ddc27326f1c352023c66 . - _:B256c880ef9bda8783ccedb5dc63dd0a9 . -_:B24a27fcca8528cbdb5ab883b8f4facea "https://gipod.vlaanderen.be"@nl-BE . -_:B24a27fcca8528cbdb5ab883b8f4facea "10590445"^^ . -_:B24a27fcca8528cbdb5ab883b8f4facea . -_:B3d51b2cabeca554b3971089b4955053d "Stad Ronse"^^ . -_:B3d51b2cabeca554b3971089b4955053d . -_:B3d51b2cabeca554b3971089b4955053d . - . - . - "9197099"^^ . -_:B4e10943cbccd17faa0c88928e1045280 "Stad Turnhout"^^ . -_:B4e10943cbccd17faa0c88928e1045280 . -_:B4e10943cbccd17faa0c88928e1045280 . -_:Bdfb6587c8512afff810811f99296faca "2021-01-13T08:00:00Z"^^ . -_:Bdfb6587c8512afff810811f99296faca "2021-01-16T14:00:00Z"^^ . -_:Bdfb6587c8512afff810811f99296faca . -_:B08673ce26078022606c67e5827d150e5 "Politiezone Leuven"^^ . -_:B08673ce26078022606c67e5827d150e5 . -_:B08673ce26078022606c67e5827d150e5 . -_:Bc1d583beecfbfde59626d70dab957fc5 " MULTIPOLYGON (((126693.004830379 181412.704114072, 126705.004830379 181412.704114072, 126705.004830379 181414.704114072, 126693.004830379 181414.704114072, 126693.004830379 181412.704114072)), ((126692.980722678 181411.638312627, 126708.980722678 181411.638312627, 126708.980722678 181412.638312627, 126692.980722678 181412.638312627, 126692.980722678 181411.638312627)))"^^ . -_:Bc1d583beecfbfde59626d70dab957fc5 . -_:Ba95736f2a9d7a28a279bfc9350edf44c "https://gipod.vlaanderen.be"@nl-BE . -_:Ba95736f2a9d7a28a279bfc9350edf44c "10590524"^^ . -_:Ba95736f2a9d7a28a279bfc9350edf44c . -_:B341016649f2b6e1b5192c785c27e627c "Gemeente Meise"^^ . -_:B341016649f2b6e1b5192c785c27e627c . -_:B341016649f2b6e1b5192c785c27e627c . -_:B50dd1fd9dac0c1d421d3e7b5941db999 "Stad Izegem"^^ . -_:B50dd1fd9dac0c1d421d3e7b5941db999 . -_:B50dd1fd9dac0c1d421d3e7b5941db999 . -_:B9017c213345c889314b4cb9ca6bcb31e "Gemeente Schoten"^^ . -_:B9017c213345c889314b4cb9ca6bcb31e . -_:B9017c213345c889314b4cb9ca6bcb31e . -_:Bff79189426d8be21c66736851c89986c "Stad Izegem"^^ . -_:Bff79189426d8be21c66736851c89986c . -_:Bff79189426d8be21c66736851c89986c . -_:B4f263ff4e505ede540eaa18e0765baea "2020-12-07T05:00:00Z"^^ . -_:B4f263ff4e505ede540eaa18e0765baea "2021-01-03T21:00:00Z"^^ . -_:B4f263ff4e505ede540eaa18e0765baea . - . - _:Bc8f0294a4e910c7b261ac61d99c1cd6b . - . -_:B1bad81fefe27528fe3433acbbaeb79c0 "Stad Eeklo"^^ . -_:B1bad81fefe27528fe3433acbbaeb79c0 . -_:B1bad81fefe27528fe3433acbbaeb79c0 . -_:B23deadd8ddb2b98c1d0a873ac05258d5 "Gemeente De Panne"^^ . -_:B23deadd8ddb2b98c1d0a873ac05258d5 . -_:B23deadd8ddb2b98c1d0a873ac05258d5 . - . - _:B548e6f72b19d73155c4641fb25354afd . - . - _:B7df343ae36c5af9123f57be1918c642d . - "2021-01-06T13:40:55.66Z"^^ . - "2021-01-06T13:13:06.117Z"^^ . - "Bestelwagen Twee dwarsplaatsen over 7 = ( verlenging vergunning 53502)"^^ . - "2021-01-06T18:05:28.757Z"^^ . - _:B21f8fd37585dd79d4622563de24c74f0 . - . - _:Bed0dcf7cc620a57b844e6506eeff3ac5 . - . - _:Ba478f8310eaf175a26684ef45874f850 . - . - "10590537"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:Baa6508e0e8bf60ee89043bcfa40bb9a9 . -_:B90ac90820c68a00d7c324f0f1ed31049 "2021-01-21T06:00:00Z"^^ . -_:B90ac90820c68a00d7c324f0f1ed31049 "2021-01-21T17:00:00Z"^^ . -_:B90ac90820c68a00d7c324f0f1ed31049 . -_:Ba560afb499c4da43e169fa3dc33d6465 "Gemeente Bredene"^^ . -_:Ba560afb499c4da43e169fa3dc33d6465 . -_:Ba560afb499c4da43e169fa3dc33d6465 . -_:B519b9f0052ff7c515a6c316251947623 "https://gipod.vlaanderen.be"@nl-BE . -_:B519b9f0052ff7c515a6c316251947623 "10590558"^^ . -_:B519b9f0052ff7c515a6c316251947623 . -_:Baa3125e939935cb01eb3bf19c8f47535 "Stad Ronse"^^ . -_:Baa3125e939935cb01eb3bf19c8f47535 . -_:Baa3125e939935cb01eb3bf19c8f47535 . - . - . - "9197179"^^ . - . - . - "9197158"^^ . -_:B72b7a239d8d36e4c9eef1ebeb9ed24e4 "Gemeente Meise"^^ . -_:B72b7a239d8d36e4c9eef1ebeb9ed24e4 . -_:B72b7a239d8d36e4c9eef1ebeb9ed24e4 . -_:Bf040d48e716a50378e3a458c0e48e047 "Politiezone Brugge"^^ . -_:Bf040d48e716a50378e3a458c0e48e047 . -_:Bf040d48e716a50378e3a458c0e48e047 . -_:Be136a6a7dae50c7a12eb63ff3ac524b5 "Gemeente Hooglede"^^ . -_:Be136a6a7dae50c7a12eb63ff3ac524b5 . -_:Be136a6a7dae50c7a12eb63ff3ac524b5 . - "2021-01-06T13:09:25.443Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - "2021-01-06T13:45:20.38Z"^^ . - "2021-01-06T18:05:30.29Z"^^ . - _:Ba2d7e7129d6a0872bbe269130e1bcf1d . - . - _:Bf803249d8839d273af3a8eacf516d597 . - _:B0494d87ca08c9f65da7d223f612a8dc1 . - . - _:Be290dead4fe3a05c6272637dadeb5498 . - . - _:B1ce63bebb2a0abf1548df2eaa63d5b82 . - "Voertuig Verhuis."^^ . - "10590543"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B861031f27c23c1be79e8e39f7982eedc . - _:Ba4658017497ea6a3d89fea3326be3b24 . - "9100 Sint-Niklaas, Bremstraat 28: Verhuis/levering zonder lift"^^ . - . - "2021-01-06T14:37:57.397Z"^^ . - . - _:B9144611b8cbf661261d5e44435006937 . - . - "2021-01-06T18:04:51.597Z"^^ . - _:Bc2623d413cc7638797ba72c5c45975dc . - _:B8ba383de2aaf55e236b33edfdcb23bfa . - "2021-01-06T14:26:45.077Z"^^ . - "10590439"^^ . - . - . - "9197233"^^ . -_:B32172f5de00abe13b33b52aed59506ea " MULTIPOLYGON (((129769.654299203 191488.659104092, 129770.045836713 191488.679503478, 129770.425871217 191488.775896075, 129770.779798202 191488.944577568, 129771.094016452 191489.179065624, 129771.356450736 191489.470348997, 129771.557015852 191489.80723383, 129771.688004195 191490.176773829, 129771.744381956 191490.564767778, 129771.72398257 191490.956305289, 129771.627589973 191491.336339792, 129771.45890848 191491.690266777, 129771.224420424 191492.004485027, 129770.933137051 191492.266919311, 129770.596252218 191492.467484427, 129770.226712219 191492.59847277, 129769.83871827 191492.654850531, 129731.066492021 191494.444337897, 129730.674954511 191494.42393851, 129730.294920007 191494.327545914, 129729.940993023 191494.15886442, 129729.626774773 191493.924376365, 129729.364340489 191493.633092992, 129729.163775373 191493.296208159, 129729.03278703 191492.92666816, 129728.976409268 191492.53867421, 129728.996808655 191492.1471367, 129729.093201251 191491.767102196, 129729.261882745 191491.413175212, 129729.4963708 191491.098956962, 129729.787654173 191490.836522677, 129730.124539007 191490.635957561, 129730.494079006 191490.504969219, 129730.882072955 191490.448591457, 129769.654299203 191488.659104092)), ((129720.717385408 191430.203784163, 129721.109141806 191430.219426474, 129721.49031905 191430.311196104, 129721.846268715 191430.475566397, 129722.163311852 191430.706220696, 129722.429264674 191430.994295085, 129722.633906761 191431.328719027, 129722.769373833 191431.696640797, 129722.830459967 191432.083921369, 129727.005930486 191503.663415981, 129727.008531582 191503.836200347, 129725.815540006 191546.187401325, 129725.764201211 191546.584747997, 129725.634694442 191546.963889192, 129725.432216808 191547.30960997, 129725.164893738 191547.608036552, 129724.84345291 191547.847193076, 129724.480793748 191548.017482188, 129724.09146977 191548.112070182, 129704.121511799 191550.885675456, 129694.184097479 191624.539452183, 129694.093842397 191624.92099088, 129693.930887035 191625.277590524, 129693.701493674 191625.595547193, 129693.414477774 191625.862641988, 129693.080869194 191626.068610607, 129692.713488325 191626.205537792, 129692.326453408 191626.268161508, 129691.934637978 191626.254075159, 129691.553099281 191626.163820078, 129691.196499636 191626.000864715, 129690.878542968 191625.771471355, 129690.611448173 191625.484455454, 129690.405479553 191625.150846875, 129690.268552368 191624.783466006, 129690.205928653 191624.396431089, 129690.220015001 191624.004615658, 129700.360443404 191548.846146316, 129700.443785198 191548.485121729, 129700.592292543 191548.145666024, 129700.800868497 191547.839429712, 129701.062354492 191547.576923177, 129701.367776029 191547.367155944, 129701.706650688 191547.217327467, 129702.067347901 191547.132580032, 129721.864783336 191544.382936221, 129723.007682459 191503.810017388, 129718.837248203 191432.316858722, 129718.852890514 191431.925102324, 129718.944660143 191431.54392508, 129719.109030437 191431.187975416, 129719.339684736 191430.870932278, 129719.627759125 191430.604979457, 129719.962183067 191430.400337369, 129720.330104837 191430.264870297, 129720.717385408 191430.203784163)), ((129714.400817711 191422.450071804, 129714.787725713 191422.513474916, 129795.314657152 191443.9873233, 129795.681761491 191444.124990146, 129796.014954555 191444.331630266, 129796.30143192 191444.599302596, 129796.530184421 191444.917720638, 129796.692421229 191445.274647766, 129796.781907674 191445.656367471, 129796.795204842 191446.048210478, 129796.73180173 191446.43511848, 129796.594134884 191446.80222282, 129796.387494764 191447.135415884, 129796.119822434 191447.421893249, 129795.801404392 191447.65064575, 129795.444477263 191447.812882558, 129795.062757558 191447.902369003, 129794.670914552 191447.915666171, 129794.284006549 191447.852263058, 129721.813480884 191428.526789548, 129713.757075111 191426.378414675, 129713.389970771 191426.240747829, 129713.056777707 191426.034107709, 129712.770300343 191425.766435379, 129712.541547841 191425.448017337, 129712.379311033 191425.091090208, 129712.289824588 191424.709370504, 129712.276527421 191424.317527497, 129712.339930533 191423.930619495, 129712.477597379 191423.563515155, 129712.684237499 191423.230322091, 129712.951909828 191422.943844726, 129713.270327871 191422.715092225, 129713.627254999 191422.552855417, 129714.008974704 191422.463368972, 129714.400817711 191422.450071804)), ((129704.728467797 191417.0774827, 129705.118648441 191417.115912139, 129705.493834662 191417.229723635, 129705.839608263 191417.414543475, 129706.14268136 191417.663269137, 129706.391407022 191417.966342234, 129706.576226862 191418.312115835, 129706.690038358 191418.687302056, 129706.728467797 191419.0774827, 129706.690038358 191419.467663344, 129706.576226862 191419.842849565, 129706.391407022 191420.188623166, 129706.14268136 191420.491696262, 129705.839608263 191420.740421924, 129705.493834662 191420.925241765, 129705.118648441 191421.039053261, 129704.728467797 191421.0774827, 129704.338287153 191421.039053261, 129703.963100932 191420.925241765, 129703.617327331 191420.740421924, 129703.314254235 191420.491696262, 129703.065528573 191420.188623166, 129702.880708732 191419.842849565, 129702.766897236 191419.467663344, 129702.728467797 191419.0774827, 129702.766897236 191418.687302056, 129702.880708732 191418.312115835, 129703.065528573 191417.966342234, 129703.314254235 191417.663269137, 129703.617327331 191417.414543475, 129703.963100932 191417.229723635, 129704.338287153 191417.115912139, 129704.728467797 191417.0774827)))"^^ . -_:B32172f5de00abe13b33b52aed59506ea . -_:B41fce9164b7343a8095a9bef933449b6 " POLYGON ((227072.097974918 164093.018884782, 227072.479592909 164091.055630415, 227090.148882211 164094.490192332, 227089.76726422 164096.453446699, 227072.097974918 164093.018884782))"^^ . -_:B41fce9164b7343a8095a9bef933449b6 . -_:Be1a4a91cdf362f795f68512a47c30f43 "Gemeente Brasschaat"^^ . -_:Be1a4a91cdf362f795f68512a47c30f43 . -_:Be1a4a91cdf362f795f68512a47c30f43 . - . - _:Beaf8dace6a39b48f9dd90fd9e4445c86 . - . -_:B602e07c828ea80361f7393412b16af96 "Gemeente Brasschaat"^^ . -_:B602e07c828ea80361f7393412b16af96 . -_:B602e07c828ea80361f7393412b16af96 . - . - . - "9197246"^^ . -_:Ba45a75e83cca14e87dccc0afef62edd7 " POLYGON ((159580.845903978 215649.243676338, 159582.769195287 215648.695086746, 159587.706501617 215666.004708527, 159585.783210308 215666.553298119, 159580.845903978 215649.243676338))"^^ . -_:Ba45a75e83cca14e87dccc0afef62edd7 . -_:B625c30f653d25993e39a92fc824b43ff "Gemeente Bredene"^^ . -_:B625c30f653d25993e39a92fc824b43ff . -_:B625c30f653d25993e39a92fc824b43ff . -_:B4a9c40f6d6c5839e85cac22f7e490d21 "Stad Tielt"^^ . -_:B4a9c40f6d6c5839e85cac22f7e490d21 . -_:B4a9c40f6d6c5839e85cac22f7e490d21 . - . - . - "9197081"^^ . -_:B734b5b55ff88cffff35c40f4d7829def "https://gipod.vlaanderen.be"@nl-BE . -_:B734b5b55ff88cffff35c40f4d7829def "10590443"^^ . -_:B734b5b55ff88cffff35c40f4d7829def . - . - . - "9197060"^^ . -_:B2e9e248b0ca99229c013eede120b8625 "Stad Hasselt"^^ . -_:B2e9e248b0ca99229c013eede120b8625 . -_:B2e9e248b0ca99229c013eede120b8625 . -_:Bdd99da2028ca7ce0976e6dcf235d0dfe "2021-01-25T05:00:00Z"^^ . -_:Bdd99da2028ca7ce0976e6dcf235d0dfe "2021-02-14T22:30:00Z"^^ . -_:Bdd99da2028ca7ce0976e6dcf235d0dfe . - . - . - "9196970"^^ . -_:Ba2d7e7129d6a0872bbe269130e1bcf1d "https://gipod.vlaanderen.be"@nl-BE . -_:Ba2d7e7129d6a0872bbe269130e1bcf1d "10590543"^^ . -_:Ba2d7e7129d6a0872bbe269130e1bcf1d . - "2021-01-06T18:04:21.507Z"^^ . - . - . - . - "2021-01-06T15:54:36.83Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B926dd8f966712dffa78cb69a6a549bae . - _:B5862e6ef8ee611411ab0f51c0e7db0c6 . - "2021-01-06T15:51:00.32Z"^^ . - _:Bfa3ad8539cc2af07b3ad054b1bd79d3a . - "9160 Lokeren, Eksaarde-dorp 71-71A: Werfwagen / Verlenging"^^ . - _:B9806f746bd99d8384391f355586c1314 . - "10590355"^^ . - _:Bb9de4f89049549fc1b2eb5cf4ba5e71a . - . - _:Bfd9cf0e817ceec84c500abbe872af4c8 . - _:B0e8cae372528e2c29871ce7c636e4514 . - "Verhuiswagen Inclusief verhuislift.\nOns appartement is gelegen aan de hoek van het gebouw, met langs ene kant het Margarethaplein en de andere kant het Pieter de Somerplein.\nIngetekende zone op de kaart betreft twee delen. Normaalgezien zal zone aan de kant van het Margarethaplein volstaan maar moge"^^ . - . - "2021-01-06T14:34:16.29Z"^^ . - _:Ba7a127d0251a5c6f24c9f2e3f2210d61 . - . - . - _:Bdbd8dbb74f77acbdcefc50e5af39080b . - . - "2021-01-06T18:04:49Z"^^ . - "10590429"^^ . - _:Bb13984d1fa35f1bc19bd5ce86f66b428 . - "2021-01-06T14:34:16.29Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . -_:Bf9cf6564d762a860cd71e47118c406db "Stad Ninove"^^ . -_:Bf9cf6564d762a860cd71e47118c406db . -_:Bf9cf6564d762a860cd71e47118c406db . - . - . - "9197019"^^ . - . - _:B42f7795bf143926e2e499dd8e81068c7 . - . -_:B79fddffe33871c86585cabd79de3583c "Stad Aalst"^^ . -_:B79fddffe33871c86585cabd79de3583c . -_:B79fddffe33871c86585cabd79de3583c . -_:Be3f9fd636e29e599d0dc48a50208a65b "https://gipod.vlaanderen.be"@nl-BE . -_:Be3f9fd636e29e599d0dc48a50208a65b "10590451"^^ . -_:Be3f9fd636e29e599d0dc48a50208a65b . - . - . - "9196929"^^ . - . - . - "9197086"^^ . -_:B92e1a072781d87f2d4bfab96810b5263 "Gemeente Heist-op-den-Berg"^^ . -_:B92e1a072781d87f2d4bfab96810b5263 . -_:B92e1a072781d87f2d4bfab96810b5263 . - . - . - "9197161"^^ . - _:Bbabb6fed4365b222ee59aa71dcd35eeb . - . - "9160 Lokeren, Eksaarde-dorp 73: Werfwagen / Verlenging"^^ . - "10590361"^^ . - _:B0059e9cc4ecea97c93f6133d4b6c7f08 . - . - _:B58f91138101cd967ced7b9503f1c467e . - _:Bf0fb518404fcabb03588da280c8b04e7 . - "2021-01-06T15:47:31.637Z"^^ . - "2021-01-06T15:42:58.527Z"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B05771377074bb3ba81d154182dfb6ee8 . - . - "2021-01-06T18:04:25.527Z"^^ . - "2021-01-06T18:05:34.327Z"^^ . - "2021-01-06T13:10:17.077Z"^^ . - _:Bc0ae83908b98817795f241010067b11b . - . - . - _:Be1e221795f65ef118d1a9c054c667f4d . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B30cde8411d882f9deb8846c954b1239a . - "2021-01-06T13:03:21.283Z"^^ . - . - _:B6a8e8fa6e3118abca39e50b57f337073 . - _:Bf93ec36bf8f839dbbafe4139b7fd8ec8 . - "10590554"^^ . - "Wegeniswerken"^^ . - . -_:Bc07e00f3580b097f29436861469b6bad "2021-01-11T06:00:00Z"^^ . -_:Bc07e00f3580b097f29436861469b6bad "2021-01-22T18:00:00Z"^^ . -_:Bc07e00f3580b097f29436861469b6bad . - . - _:B1140511aaaf7b5d6467c4a41436c89d8 . - . -_:Bb18936d52f051770969df408df8cb63e "Politiezone Leuven"^^ . -_:Bb18936d52f051770969df408df8cb63e . -_:Bb18936d52f051770969df408df8cb63e . -_:Bac9dabc3586ef6d20cc103d4a1dbe1e6 "Gemeente Drogenbos"^^ . -_:Bac9dabc3586ef6d20cc103d4a1dbe1e6 . -_:Bac9dabc3586ef6d20cc103d4a1dbe1e6 . - "Vrachtwagen/werfwagen"^^ . - . - "2021-01-06T16:58:14.16Z"^^ . - _:B183b69d54c69f07163e8e39193104835 . - . - "2021-01-06T18:04:12.58Z"^^ . - _:B64bbd77b487cdb1c6fb9db9330e902f3 . - . - "10590331"^^ . - _:Bf63aed11e551b2ac3b50e101784329bc . - . - _:Bb18936d52f051770969df408df8cb63e . - _:Befa179c78c4b4091d1fd884a8a2ec448 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T16:58:14.16Z"^^ . -_:Bc8049be4948328970f111ce187111d3f "https://gipod.vlaanderen.be"@nl-BE . -_:Bc8049be4948328970f111ce187111d3f "10590487"^^ . -_:Bc8049be4948328970f111ce187111d3f . -_:Bef75ae3d5da79ca3c5ed3eed203e3d27 "Stad Ronse"^^ . -_:Bef75ae3d5da79ca3c5ed3eed203e3d27 . -_:Bef75ae3d5da79ca3c5ed3eed203e3d27 . -_:B3a033a5e9bba7ce83aad2bb0189aa427 "https://gipod.vlaanderen.be"@nl-BE . -_:B3a033a5e9bba7ce83aad2bb0189aa427 "10590463"^^ . -_:B3a033a5e9bba7ce83aad2bb0189aa427 . -_:B2822f1393c4b45196ea1f0591e8924ef "Politiezone Leuven"^^ . -_:B2822f1393c4b45196ea1f0591e8924ef . -_:B2822f1393c4b45196ea1f0591e8924ef . -_:Bbb219cc7d3ad42689784723f5bb230db "2021-01-13T06:00:00Z"^^ . -_:Bbb219cc7d3ad42689784723f5bb230db "2021-01-13T15:00:00Z"^^ . -_:Bbb219cc7d3ad42689784723f5bb230db . -_:B52b9cb23789072d466fb172f96660dd6 "Stad Lokeren"^^ . -_:B52b9cb23789072d466fb172f96660dd6 . -_:B52b9cb23789072d466fb172f96660dd6 . -_:B89e48d84e85dd0301e9cddda0951eff5 "https://gipod.vlaanderen.be"@nl-BE . -_:B89e48d84e85dd0301e9cddda0951eff5 "10590337"^^ . -_:B89e48d84e85dd0301e9cddda0951eff5 . - . - _:Bf98377530dc27f02f2295ef190ff5c77 . - . -_:B61602350dcb48a32de1184ec71999c56 "Gemeente Willebroek"^^ . -_:B61602350dcb48a32de1184ec71999c56 . -_:B61602350dcb48a32de1184ec71999c56 . - "Vermindering van rijstroken"@nl-BE . - . - . - "9197220"^^ . - . - . - . - . - _:Be01be9360e4dfb033470d29771f94a26 . - . -_:B3ecb70a472774fdffdf568dc8fcfc945 " POLYGON ((126976.20760756 181030.537122162, 126995.146348843 181035.756460311, 126995.891968578 181033.072229263, 126976.953227296 181027.703767167, 126976.20760756 181030.537122162))"^^ . -_:B3ecb70a472774fdffdf568dc8fcfc945 . - . - . - _:B0f30b09e4cce5676dba1ff52299e567c . - . - . - _:Be47de5c37f0ff7266204b843b4f77a37 . - _:B4964418fc655cbdffd242f3b419513a0 . - "10590590"^^ . - . - _:B82e436e7b145dcb0b36242ba53e43006 . - . - "9120 Beveren, Kriekelaarstraat 66: Wegenwerken (4-3b)"^^ . - "2021-01-06T12:43:35.957Z"^^ . - _:B432ad1c603c1a0f3e0211ccf0804d74e . - _:B7d9e162f9de34013af6bf8be48622d00 . - . - "2021-01-06T18:05:42.943Z"^^ . - "2021-01-06T12:43:35.957Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - "9197001"^^ . -_:Bcb4b8b535b3219132806600b33b1c218 "2021-01-12T06:00:00Z"^^ . -_:Bcb4b8b535b3219132806600b33b1c218 "2021-01-12T16:00:00Z"^^ . -_:Bcb4b8b535b3219132806600b33b1c218 . -_:B3aa48cb3ad4b143a2091b2ca3bef9c3e "Stad Turnhout"^^ . -_:B3aa48cb3ad4b143a2091b2ca3bef9c3e . -_:B3aa48cb3ad4b143a2091b2ca3bef9c3e . -_:Ba0e97f72420be8d0e6062006fd8fc687 " MULTIPOLYGON (((150619.161664406 189143.871286085, 150619.4599123 189145.138839636, 150615.508127701 189146.108145292, 150615.135317834 189144.989715689, 150619.161664406 189143.871286085)), ((150615.135317834 189132.537866105, 150615.880937569 189133.730857682, 150611.481781129 189134.998411233, 150610.959847315 189133.730857682, 150615.135317834 189132.537866105)))"^^ . -_:Ba0e97f72420be8d0e6062006fd8fc687 . -_:B9cbdb1cf3440ec0d4eab55b2d5a66324 "Stad Mechelen"^^ . -_:B9cbdb1cf3440ec0d4eab55b2d5a66324 . -_:B9cbdb1cf3440ec0d4eab55b2d5a66324 . -_:Bdfad8bc5392978b7a06327f830efc645 "Gemeente Brasschaat"^^ . -_:Bdfad8bc5392978b7a06327f830efc645 . -_:Bdfad8bc5392978b7a06327f830efc645 . -_:B0c39bad0f320c91f2380420e649403f1 "2021-01-18T00:00:00Z"^^ . -_:B0c39bad0f320c91f2380420e649403f1 "2021-01-31T00:00:00Z"^^ . -_:B0c39bad0f320c91f2380420e649403f1 . -_:B297d962fd42adf93ef0209dd61d76917 " POLYGON ((141057.407918895 198438.954557141, 141058.059055204 198440.845594292, 141052.385943751 198442.799003218, 141051.734807442 198440.907966067, 141057.407918895 198438.954557141))"^^ . -_:B297d962fd42adf93ef0209dd61d76917 . -_:Bee2da5e565021c9bb2839050aafd6309 "2021-01-08T06:00:00Z"^^ . -_:Bee2da5e565021c9bb2839050aafd6309 "2021-01-08T15:00:00Z"^^ . -_:Bee2da5e565021c9bb2839050aafd6309 . -_:Bff1a408e4952ed83b56cff9782d36357 "2021-01-22T23:00:00Z"^^ . -_:Bff1a408e4952ed83b56cff9782d36357 "2021-01-23T22:30:00Z"^^ . -_:Bff1a408e4952ed83b56cff9782d36357 . -_:Be542303d24bde73be54033980395c3b0 "Politiezone Brugge"^^ . -_:Be542303d24bde73be54033980395c3b0 . -_:Be542303d24bde73be54033980395c3b0 . -_:Bfdbff4d375ad7c6bf22501fc79b849f5 "2021-01-11T05:00:00Z"^^ . -_:Bfdbff4d375ad7c6bf22501fc79b849f5 "2021-01-22T19:00:00Z"^^ . -_:Bfdbff4d375ad7c6bf22501fc79b849f5 . -_:B0e35bf97d997a2a3aea79f5de267fd44 "https://gipod.vlaanderen.be"@nl-BE . -_:B0e35bf97d997a2a3aea79f5de267fd44 "10590503"^^ . -_:B0e35bf97d997a2a3aea79f5de267fd44 . - . - . - "9196924"^^ . -_:Ba4b494920b176bd2dbec3f2e2ea55e48 "Gemeente Schoten"^^ . -_:Ba4b494920b176bd2dbec3f2e2ea55e48 . -_:Ba4b494920b176bd2dbec3f2e2ea55e48 . -_:B2ebf501e7668b39df0972a9e92001ae1 "Gemeente Deerlijk"^^ . -_:B2ebf501e7668b39df0972a9e92001ae1 . -_:B2ebf501e7668b39df0972a9e92001ae1 . -_:B58210a9e828a4af42d5c001669f25991 "2021-01-26T07:00:00Z"^^ . -_:B58210a9e828a4af42d5c001669f25991 "2021-01-26T15:00:00Z"^^ . -_:B58210a9e828a4af42d5c001669f25991 . - . - . - "9197321"^^ . -_:B9a8d7b4d9d224982671e3eb860f54824 "Stad Kortrijk"^^ . -_:B9a8d7b4d9d224982671e3eb860f54824 . -_:B9a8d7b4d9d224982671e3eb860f54824 . -_:Bf94f4cbc04d3160ee698b8eeee6a42a3 "2021-01-25T06:00:00Z"^^ . -_:Bf94f4cbc04d3160ee698b8eeee6a42a3 "2021-01-27T15:00:00Z"^^ . -_:Bf94f4cbc04d3160ee698b8eeee6a42a3 . - . - . - "9196937"^^ . -_:Bfe1ab231461adccbf4470720a0efbb7e "https://gipod.vlaanderen.be"@nl-BE . -_:Bfe1ab231461adccbf4470720a0efbb7e "10590474"^^ . -_:Bfe1ab231461adccbf4470720a0efbb7e . -_:B6cd0ff4e281f1a67ab7342452c4b0327 "Gemeente Koksijde"^^ . -_:B6cd0ff4e281f1a67ab7342452c4b0327 . -_:B6cd0ff4e281f1a67ab7342452c4b0327 . -_:B334f2851ade92838f1e0ed5e61da276e "Gemeente Sint-Lievens-Houtem"^^ . -_:B334f2851ade92838f1e0ed5e61da276e . -_:B334f2851ade92838f1e0ed5e61da276e . -_:Bf42bc4ea28e38acc088cc65fedcc9001 " POLYGON ((127653.900764897 181145.553150116, 127655.775992094 181146.248508268, 127649.517768725 181163.12555304, 127647.642541528 181162.430194888, 127653.900764897 181145.553150116))"^^ . -_:Bf42bc4ea28e38acc088cc65fedcc9001 . -_:B5be6e2c6855c7513994e8afc3df71b2d "Gemeente Brasschaat"^^ . -_:B5be6e2c6855c7513994e8afc3df71b2d . -_:B5be6e2c6855c7513994e8afc3df71b2d . - . - . - "9197182"^^ . - "Geen doorgang voor voetgangers"@nl-BE . - . - . - "9197339"^^ . -_:Bb61a2744b697518282e0e9b126fd865a "https://gipod.vlaanderen.be"@nl-BE . -_:Bb61a2744b697518282e0e9b126fd865a "10590368"^^ . -_:Bb61a2744b697518282e0e9b126fd865a . -_:Bf4d73e4cc3def3229bb5e18f90d844c4 "Politiezone Leuven"^^ . -_:Bf4d73e4cc3def3229bb5e18f90d844c4 . -_:Bf4d73e4cc3def3229bb5e18f90d844c4 . -_:B2d7d3e4fd598d578d6fc732e08a5b12d "https://gipod.vlaanderen.be"@nl-BE . -_:B2d7d3e4fd598d578d6fc732e08a5b12d "10590371"^^ . -_:B2d7d3e4fd598d578d6fc732e08a5b12d . - . - "10590580"^^ . - . - "8450 Bredene, Draversstraat 2: Nutswerken"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:05:40.533Z"^^ . - _:B50b510735d803f92b766f01d736e0105 . - _:B625c30f653d25993e39a92fc824b43ff . - _:Bfd77cb3713f87c5f3ae23cf21654e512 . - "2021-01-06T12:50:59.093Z"^^ . - . - _:B931ff6808c325f325acb22c10c673790 . - "2021-01-06T12:54:08.17Z"^^ . - _:Ba560afb499c4da43e169fa3dc33d6465 . - . -_:B4a9bfc9ef223533d100980ec3e0a1d87 " MULTIPOLYGON (((173462.86308348898 174383.7456376301, 173464.55729799747 174384.78870507982, 173456.6715256715 174396.3313643122, 173454.60021010097 174395.1924744649, 173462.86308348898 174383.7456376301)), ((173466.19122802094 174378.25393868051, 173473.82303183014 174381.2063556183, 173472.4940586405 174382.89473517798, 173465.23639580293 174380.69705450814, 173465.2385136074 174380.22640788835, 173466.19122802094 174378.25393868051)))"^^ . -_:B4a9bfc9ef223533d100980ec3e0a1d87 . -_:B93c00c7af86cc918ed517e9f69f3a876 "Politiezone Leuven"^^ . -_:B93c00c7af86cc918ed517e9f69f3a876 . -_:B93c00c7af86cc918ed517e9f69f3a876 . -_:B6f0651555d9f314faad60457f42be97e "Gemeente Hamme"^^ . -_:B6f0651555d9f314faad60457f42be97e . -_:B6f0651555d9f314faad60457f42be97e . - . - . - . - . - _:B91b7d25689167ed9e776a0384cd8e81c . - . -_:Bb59ff7dbbc7f6bbd520caa9a1e448d7b "2021-01-31T23:00:00Z"^^ . -_:Bb59ff7dbbc7f6bbd520caa9a1e448d7b "2021-02-19T22:30:00Z"^^ . -_:Bb59ff7dbbc7f6bbd520caa9a1e448d7b . - . - _:B9c0090a5a5e5dc02d4377c2de46b2ae9 . - . -_:B98955608a81831bc9dbbb75075886221 "Gemeente Hemiksem"^^ . -_:B98955608a81831bc9dbbb75075886221 . -_:B98955608a81831bc9dbbb75075886221 . -_:B19437d4952a0913cee4a441cd474b1bd "Gemeente Zonhoven"^^ . -_:B19437d4952a0913cee4a441cd474b1bd . -_:B19437d4952a0913cee4a441cd474b1bd . -_:B1ea587aa44c902705429318bbf1fce0c "Stad Ronse"^^ . -_:B1ea587aa44c902705429318bbf1fce0c . -_:B1ea587aa44c902705429318bbf1fce0c . - "Versmalde rijstroken"@nl-BE . -_:B36dc3725ee2232b55309a54effab7884 "2021-01-10T23:00:00Z"^^ . -_:B36dc3725ee2232b55309a54effab7884 "2021-01-12T22:30:00Z"^^ . -_:B36dc3725ee2232b55309a54effab7884 . -_:B8652f81a1c7a30f0845ed298b024ea5f "https://gipod.vlaanderen.be"@nl-BE . -_:B8652f81a1c7a30f0845ed298b024ea5f "10590413"^^ . -_:B8652f81a1c7a30f0845ed298b024ea5f . - . - _:B246e9e71720dc4411f25bff5f8f79cab . - . - . - . - "9196932"^^ . - . - _:B06902b2befaecc46610a411650bb8088 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - . - "2021-01-06T18:05:22.14Z"^^ . - "10590515"^^ . - _:B1bad81fefe27528fe3433acbbaeb79c0 . - "9900 Eeklo, Moeie 29: nutswerken"^^ . - _:B791cc74711b7e0ea61f69eb69f5c884b . - _:B837362e5b8a0fac9777cc89426f4d911 . - _:B1982723485d8d2a04dd04a102810e2aa . - "2021-01-06T13:34:42.187Z"^^ . - "2021-01-06T13:24:38.227Z"^^ . -_:B26c4301a91aad795fded7c2e6ba1cf3b "Gemeente Ingelmunster"^^ . -_:B26c4301a91aad795fded7c2e6ba1cf3b . -_:B26c4301a91aad795fded7c2e6ba1cf3b . - . - . - "9197342"^^ . -_:B75cfecdee28a4cc2d8bc6936098785ff "Gemeente Gavere"^^ . -_:B75cfecdee28a4cc2d8bc6936098785ff . -_:B75cfecdee28a4cc2d8bc6936098785ff . -_:B3811edd26495802358252b248945da0c "Stad Ronse"^^ . -_:B3811edd26495802358252b248945da0c . -_:B3811edd26495802358252b248945da0c . - . - _:Bc3096bc5d182cd3bf6633ebe28fc277b . - . - . - . - "9196958"^^ . -_:Bf0b666079025bb93fe6b92673ce76dbe "Gemeente Middelkerke"^^ . -_:Bf0b666079025bb93fe6b92673ce76dbe . -_:Bf0b666079025bb93fe6b92673ce76dbe . - . - . - "9197102"^^ . -_:Ba0a975f9b52748ce7a562386ff13418a "2021-01-08T00:00:00Z"^^ . -_:Ba0a975f9b52748ce7a562386ff13418a "2021-01-11T00:00:00Z"^^ . -_:Ba0a975f9b52748ce7a562386ff13418a . -_:Bce5b425eac609233920d77c1d61152ec "https://gipod.vlaanderen.be"@nl-BE . -_:Bce5b425eac609233920d77c1d61152ec "10590437"^^ . -_:Bce5b425eac609233920d77c1d61152ec . -_:B001ca1373f2a690417871225cdb2a99c "Politiezone Brugge"^^ . -_:B001ca1373f2a690417871225cdb2a99c . -_:B001ca1373f2a690417871225cdb2a99c . -_:B41bb1d1181d0d7e47f794941b3da5e88 " POLYGON ((172879.89196024116 174633.39205736946, 172876.7737908745 174634.225515672, 172867.05127368515 174634.5593749052, 172863.22554054242 174559.9937779978, 172860.95797614855 174560.5486036148, 172861.17025623692 174555.1842380762, 172858.99830666033 174555.4571001483, 172859.06214989346 174562.42285089102, 172861.98912571275 174562.15329958312, 172865.43777835515 174636.62308462057, 172877.33220846043 174636.01637152303, 172880.35599952767 174635.18249970395, 172879.89196024116 174633.39205736946))"^^ . -_:B41bb1d1181d0d7e47f794941b3da5e88 . -_:Bbeca0dae26a4816e2b26179c5647c4f3 " POLYGON ((28505.750828463868 202445.60037976762, 28504.185027019234 202443.363520561, 28511.566662401085 202437.77137254443, 28513.430711739937 202440.38104161882, 28505.750828463868 202445.60037976762))"^^ . -_:Bbeca0dae26a4816e2b26179c5647c4f3 . -_:B2428ca908693b2a06a36e020ac13b8cd "2021-01-09T06:00:00Z"^^ . -_:B2428ca908693b2a06a36e020ac13b8cd "2021-01-09T18:00:00Z"^^ . -_:B2428ca908693b2a06a36e020ac13b8cd . -_:B9da030f9f5d2538c86b4d8043903a27f "Politiezone Brugge"^^ . -_:B9da030f9f5d2538c86b4d8043903a27f . -_:B9da030f9f5d2538c86b4d8043903a27f . - "10590394"^^ . - "2021-01-06T18:04:38.297Z"^^ . - _:Bb59ff7dbbc7f6bbd520caa9a1e448d7b . - _:B4a1cac4c4fd02eab99d35d70d20f3d48 . - . - . - _:B1856c7bc97848261a248b5b4c7a8dcee . - . - "2021-01-06T14:56:10.633Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B03b5b001c87f4911c5da18981c3c52f2 . - "2021-01-06T15:14:52.677Z"^^ . - . - _:Bf31a9f0ea5369bf2a27df78fe880140f . - "Kraan Ruiming van puin van riolen, bermen en grachten in naam van Stad Kortrijk."^^ . - _:B938041365d5912f5f7320867f8e95fcf . - "2021-01-06T16:14:09.39Z"^^ . - "2021-01-06T18:04:18.197Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bf7dfda4f642fe6ab8fb249d2cfe7cf6b . - "10590347"^^ . - "2021-01-06T16:14:09.39Z"^^ . - "Verhuiswagen Verhuiswagen\nVerhuis lift"^^ . - _:B5b6aad1a73e784714a22fe23b1c40521 . - _:B787b37ddbce483ccbc034b28899e20f3 . - _:B4a8d014f90cbf03704da7be6dec1fe33 . - . - . - . - . - . - _:Be66e17cf4c25f17bf8a94960a945b012 . - . -_:Bbd5c442f8be4948fd93f1e14300a9724 "Stad Mechelen"^^ . -_:Bbd5c442f8be4948fd93f1e14300a9724 . -_:Bbd5c442f8be4948fd93f1e14300a9724 . -_:B091813a480ec604ff0bb81fb3821d265 "https://gipod.vlaanderen.be"@nl-BE . -_:B091813a480ec604ff0bb81fb3821d265 "10590330"^^ . -_:B091813a480ec604ff0bb81fb3821d265 . - . - . - "9197107"^^ . -_:B4a5b84a05510f5e6e1fbbf03ccece0b6 " MULTIPOLYGON (((93316.0097874294 208436.848029878, 93316.2046132163 208436.869763537, 93316.3914554539 208436.929088215, 93316.5631338996 208437.023724099, 93316.7130510471 208437.150034384, 93316.8354456645 208437.303165037, 93316.9256141953 208437.477231332, 93316.9800915134 208437.665544, 93316.996784086 208437.860866291, 93316.9750504269 208438.055692078, 93316.9157257485 208438.242534316, 93316.8210898649 208438.414212761, 93316.69477958 208438.564129909, 93316.5416489272 208438.686524526, 93316.3675826316 208438.776693057, 93316.1792699634 208438.831170375, 93198.8187235893 208460.603266653, 93198.6234012987 208460.619959225, 93198.4285755118 208460.598225566, 93198.2417332742 208460.538900888, 93198.0700548285 208460.444265004, 93197.920137681 208460.317954719, 93197.7977430636 208460.164824067, 93197.7075745328 208459.990757771, 93197.6530972148 208459.802445103, 93197.6364046421 208459.607122812, 93197.6581383012 208459.412297025, 93197.7174629796 208459.225454788, 93197.8120988632 208459.053776342, 93197.9384091481 208458.903859195, 93198.0915398009 208458.781464577, 93198.2656060965 208458.691296046, 93198.4539187647 208458.636818728, 93315.8144651388 208436.864722451, 93316.0097874294 208436.848029878)), ((93384.3064675867 208424.172469579, 93384.5013383238 208424.193796441, 93384.6883040101 208424.252730907, 93384.8601796591 208424.34700816, 93385.010360186 208424.473005178, 93385.1330742373 208424.625879966, 93385.223605981 208424.799757632, 93385.2784763328 208424.987956154, 93385.295576656 208425.183243169, 93385.2742497946 208425.378113906, 93385.215315328 208425.565079592, 93385.1210380748 208425.736955241, 93384.9950410568 208425.887135768, 93384.8421662688 208426.009849819, 93384.6682886033 208426.100381563, 93384.4800900813 208426.155251915, 93331.2428409637 208436.146556371, 93331.0475539489 208436.163656694, 93330.8526832118 208436.142329833, 93330.6657175255 208436.083395366, 93330.4938418765 208435.989118113, 93330.3436613497 208435.863121095, 93330.2209472983 208435.710246307, 93330.1304155546 208435.536368642, 93330.0755452028 208435.34817012, 93330.0584448797 208435.152883105, 93330.079771741 208434.958012368, 93330.1387062076 208434.771046681, 93330.2329834609 208434.599171032, 93330.3589804788 208434.448990506, 93330.5118552668 208434.326276454, 93330.6857329323 208434.23574471, 93330.8739314543 208434.180874359, 93384.111180572 208424.189569902, 93384.3064675867 208424.172469579)), ((93449.2401649016 208398.525797627, 93449.4361398835 208398.530619003, 93449.6274086572 208398.57358056, 93449.8066208711 208398.653031309, 93449.9668895002 208398.765918003, 93450.1020555111 208398.90790247, 93450.2069245497 208399.073528325, 93450.2774665577 208399.25643066, 93450.3109706452 208399.449580642, 93450.3061492691 208399.645555624, 93450.263187712 208399.836824397, 93450.1837369626 208400.016036611, 93450.0708502685 208400.17630524, 93449.9288658021 208400.311471251, 93449.7632399468 208400.41634029, 93449.5803376113 208400.486882298, 93411.851978993 208410.925558595, 93411.6588290116 208410.959062683, 93411.4628540297 208410.954241307, 93411.271585256 208410.91127975, 93411.0923730421 208410.831829, 93410.932104413 208410.718942306, 93410.7969384021 208410.57695784, 93410.6920693635 208410.411331985, 93410.6215273555 208410.228429649, 93410.5880232679 208410.035279668, 93410.5928446441 208409.839304686, 93410.6358062011 208409.648035912, 93410.7152569506 208409.468823698, 93410.8281436447 208409.308555069, 93410.9701281111 208409.173389058, 93411.1357539664 208409.06852002, 93411.3186563018 208408.997978012, 93449.0470149202 208398.559301714, 93449.2401649016 208398.525797627)), ((93481.4433998482 208398.228133993, 93481.6394056799 208398.231473624, 93481.8309937848 208398.272987926, 93482.0108015393 208398.351081528, 93482.1719190325 208398.462753335, 93482.3081546092 208398.603711864, 93482.4142728129 208398.768540157, 93482.4861955803 208398.950903955, 93482.5211589598 208399.143795119, 93482.5178193285 208399.339800951, 93482.4763050264 208399.531389055, 93482.398211425 208399.71119681, 93482.2865396174 208399.872314303, 93482.1455810887 208400.00854988, 93481.9807527961 208400.114668084, 93481.7983889984 208400.186590851, 93409.0259028096 208420.914819499, 93408.8330116453 208420.949782879, 93408.6370058136 208420.946443247, 93408.4454177087 208420.904928945, 93408.2656099542 208420.826835344, 93408.104492461 208420.715163536, 93407.9682568843 208420.574205007, 93407.8621386806 208420.409376715, 93407.7902159132 208420.227012917, 93407.7552525336 208420.034121753, 93407.758592165 208419.838115921, 93407.800106467 208419.646527816, 93407.8782000685 208419.466720062, 93407.989871876 208419.305602568, 93408.1308304047 208419.169366992, 93408.2956586974 208419.063248788, 93408.4780224951 208418.991326021, 93481.2505086839 208398.263097373, 93481.4433998482 208398.228133993)))"^^ . -_:B4a5b84a05510f5e6e1fbbf03ccece0b6 . -_:Bdd06cc526f9496541eb7d2167d6256be "Gemeente Meise"^^ . -_:Bdd06cc526f9496541eb7d2167d6256be . -_:Bdd06cc526f9496541eb7d2167d6256be . -_:B1eefd8d0c8122b4ae3b817336f347bf6 "2021-01-16T09:00:00Z"^^ . -_:B1eefd8d0c8122b4ae3b817336f347bf6 "2021-01-16T12:00:00Z"^^ . -_:B1eefd8d0c8122b4ae3b817336f347bf6 . -_:Bcc079400f4dac274b859d6f5e5f6cf71 "Politiezone Brugge"^^ . -_:Bcc079400f4dac274b859d6f5e5f6cf71 . -_:Bcc079400f4dac274b859d6f5e5f6cf71 . -_:B4cd5a034e737f36536edc23605a41891 "Stad Lokeren"^^ . -_:B4cd5a034e737f36536edc23605a41891 . -_:B4cd5a034e737f36536edc23605a41891 . -_:Bb946b430f5b074e786fb21c812fb69c5 "Stad Kortrijk"^^ . -_:Bb946b430f5b074e786fb21c812fb69c5 . -_:Bb946b430f5b074e786fb21c812fb69c5 . -_:B63927cf530abd8cf7baa444faa10899c "https://gipod.vlaanderen.be"@nl-BE . -_:B63927cf530abd8cf7baa444faa10899c "10590541"^^ . -_:B63927cf530abd8cf7baa444faa10899c . - . - . - "9197270"^^ . - _:B8cd71a2f253e285f4042ca9301922791 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B342cb15e40269689fd4d27745bfe821a . - "2021-01-06T16:34:52.833Z"^^ . - _:Bf61c7ac2f42d99f9de3157c5f07d563e . - "10590478"^^ . - _:B0582bf0ca4746dc7699116ceab1b4b30 . - . - _:B86e9502ec4a0699ba709d2df67f21898 . - "Container"^^ . - "2021-01-06T13:54:02.82Z"^^ . - . - "2021-01-06T18:05:05.69Z"^^ . - . - . - _:Bb725f1fd316a5bb77eee15276bc0ef08 . - . -_:Be71420d1950409879598226239777998 "https://gipod.vlaanderen.be"@nl-BE . -_:Be71420d1950409879598226239777998 "10590560"^^ . -_:Be71420d1950409879598226239777998 . -_:Bbabb6fed4365b222ee59aa71dcd35eeb "Stad Lokeren"^^ . -_:Bbabb6fed4365b222ee59aa71dcd35eeb . -_:Bbabb6fed4365b222ee59aa71dcd35eeb . -_:Bbd28b54854cecdf22750b6f12c599f61 " POLYGON ((174319.32381874585 174621.95688167494, 174322.8140324857 174622.34966758918, 174323.3065540917 174617.92798984703, 174319.90895924706 174617.91214390565, 174319.32381874585 174621.95688167494))"^^ . -_:Bbd28b54854cecdf22750b6f12c599f61 . - _:Bea65a3690ae1001172d9ce48a82f44df . - _:Ba4b494920b176bd2dbec3f2e2ea55e48 . - . - _:B06382ca87ed176738ec04d1c2dca4084 . - _:Be68f336d2fc2dc59343208b96565f4c5 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:34.27Z"^^ . - . - . - "2021-01-06T15:08:51Z"^^ . - "10590382"^^ . - "2900 Schoten, Ridder Walter Van Havrelaan 22: Parkeerverbod laden en lossen"^^ . - "2021-01-06T15:05:48.41Z"^^ . - _:Bd792879a900fa0f16f83b2d4a0a157f2 . - . -_:B3b3edc706c6c72ca705caff67b48a3c6 "https://gipod.vlaanderen.be"@nl-BE . -_:B3b3edc706c6c72ca705caff67b48a3c6 "10590388"^^ . -_:B3b3edc706c6c72ca705caff67b48a3c6 . -_:Bd44689c3f385c3f6e838a65679effe5c "Politiezone Brugge"^^ . -_:Bd44689c3f385c3f6e838a65679effe5c . -_:Bd44689c3f385c3f6e838a65679effe5c . -_:Bd3a0e17a8a715193cc59257789bcd6d3 "Politiezone Leuven"^^ . -_:Bd3a0e17a8a715193cc59257789bcd6d3 . -_:Bd3a0e17a8a715193cc59257789bcd6d3 . - "2021-01-06T14:17:52.173Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:04:55.343Z"^^ . - _:Bbd5c442f8be4948fd93f1e14300a9724 . - "10590450"^^ . - . - _:B535b4f72e8fb8a9d05ef843e1bc26c12 . - "2021-01-06T14:21:05.413Z"^^ . - . - . - . - _:B45bb39b56303c4a7006860ac979d1a29 . - _:B610c23989f0d2f272ff6b3ac0fef5320 . - "2800 Mechelen, Hombeeksesteenweg 88: Verhuis"^^ . - _:Bff8544336f6c9d1dbe97b56c8e25b4a5 . -_:B5bd820737d23d0da033932b4a3f7ff47 " MULTIPOLYGON (((172848.74915183889 174625.72721624933, 172849.01351688177 174631.21706467215, 172849.27788134365 174636.70690737292, 172849.54224522467 174642.19674435165, 172847.0401747685 174642.31653012894, 172846.7758082658 174636.82669341192, 172846.51144118235 174631.33685097378, 172846.24707351805 174625.84700281452, 172848.74915183889 174625.72721624933)), ((172847.28946229833 174587.87101633102, 172847.40964582335 174593.36588712037, 172847.5298290701 174598.86075216252, 172847.65001203856 174604.355611464, 172847.77019472886 174609.85046502016, 172847.89037714084 174615.34531283472, 172845.38602128788 174615.39973694086, 172845.26583624413 174609.9048892539, 172845.1456509221 174604.41003582068, 172845.02546532196 174598.91517664585, 172844.90527944357 174593.42031172756, 172844.78509328677 174587.92544106673, 172847.28946229833 174587.87101633102)))"^^ . -_:B5bd820737d23d0da033932b4a3f7ff47 . -_:Bd406762db6a01711c0572b38c3e5414a "2021-01-27T23:00:00Z"^^ . -_:Bd406762db6a01711c0572b38c3e5414a "2021-01-28T22:30:00Z"^^ . -_:Bd406762db6a01711c0572b38c3e5414a . -_:B0059e9cc4ecea97c93f6133d4b6c7f08 "https://gipod.vlaanderen.be"@nl-BE . -_:B0059e9cc4ecea97c93f6133d4b6c7f08 "10590361"^^ . -_:B0059e9cc4ecea97c93f6133d4b6c7f08 . -_:B3f5c987ded226ca5fc056c70c560e0bd " POLYGON ((200408.30940818 195553.688043253, 200414.672023856 195553.489205256, 200414.274366065 195538.775648542, 200406.122263024 195540.962793699, 200408.30940818 195553.688043253))"^^ . -_:B3f5c987ded226ca5fc056c70c560e0bd . -_:Bd5f357a9cc8ba09c2806ced075cc785d "Gemeente Koksijde"^^ . -_:Bd5f357a9cc8ba09c2806ced075cc785d . -_:Bd5f357a9cc8ba09c2806ced075cc785d . -_:B8efb6464dde7dfaeb9df93198c359b14 " MULTIPOLYGON (((152217.34443849 199243.461860386, 152221.281314334 199243.81975894, 152223.428697352 199257.658461061, 152218.179532594 199257.777758399, 152217.34443849 199243.461860386)), ((152220.714614209 199153.480473716, 152218.805856812 199156.343646219, 152217.851405299 199154.434852415, 152220.714614209 199153.480473716)))"^^ . -_:B8efb6464dde7dfaeb9df93198c359b14 . - "2021-01-06T15:40:21.18Z"^^ . - "10590367"^^ . - . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B11dbd9d0101f134b49d9089ecbb67f0d . - _:Bfdbf060f7430fbbf84635344a36ff150 . - _:Ba5eba5d0622c35a9453df2d21e64b6e3 . - "2021-01-06T18:04:28.87Z"^^ . - . - _:B5bc3875e7421f9aeeeced16fafd37705 . - "2021-01-06T15:27:43.173Z"^^ . - _:Bf765709b93efce410c1f658d3303bc34 . - "9400 Ninove, Denderhoutembaan 236: Wegenwerken"^^ . - _:Bbbc55d6c1509ef7bcb9d406ed9139b6a . - "2021-01-06T18:05:28.123Z"^^ . - . - . - _:Bb038c2f0789f8e7807c90707694654a7 . - _:B61602350dcb48a32de1184ec71999c56 . - . - . - _:Bd85e2db30c9e7afd92b54ef8fb50d326 . - _:B7b7abffcd390d12abdce19a622606739 . - "10590534"^^ . - "2830 Willebroek, Mechelsesteenweg 183: Gemeentediensten (enkel intern gebruik)"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T13:13:44.673Z"^^ . - "2021-01-06T13:23:14.407Z"^^ . - "HinderZone"@nl-BE . -_:B9719549b387d7e8909cfd26c7f7e40ef "Gemeente Brasschaat"^^ . -_:B9719549b387d7e8909cfd26c7f7e40ef . -_:B9719549b387d7e8909cfd26c7f7e40ef . - . - _:Bb351de16d2028c7538c8c7d8c37682e4 . - . -_:Bfd9cf0e817ceec84c500abbe872af4c8 "https://gipod.vlaanderen.be"@nl-BE . -_:Bfd9cf0e817ceec84c500abbe872af4c8 "10590429"^^ . -_:Bfd9cf0e817ceec84c500abbe872af4c8 . - . - "2021-01-06T18:04:50.613Z"^^ . - "Vrachtwagen/werfwagen "^^ . - . - _:Bbfa37d5dcd48ffe704d7341f29e4e6e8 . - . - _:Bc15b22eb246d3a2112ece28f3c2d40c3 . - _:B550b1149c0afc3b163f42220194039ef . - _:B414ca49d17bb153735adff686583c531 . - _:B2f8e2bcb20d68d863962d0e519a69db6 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:31:09.467Z"^^ . - "10590435"^^ . - . - "2021-01-06T16:40:16.923Z"^^ . -_:B91b7d25689167ed9e776a0384cd8e81c " MULTIPOLYGON (((58976.61178572218 188778.35463656398, 58976.84179534677 188778.3584189554, 58977.070838937805 188778.3798144525, 58977.297569751194 188778.4186972527, 58977.520654641645 188778.4748387306, 58977.73878190138 188778.54790878223, 58977.950668972815 188778.637477766, 58978.15506998977 188778.7430190288, 58978.350783103015 188778.86391200294, 58978.53665754698 188778.9994458547, 58978.71160040608 188779.14882366406, 58978.874583040924 188779.3111671106, 58979.02464713654 188779.48552163763, 58979.16091033716 188779.67086206508, 58979.28257143433 188779.8660986173, 58979.38891507791 188780.07008333085, 58979.479315982244 188780.28161680428, 58979.47931598226 188780.28161680428, 59041.47371705213 188942.26698734172, 59056.3178283178 188979.87206921476, 59198.002287217845 189167.45431057538, 59295.92642219982 189278.36838183046, 59296.06947633771 189278.54326792265, 59296.198962752154 189278.72842434325, 59296.31414697271 189278.92280085146, 59296.41437565362 189279.1252949085, 59296.49908027962 189279.33475793138, 59296.56778039072 189279.55000180783, 59296.62008630743 189279.76980563556, 59296.655701341115 189279.99292264745, 59308.532053932475 189377.97283152625, 59411.808945798955 189482.2427704299, 59411.93475415531 189482.37785914564, 59412.05201586933 189482.52042980905, 59473.05168553361 189561.5200019972, 59489.81703810482 189583.21634061876, 59551.51401957399 189630.98174562716, 59551.708144035 189631.14564032192, 59551.887705218454 189631.32537222985, 59618.74538896488 189704.17031123716, 59663.58281619379 189741.03664029203, 59663.58281619379 189741.03664029203, 59663.69422452353 189741.13292098773, 59663.79752082599 189741.23129768946, 59663.89602397298 189741.33447342098, 59663.98951125873 189741.44221491227, 59664.077771317825 189741.55427857058, 59664.160604603065 189741.67041103114, 59664.23782383667 189741.7903497301, 59664.30925443367 189741.91382349798, 59664.374734896606 189742.04055317293, 59664.434117180695 189742.17025223182, 59664.48726702851 189742.30262743804, 59664.53406427356 189742.43737950444, 59664.57440311194 189742.57420377005, 59664.60819234157 189742.71279088888, 59664.63535556837 189742.85282752928, 59664.655831378994 189742.99399708238, 59664.66957347968 189743.1359803779, 59664.67655080092 189743.27845640582, 59664.676747567675 189743.42110304206, 59664.670163335075 189743.56359777678, 59664.65681298942 189743.70561844364, 59664.6367267145 189743.84684394806, 59664.60994992339 189743.9869549933, 59664.57654315573 189744.1256348023, 59664.53658194089 189744.26256983378, 59664.490156627195 189744.39745049138, 59664.437372177636 189744.52997182336, 59664.37834793258 189744.65983421222, 59664.313217339964 189744.78674405205, 59664.24212765355 189744.91041441238, 59664.16523960002 189745.0305656869, 59664.08272701559 189745.14692622554, 59663.994776452986 189745.25923294877, 59663.898495757276 189745.37064127854, 59663.79686448824 189745.47719114227, 59663.6901274845 189745.578625852, 59663.57854188486 189745.67470104265, 59663.46237650879 189745.76518526068, 59663.34191120887 189745.84986052164, 59663.21743619654 189745.92852283546, 59663.08925134302 189746.00098269767, 59662.95766545685 189746.0670655462, 59662.82299553995 189746.12661218163, 59662.68556602395 189746.1794791509, 59662.5457079886 189746.22553909285, 59662.40375836413 189746.26468104505, 59662.260059119646 189746.2968107111, 59662.1149564392 189746.32185068785, 59661.96879988787 189746.33974065178, 59661.82194156958 189746.35043750438, 59661.67473527889 189746.35391547607, 59661.52753564864 189746.35016618803, 59661.38069729563 189746.33919867265, 59661.23457396632 189746.32103935163, 59661.08951768462 189746.29573197238, 59660.945877903796 189746.2633375026, 59660.80400066468 189746.2239339834, 59660.664227761954 189746.17761634127, 59660.52689592079 189746.1244961595, 59660.39233598563 189746.06470140928, 59660.26087212312 189745.99837614136, 59660.132821041254 189745.92568013916, 59660.008491226276 189745.84678853367, 59659.88818219961 189745.76189138173, 59659.77218379624 189745.67119320796, 59659.77218379623 189745.67119320796, 59659.77218379623 189745.67119320796, 59614.77218379624 189708.67119320796, 59614.61468137061 189708.532168187, 59614.46729477156 189708.38246127014, 59547.639548111234 189635.570140282, 59485.84098041604 189587.72608787284, 59485.69409295087 189587.60471582974, 59485.5552067922 189587.47426378797, 59485.42488222378 189587.33525800702, 59485.30364499084 189587.18825925322, 59468.30364499084 189565.18825925322, 59468.30298412068 189565.18740369094, 59407.41596440814 189486.33372242388, 59306.068030250164 189384.011288899, 59306.0250767456 189384.0342221246, 59305.891937179156 189384.09711603654, 59113.89193717916 189469.09711603654, 59113.65886152817 189469.1888646404, 59113.418944471676 189469.26084985692, 58866.41894447167 189532.26084985692, 58866.23094366838 189532.30242486435, 58866.04066312095 189532.33185438265, 58743.04066312095 189547.33185438265, 58742.799306173154 189547.3514429392, 58742.55715563257 189547.35150198388, 58742.31578916074 189547.332031132, 58742.07677931087 189547.29315724026, 58605.17392039388 189519.31301089228, 58539.27216038081 189510.32640725412, 58539.12679543413 189510.30293768694, 58538.87580802498 189510.24481453185, 58538.63073291424 189510.16537165424, 58538.393377475855 189510.0651949275, 58538.16549215294 189509.94502313252, 58537.94875754862 189509.8057425093, 58537.744772031976 189509.64838022125, 58537.55503995041 189509.47409677986, 58537.38096053548 189509.28417748646, 58537.3714387279 189509.27226724994, 58537.23969859691 189509.30076807505, 58536.98479362907 189509.33813702042, 58536.72762243962 189509.35349801087, 58536.470081608386 189509.3467377625, 58536.214070441216 189509.31790613066, 58535.96147696303 189509.26721574215, 58535.71416399405 189509.1950404272, 58535.473955411944 189509.10191246262, 58535.2426227011 189508.9885186462, 58535.02187188836 189508.8556952319, 58534.81333096144 189508.7044217626, 58534.618537862894 189508.53581384622, 58534.438929148106 189508.35111492831, 58534.27582939106 189508.15168712192, 58534.13044141586 189507.9390011624, 58534.003837426215 189507.71462556097, 58533.89695109813 189507.48021503736, 58533.89695109801 189507.480215037, 58469.89695109817 189349.48021503742, 58469.89695109813 189349.48021503736, 58469.845035553495 189349.34242329403, 58469.79994366379 189349.20225015184, 58469.76178405933 189349.0600333002, 58469.730648669945 189348.91611535192, 58469.70661250352 189348.77084301796, 58469.689733465275 189348.6245662721, 58469.680052218304 189348.47763750787, 58469.67759208557 189348.33041068946, 58469.68235899375 189348.18324049923, 58469.69434145895 189348.03648148305, 58469.71351061435 189347.89048719621, 58469.739820279785 189347.74560935175, 58469.77320707296 189347.6021969731, 58469.81359056218 189347.46059555328, 58469.86087346007 189347.3211462224, 58469.914941857984 189347.1841849262, 58469.97566550043 189347.05004161646, 58470.04289809882 189346.9190394561, 58470.11647768394 189346.7914940408, 58470.19622699614 189346.66771263868, 58470.28195391231 189346.54799344996, 58470.37345190883 189346.43262488864, 58470.47050055899 189346.3218848877, 58470.57286606412 189346.2160402295, 58470.68030181672 189346.1153459031, 58470.792548994665 189346.02004448994, 58470.909337184676 189345.9303655795, 58471.030385033766 189345.84652521607, 58471.15540092707 189345.7687253785, 58471.28408369035 189345.69715349335, 58471.41612331556 189345.6319819836, 58471.55120170767 189345.57336785313, 58471.688993451 189345.5214523085, 58471.82916659319 189345.47636041878, 58471.97138344484 189345.43820081433, 58472.11530139311 189345.40706542495, 58472.26057372706 189345.38302925852, 58472.4068504729 189345.36615022027, 58472.553779237154 189345.3564689733, 58472.70100605554 189345.35400884057, 58472.848176245774 189345.35877574875, 58472.99493526197 189345.37075821395, 58473.140929548805 189345.38992736937, 58473.28580739325 189345.41623703478, 58473.42921977189 189345.44962382797, 58473.570821191744 189345.4900073172, 58473.7102705226 189345.53729021508, 58473.847231818785 189345.591358613, 58473.98137512855 189345.65208225543, 58474.11237728891 189345.7193148538, 58474.2399227042 189345.79289443896, 58474.36370410633 189345.87264375112, 58474.48342329505 189345.9583706673, 58474.59879185637 189346.04986866383, 58474.709531857305 189346.14691731398, 58474.8153765155 189346.2492828191, 58474.91607084191 189346.3567185717, 58475.01137225507 189346.46896574966, 58475.101051165526 189346.58575393967, 58475.18489152894 189346.70680178874, 58475.26269136652 189346.83181768205, 58475.33426325166 189346.96050044533, 58475.399434761406 189347.09254007053, 58475.45804889189 189347.22761846264, 58475.45804889206 189347.22761846308, 58539.12527965276 189504.4060944036, 58539.20251737488 189504.39175680993, 58539.38505306711 189504.36820497652, 58539.56868946355 189504.35589068805, 58539.75273539826 189504.35486029272, 58539.936498163894 189504.3651176687, 58540.08283960921 189504.38142624588, 58606.08283960921 189513.38142624588, 58606.27822067916 189513.41467625974, 58742.79943057622 189541.31682134818, 58865.122914096944 189526.39932335785, 59111.692705794056 189463.5090526011, 59302.61117092156 189378.98785710195, 59290.81149221935 189281.64050780868, 59193.428577790204 189171.33945166954, 59193.28362584998 189171.16205573187, 59051.28362584999 188983.16205573187, 59051.16673642513 188982.99588699825, 59051.06136169279 188982.82218797278, 59050.96798491535 188982.64175526204, 59050.88703433102 188982.4554163542, 59035.88703433101 188944.4554163542, 59035.87568400777 188944.42621669572, 58973.87568400776 188782.42621669572, 58973.87568400777 188782.42621669572, 58973.82644365331 188782.2874464691, 58973.78529084303 188782.1508648168, 58973.75067702891 188782.01248134446, 58973.722680469335 188781.87260892332, 58973.70136446174 188781.73156379096, 58973.68677719947 188781.58966483633, 58973.67895166289 188781.44723287883, 58973.67790554475 188781.30458994285, 58973.68364121021 188781.16205852988, 58973.696145691516 188781.01996088919, 58973.715390717276 188780.87861828937, 58973.74133277641 188780.7383502919, 58973.77391321651 188780.59947402877, 58973.81305837645 188780.46230348528, 58973.85867975294 188780.3271487904, 58973.910674200604 188780.19431551537, 58973.96892416518 188780.06410398296, 58974.03329794931 188779.93680858848, 58974.1036500103 188779.81271713407, 58974.17982128916 188779.69211017815, 58974.261639570235 188779.57526040098, 58974.34891987056 188779.46243198824, 58974.441464858086 188779.35388003374, 58974.53906529784 188779.2498499626, 58974.64150052496 188779.1505769764, 58974.74853894363 188779.05628552148, 58974.85993855068 188778.96718878142, 58974.97544748271 188778.88348819502, 58975.094804585555 188778.80537300094, 58975.21774000472 188778.73301980988, 58975.3439757955 188778.66659220515, 58975.473226551374 188778.60624037296, 58975.60520004928 188778.55210076275, 58975.84954231642 188778.47043169153, 58976.09999058568 188778.41002767565, 58976.35469785726 188778.37133418117, 58976.61178572218 188778.35463656398)), ((58879.69611585384 188707.80853383892, 58879.89840132997 188707.81662003396, 58880.09968085087 188707.83833074267, 58880.29903781642 188707.87356709735, 58880.49556438158 188707.92216863635, 58880.688365590555 188707.98391403473, 58880.876563452344 188708.05852211217, 58881.05930093898 188708.14565311346, 58881.23574588829 188708.2449102556, 58881.23574588848 188708.24491025571, 58983.23574588828 188770.2449102556, 58983.35965712585 188770.3244576849, 58983.47583454825 188770.40722789735, 58983.58794611574 188770.49542709225, 58983.69573835527 188770.58885585997, 58983.79896755935 188770.68730296745, 58983.897400337046 188770.79054583557, 58983.990814141674 188770.89835104253, 58984.078997773955 188771.0104748515, 58984.1617518595 188771.12666376177, 58984.23888929957 188771.2466550818, 58984.31023569413 188771.37017752317, 58984.375629736096 188771.496951814, 58984.43492357607 188771.6266913303, 58984.48798315659 188771.75910274393, 58984.534688515254 188771.8938866859, 58984.5749340559 188772.0307384232, 58984.60862878738 188772.1693485477, 58984.63569652927 188772.30940367575, 58984.65607608411 188772.45058715667, 58984.66972137576 188772.59257978873, 58984.676601553576 188772.73506054076, 58984.67670106216 188772.87770727798, 58984.670019676545 188773.02019749038, 58984.65657250267 188773.1622090218, 58984.63638994325 188773.30342079836, 58984.60951762903 188773.44351355432, 58984.57601631565 188773.58217055394, 58984.535961746216 188773.7190783076, 58984.489444480125 188773.85392728052, 58984.43656968826 188773.98641259264, 58984.37745691526 188774.1162347079, 58984.31223980919 188774.24310011146, 58984.24106581942 188774.3667219733, 58984.1615183901 188774.49063321087, 58984.07598674289 188774.61049198455, 58983.984676931024 188774.7260095441, 58983.88780892784 188774.83690759758, 58983.78561609682 188774.94291898186, 58983.67834462948 188775.04378830624, 58983.56625295215 188775.13927256767, 58983.44961110352 188775.2291417362, 58983.32870008401 188775.31317930916, 58983.20381117885 188775.39118283262, 58983.07524525636 188775.46296438933, 58982.94331204311 188775.52835105118, 58982.80832937777 188775.587185296, 58982.67062244539 188775.63932538693, 58982.53052299404 188775.68464571392, 58982.388368535576 188775.72303709635, 58982.24450153253 188775.754407046, 58982.09926857312 188775.77867998992, 58981.95301953625 188775.79579745248, 58981.806106748685 188775.80571819618, 58981.65888413618 188775.80841832107, 58981.51170637091 188775.80389132237, 58981.36492801701 188775.79214810597, 58981.21890267637 188775.77321696232, 58981.07398213685 188775.7471434982, 58980.930515524706 188775.7139905269, 58980.788848463584 188775.67383791678, 58980.649322241836 188775.62678239905, 58980.51227299035 188775.5729373345, 58980.37803087278 188775.51243244068, 58980.24691929015 188775.44541347914, 58980.11925410174 188775.37204190443, 58980.11925410154 188775.3720419043, 58878.11925410192 188713.37204190454, 58878.11925410173 188713.37204190443, 58877.99534286416 188713.2924944751, 58877.875484090466 188713.20696282788, 58877.75996653092 188713.11565301602, 58877.64906847744 188713.01878501283, 58877.54305709316 188712.91659218183, 58877.442187768786 188712.80932071447, 58877.34670350735 188712.69722903715, 58877.25683433881 188712.5805871885, 58877.17279676586 188712.459676169, 58877.09479324238 188712.33478726386, 58877.023011685684 188712.20622134136, 58876.957625023824 188712.07428812812, 58876.89879077901 188711.93930546276, 58876.84665068808 188711.8015985304, 58876.801330361086 188711.66149907905, 58876.76293897866 188711.51934462058, 58876.731569029005 188711.37547761752, 58876.707296085086 188711.23024465813, 58876.69017862254 188711.08399562124, 58876.68025787885 188710.9370828337, 58876.67755775393 188710.78986022118, 58876.68208475264 188710.64268245592, 58876.69382796904 188710.49590410202, 58876.712759112685 188710.34987876136, 58876.7388325768 188710.20495822185, 58876.77198554811 188710.0614916097, 58876.81213815823 188709.9198245486, 58876.859193675984 188709.78029832683, 58876.91303874052 188709.64324907534, 58876.97354363435 188709.50900695781, 58877.040562595896 188709.37789537513, 58877.1139341706 188709.25023018674, 58877.219576806245 188709.08841398865, 58877.33541841621 188708.9337350637, 58877.46097832413 188708.78683524087, 58877.59573552825 188708.64832407035, 58877.739130863316 188708.5187762942, 58877.890569320756 188708.3987294615, 58878.049422517666 188708.28868169797, 58878.21503130419 188708.18908963882, 58878.38670849868 188708.10036653405, 58878.563741739024 188708.02288053377, 58878.74539643862 188707.95695316055, 58878.93091883444 188707.90285797525, 58879.11953911474 188707.8608194419, 58879.31047461332 188707.8310119964, 58879.50293305714 188707.81355932253, 58879.69611585384 188707.80853383892)), ((58857.65112455598 188698.3540326962, 58857.89024649702 188698.36146977037, 58858.128015497656 188698.3879370161, 58858.362919489366 188698.43326611756, 58858.593464623365 188698.49716880877, 58858.818184770615 188698.5792387069, 58859.035650845486 188698.67895389654, 58859.24447989391 188698.7956802487, 58859.44334388814 188698.92867545373, 58859.560217801925 188699.01824261615, 58859.672556083606 188699.11343662214, 58859.78008810043 188699.214028141, 58859.882554798336 188699.31977483895, 58859.979709326086 188699.43042196293, 58860.0713176299 188699.54570295432, 58860.15715901736 188699.66534009113, 58860.23702668905 188699.78904515703, 58860.31072823674 188699.91652013565, 58860.37808610695 188700.04745792862, 58860.43893802868 188700.18154309533, 58860.493137404315 188700.31845261285, 58860.5405536628 188700.45785665416, 58860.581072574234 188700.59941938275, 58860.614596524996 188700.74279976156, 58860.64104475296 188700.88765237475, 58860.66035354203 188701.03362825964, 58860.672476375636 188701.18037574756, 58860.67738404881 188701.32754131098, 58860.67506473854 188701.4747704151, 58860.66552403225 188701.6217083722, 58860.64878491433 188701.7680011958, 58860.62488771079 188701.9132964537, 58860.59388999208 188702.0572441169, 58860.55586643442 188702.19949740288, 58860.510908639895 188702.339713611, 58860.45912491576 188702.47755494813, 58860.40064001356 188702.6126893424, 58860.33559482853 188702.74479124328, 58860.264146060224 188702.87354240566, 58860.18646583499 188702.99863265673, 58860.10274129128 188703.11976064314, 58860.10274129107 188703.11976064343, 58702.102741291266 188920.11976064314, 58702.01168820316 188920.23847648874, 58701.914829699315 188920.35250520043, 58701.812406678866 188920.4615631746, 58701.704673880566 188920.5653791706, 58654.1249904128 188964.18008901607, 58579.44258335561 189117.52796484018, 58552.495766645596 189191.3822032306, 58552.41688122475 189191.57694188392, 58552.32455881854 189191.76568145587, 58472.324558818545 189341.76568145587, 58472.32455881853 189341.76568145587, 58472.32455881853 189341.76568145587, 58472.25209830944 189341.89386594374, 58472.17343536749 189342.0183405591, 58472.08875949862 189342.13880543172, 58471.9982746944 189342.2549703512, 58471.90219894066 189342.366555466, 58471.80076369229 189342.47329195787, 58471.694213315706 189342.57492268924, 58471.58280450008 189342.67120282273, 58471.46680563902 189342.76190041113, 58471.34649618394 189342.84679695597, 58471.22216597085 189342.92568793404, 58471.09411452214 189342.99838329008, 58470.96265032494 189343.06470789458, 58470.828090088035 189343.12450196577, 58470.69075797882 189343.1776214545, 58470.55098484236 189343.22393839128, 58470.4091074044 189343.26334119454, 58470.26546746011 189343.2957349395, 58470.120411050695 189343.32104158672, 58469.97428762975 189343.33920017036, 58469.827449221404 189343.35016694473, 58469.68024957224 189343.35391548998, 58469.533043299096 189343.35043677545, 58469.38618503479 189343.33973918174, 58469.24002857373 189343.32184848026, 58469.09492601965 189343.2968077713, 58468.95122693731 189343.26467738007, 58468.80927751037 189343.22553471156, 58468.66941970745 189343.17947406383, 58468.53199045823 189343.12660640106, 58468.397320841825 189343.06705908605, 58468.26573528913 189343.00097557352, 58468.141501995895 189342.93087428683, 58468.0207414408 189342.85494675642, 58467.903726651406 189342.77336464683, 58467.790722186466 189342.68631240708, 58467.6819835378 189342.59398685358, 58467.57775655263 189342.4965967252, 58467.478276877766 189342.3943622113, 58467.38376942683 189342.2875144539, 58467.294447871725 189342.17629502513, 58467.21051415958 189342.060955381, 58467.13215805613 189341.94175629294, 58467.059556716704 189341.81896725818, 58466.99287428569 189341.69286589048, 58466.9322615254 189341.56373729242, 58466.87785547523 189341.4318734109, 58466.82977914184 189341.297572377, 58466.78814122102 189341.16113783192, 58466.753035851936 189341.02287824056, 58466.72454240434 189340.88310619403, 58466.702725299074 189340.74213770303, 58466.68763386242 189340.60029148316, 58466.679302214616 189340.45788823467, 58466.67774919269 189340.31524991698, 58466.68297830787 189340.17269902118, 58466.69497773764 189340.03055784057, 58466.713720352505 189339.88914774216, 58466.73916377726 189339.74878844008, 58466.771250486876 189339.60979727271, 58466.809907936506 189339.4724884852, 58466.85504872551 189339.33717251898, 58466.90657079508 189339.20415530997, 58466.964357658944 189339.0737375968, 58467.03044117148 189338.94215204412, 58467.030441171475 189338.94215204412, 58546.9313837546 189189.12788470078, 58573.85923334443 189115.3256302694, 58573.91610751622 189115.1814358, 58573.98035359846 189115.040371427, 58648.980353598454 188961.040371427, 58649.04498209504 188960.9152195941, 58649.11541377956 188960.79323926102, 58649.19149339065 188960.6746993242, 58649.27305321654 188960.55986109603, 58649.3599134647 188960.44897772878, 58649.45188265826 188960.3422936565, 58649.54875805802 188960.24004405618, 58649.650326109455 188960.14245432938, 58697.42899261131 188916.34534336935, 58855.25225869854 188699.58807285715, 58855.25225869875 188699.58807285686, 58855.359252862705 188699.44978171444, 58855.47412190383 188699.31795874765, 58855.59647562233 188699.1930517472, 58855.7258983936 188699.07548501095, 58855.861950580125 188698.9656579026, 58856.004170024855 188698.86394349491, 58856.15207362111 188698.7706873026, 58856.30515895368 188698.68620610857, 58856.46290600543 188698.61078688788, 58856.62477892381 188698.54468583278, 58856.79022784106 188698.48812748265, 58856.95869074209 188698.44130396112, 58857.129595373546 188698.40437432347, 58857.302361187765 188698.3774640164, 58857.4764013148 188698.36066445176, 58857.65112455598 188698.3540326962)), ((60521.60228143428 188137.80941920023, 60521.8343690052 188137.81258020172, 60522.065517547206 188137.83367484645, 60614.065517547206 188149.83367484645, 60614.21101674119 188149.8562972437, 60614.35074687744 188149.88499551135, 60614.488954869696 188149.92030347674, 60614.62532824349 188149.96214131205, 60614.75955867224 188150.0104144261, 60614.89134267433 188150.06501367825, 60615.020382299306 188150.125815625, 60615.14638580145 188150.19268279924, 60615.269068299414 188150.26546402098, 60615.38815242033 188150.3439947391, 60615.50336892689 188150.4280974035, 60615.61445732606 188150.51758186647, 60615.721166458075 188150.61224581255, 60615.82325506423 188150.71187521602, 60615.920492332385 188150.81624482473, 60616.012658418775 188150.92511866946, 60616.099544945086 188151.03825059725, 60616.18095546956 188151.15538482816, 60616.25670593111 188151.27625653334, 60616.32662506553 188151.400592434, 60616.39055479261 188151.528111419, 60616.44835057364 188151.65852518068, 60616.49988173813 188151.79153886656, 60616.54503177924 188151.92685174596, 60616.58369861725 188152.06415788995, 60616.6157948303 188152.2031468631, 60616.64124785206 188152.34350442514, 60616.66000013577 188152.4849132417, 60616.672009284404 188152.62705360152, 60616.67724814647 188152.76960413947, 60616.67570487743 188152.91224256298, 60616.66738296646 188153.05464638083, 60616.65230122856 188153.19649363222, 60616.630493762044 188153.33746361465, 60616.60200987142 188153.47723760907, 60616.56691395591 188153.61549960045, 60616.52528536388 188153.7519369922, 60616.477218213426 188153.886241313, 60616.42282117956 188154.01810891423, 60616.36221724857 188154.14724165638, 60616.295543439875 188154.2733475832, 60616.22295049631 188154.39614158176, 60616.14460254327 188154.51534602712, 60616.06067671765 188154.63069140996, 60615.97136276738 188154.74191694582, 60615.87686262236 188154.8487711649, 60615.77738993801 188154.95101248048, 60615.67316961212 188155.04840973514, 60615.56443727646 188155.14074272342, 60615.45143876397 188155.22780268962, 60615.33442955301 188155.3093927999, 60615.213674189734 188155.38532858714, 60615.089445689955 188155.45543836808, 60614.962024921915 188155.51956363156, 60614.83169997125 188155.5775593967, 60614.69876548966 188155.62929454094, 60614.56352202873 188155.6746520962, 60614.426275360434 188155.71352951362, 60614.28733578579 188155.74583889524, 60614.1470174333 188155.77150719275, 60614.005637548755 188155.79047637273, 60613.863515777964 188155.80270354773, 60613.72097344405 188155.80816107334, 60613.57833282101 188155.80683661063, 60613.43591640505 188155.79873315408, 60613.28948244279 188155.78327731357, 60521.75362861434 188143.84381811856, 60302.46890610003 188183.71376766663, 60107.583983873905 188255.30414725989, 60044.1223659687 188344.5470474391, 60044.04046348149 188344.65682765952, 60043.953635603204 188344.76275515248, 60043.86206331897 188344.86460912132, 60043.76593750322 188344.96217726037, 59979.947155877504 188406.84705641257, 59980.034088821165 188406.9520038598, 59980.169410685856 188407.13803269312, 59980.29008046624 188407.33388349856, 59980.395388640994 188407.53840470093, 59980.48471601286 188407.75039374433, 59980.55753734946 188407.96860416303, 59980.613424471565 188408.19175291044, 59980.652048770775 188408.41852790333, 59980.67318314165 188408.64759573663, 59980.67670331704 188408.87760952374, 59980.662588598825 188409.1072168159, 59980.63092197956 188409.33506755458, 59980.58188965451 188409.55982200947, 59980.51577992685 188409.78015865598, 59980.43298151247 188409.99478194566, 59980.333981254415 188410.20242992372, 59980.219361260264 188410.40188164928, 59980.140744507786 188410.5209089897, 59980.05655860536 188410.6360646903, 59979.96699388893 188410.74708839547, 59979.87225285535 188410.85372909173, 59979.772549704656 188410.95574567514, 59979.66810985571 188411.0529074963, 59979.559169436594 188411.1449948821, 59979.44597475071 188411.23179963217, 59979.32878171995 188411.31312548957, 59979.20785530606 188411.3887885847, 59979.08346891157 188411.45861785088, 59978.95590376173 188411.52245541103, 59978.825448268595 188411.58015693486, 59978.692397379 188411.63159196498, 59978.557051907745 188411.6766442119, 59978.41971785742 188411.715211817, 59978.280705726596 188411.74720758278, 59978.14032980784 188411.77255917, 59977.99890747707 188411.79120926125, 59977.856758476075 188411.80311569053, 59977.71420418954 188411.80825153863, 59977.571566918494 188411.80660519385, 59977.42916915156 188411.79818037848, 59977.28733283587 188411.7829961401, 59977.14637864918 188411.76108680884, 59977.00662527483 188411.73250191947, 59976.86838868124 188411.69730609958, 59976.731981407574 188411.6555789234, 59976.59771185704 188411.60741473193, 59976.46588359968 188411.55292241956, 59976.336794686045 188411.49222518798, 59976.21073697328 188411.4254602676, 59976.08409442573 188411.35033734527, 59842.966420684395 188327.903437388, 59660.731105256935 188347.7116238475, 59499.34160058369 188455.304626963, 59499.1926266867 188455.39775997872, 59499.038456413466 188455.48201261935, 59498.879618516294 188455.55709592655, 59498.7166577559 188455.62275238984, 59498.550133033 188455.67875682953, 59498.38061547154 188455.7249171692, 59498.20868645989 188455.76107509437, 59498.03493565687 188455.78710659547, 59349.24533096221 188473.64185915884, 59308.01132353562 188524.69348740127, 59307.92279360333 188524.79811338676, 59307.829577457436 188524.8985867459, 59307.73186965191 188524.994697778, 59307.62987411537 188525.0862458871, 59069.62987411537 188729.0862458871, 59069.481732197644 188729.20529608973, 59069.32634949944 188729.31472732674, 58993.32634949944 188779.31472732674, 58993.32634949944 188779.31472732674, 58993.32634949943 188779.31472732674, 58993.201387468034 188779.39261364785, 58993.07275425824 188779.4642745552, 58992.94075975871 188779.52953741144, 58992.80572195577 188779.58824499257, 58992.667966167304 188779.64025586692, 58992.52782425907 188779.68544473572, 58992.3856338452 188779.72370273503, 58992.24173747487 188779.75493769802, 58992.09648180702 188779.77907437686, 58991.950216775294 188779.79605462422, 58991.803294744954 188779.80583753317, 58991.656069664044 188779.80839953586, 58991.508896210675 188779.80373446018, 58991.36212893859 188779.7918535447, 58991.216121423015 188779.7727854116, 58991.07122540882 188779.74657599768, 58990.92778996321 188779.71328844372, 58990.78616063473 188779.67300294232, 58990.64667862085 188779.6258165448, 58990.50967994594 188779.57184292737, 58990.37549465182 188779.51121211713, 58990.244446002616 188779.44407017904, 58990.116849706 188779.37057886395, 58989.99301315263 188779.29091521882, 58989.8732346756 188779.20527116038, 58989.75780283176 188779.11385301262, 58989.646995706535 188779.01688100994, 58989.541080243995 188778.91458876632, 58989.44031160376 188778.80722271279, 58989.344932546315 188778.69504150355, 58989.25517284816 188778.57831539295, 58989.17124874828 188778.45732558443, 58989.09570308072 188778.33632577595, 58989.02599459825 188778.2118716518, 58988.96228090479 188778.08424459037, 58988.90470605063 188777.95373314372, 58988.85340020677 188777.82063238515, 58988.80847937061 188777.68524324222, 58988.77004510367 188777.54787181626, 58988.738184302 188777.4088286904, 58988.71296899967 188777.26842822717, 58988.69445620599 188777.12698785806, 58988.68268777651 188776.9848273656, 58988.6776903185 188776.84226816052, 58988.679475130695 188776.69963255493, 58988.688038177825 188776.55724303366, 58988.70336009969 188776.41542152522, 58988.72540625495 188776.2744886739, 58988.75412679945 188776.1347631148, 58988.78945679892 188775.99656075347, 58988.83131637574 188775.8601940516, 58988.87961088959 188775.72597132076, 58988.934231151405 188775.59419602514, 58988.995053670216 188775.46516609547, 58989.061940932384 188775.33917325558, 58989.13474171248 188775.21650236272, 58989.21329141522 188775.09743076348, 58989.29741244755 188774.9822276669, 58989.386914620234 188774.87115353567, 58989.48159557778 188774.76445949732, 58989.581241256004 188774.66238677638, 58989.685626365965 188774.56516614917, 58989.794514903355 188774.47301742173, 58989.90766068207 188774.38614893318, 58990.02865049059 188774.3022248333, 58990.02865049058 188774.30222483329, 59065.86964012287 188724.4068369173, 59303.516406284165 188520.70960877906, 59345.3436764544 188468.92346475876, 59345.437303293875 188468.81310174416, 59345.53614381284 188468.70738262634, 59345.639967976684 188468.6065534487, 59345.7485341522 188468.51084887414, 59345.86158966994 188468.42049163886, 59345.97887141229 188468.33569203404, 59346.100106425794 188468.25664741654, 59346.225012556446 188468.18354174925, 59346.353299106304 188468.11654517334, 59346.4846675101 188468.05581361198, 59346.61881203006 188468.00148840764, 59346.75542046746 188467.95369599306, 59346.89417488924 188467.91254759702, 59347.034752367916 188467.87813898543, 59347.17682573314 188467.85055023857, 59347.32006433316 188467.82984556456, 59496.60915521347 188449.91515465893, 59658.013399406336 188342.312325197, 59658.16598628815 188342.21708141422, 59658.32400691641 188342.1311534461, 59658.48689322216 188342.05485019542, 59658.654059644774 188341.98844596502, 59658.824905237045 188341.93217947177, 59658.99881582549 188341.88625298825, 59659.17516621828 188341.8508316158, 59659.3533224527 188341.8260426908, 59843.353322452705 188321.8260426908, 59843.603274692905 188321.80939445316, 59843.85374447551 188321.81365757415, 59844.10298537808 188321.8388023288, 59844.349259546645 188321.88465339306, 59844.59084981305 188321.95089106643, 59844.826071668074 188322.03705350094, 59845.05328500677 188322.14253992148, 59845.270905564284 188322.26661481475, 59972.525908021285 188402.03840739976, 59972.52944969789 188402.03683748248, 59972.727719868315 188401.96279203027, 59972.93071717775 188401.90290979718, 59973.13743129077 188401.8574888224, 59973.34683337311 188401.82675517, 59973.55788121222 188401.81086180417, 59973.76952440452 188401.80988782752, 59973.98070958325 188401.82383808764, 59974.19038566126 188401.85264315287, 59974.39750906233 188401.89615965783, 59974.60104891511 188401.95417101713, 59974.7999921839 188402.02638850306, 59974.993348710595 188402.11245268295, 59975.180156142815 188402.21193520774, 59975.35948472357 188402.32434094424, 59975.530441918796 188402.44911043922, 59975.69217685953 188402.58562270395, 59975.70766698935 188402.60037053353, 60039.391840838296 188340.84602013454, 60103.2326340213 188251.06990472093, 60103.36992326541 188250.8914237497, 60103.520212831114 188250.72374298138, 60103.68265602384 188250.56780708823, 60103.85633767846 188250.42449457487, 60104.04027931511 188250.29461282887, 60104.2334446517 188250.17889357216, 60104.434745442086 188250.07798873866, 60104.64304760696 188249.99246680146, 60300.64304760696 188177.99246680146, 60300.88902519546 188177.9139454634, 60301.1408436804 188177.8568663497, 60521.14084368039 188137.8568663497, 60521.37064412694 188137.824210764, 60521.60228143428 188137.80941920023)), ((60682.65163306 188074.89948419845, 60682.826445290455 188074.90307241151, 60683.00075156713 188074.9168387873, 60683.173959787266 188074.94073656268, 60683.3454815781 188074.97468455907, 60683.514734295524 188075.01856745817, 60683.681143003276 188075.07223619372, 60683.844142425914 188075.13550845787, 60684.00317886907 188075.20816932037, 60684.15771210022 188075.28997195885, 60684.30721718387 188075.38063849707, 60684.45118626469 188075.47986094895, 60684.58913029265 188075.58730226476, 60684.72058068428 188075.70259747596, 60684.845090914416 188075.82535493514, 60684.962238033 188075.95515764618, 60685.07162410179 188076.091564681, 60685.07162410179 188076.09156468103, 60685.0716241018 188076.091564681, 60721.68919471809 188124.58510414584, 60755.942016262255 188143.61444944816, 60756.13654696208 188143.30451918062, 60756.13654696209 188143.30451918065, 60756.13654696209 188143.30451918062, 60756.217863403406 188143.1817615956, 60756.30510532471 188143.06314188614, 60756.39806255257 188142.94894581748, 60756.496511144884 188142.83944849798, 60756.600213930375 188142.73491371627, 60756.708921079946 188142.63559330578, 60756.82237070854 188142.54172653807, 60756.940289506085 188142.45353954646, 60757.062393395856 188142.37124478107, 60757.18838821889 188142.29504049724, 60757.31797044263 188142.22511027774, 60757.450827892135 188142.1616225906, 60757.58664050218 188142.10473038323, 60757.72508108829 188142.05457071392, 60757.865816134974 188142.01126442174, 60758.008506599166 188141.97491583534, 60758.15280872705 188141.9456125216, 60758.29837488216 188141.9234250748, 60758.44485438287 188141.90840694646, 60758.591894347235 188141.90059431657, 60758.739140543104 188141.90000600638, 60758.88623824149 188141.90664343323, 60759.03283307116 188141.92049060698, 60759.17857187233 188141.94151416855, 60759.32310354745 188141.96966347037, 60759.46607990708 188142.00487069826, 60759.60715650862 188142.04705103498, 60759.74599348618 188142.09610286437, 60759.88225636935 188142.15190801627, 60760.01561688888 188142.2143320512, 60760.14575376761 188142.2832245842, 60760.272353494394 188142.3584196471, 60760.39133602476 188142.43710420092, 60760.506443742954 188142.52135569797, 60760.61741640191 188142.610983654, 60760.72400310353 188142.70578542922, 60760.82596286592 188142.8055466862, 60760.92306516824 188142.91004187474, 60761.015090471876 188143.01903474165, 60761.1018307168 188143.1322788649, 60761.18308979198 188143.24951821088, 60761.258683978755 188143.3704877131, 60761.32844236622 188143.4949138716, 60761.39220723762 188143.62251537127, 60761.44983442696 188143.75300371787, 60761.5011936449 188143.88608389022, 60761.546168773384 188144.02145500737, 60761.58465812814 188144.15881100876, 60761.61657468857 188144.29784134612, 60761.64184629452 188144.4382316858, 60761.66041580941 188144.57966461926, 60761.672241249435 188144.72182038068, 60761.677295878435 188144.86437757016, 60761.67556826841 188145.00701388007, 60761.667062325316 188145.14940682397, 60761.65179728023 188145.29123446567, 60761.629807645906 188145.43217614695, 60761.60114313871 188145.57191321277, 60761.56586856622 188145.71012973163, 60761.52406368074 188145.8465132097, 60761.47582299893 188145.98075529758, 60761.42125558817 188146.11255248735, 60761.36048481991 188146.24160679866, 60761.2936480908 188146.36762645261, 60761.21845302791 188146.49422617938, 60702.68667708893 188239.7482420822, 60703.57837197249 188240.5713450516, 60753.43041417254 188276.46481543564, 60753.547124285025 188276.55325030442, 60753.65938012642 188276.64727478236, 60753.7669142537 188276.74666486157, 60753.869470473066 188276.851183751, 60808.21376381197 188335.00911171015, 60842.2270148967 188288.71329773372, 60878.195849921176 188235.75917950325, 60878.32322454978 188235.5854235632, 60878.46274081061 188235.4212570755, 60878.613679180744 188235.26752669094, 60878.77526123038 188235.1250252385, 60928.775261230156 188194.12502523867, 60928.77526123037 188194.1250252385, 60928.891379916604 188194.03448111104, 60929.01180152255 188193.94974372187, 60929.13623594202 188193.8710172107, 60929.26438340159 188193.79849123664, 60929.395935182816 188193.73234052112, 60929.53057436592 188193.672724427, 60929.66797659332 188193.61978657462, 60929.80781085102 188193.573654496, 60929.94974026605 188193.53443932725, 60930.093422918006 188193.50223554124, 60930.2385126628 188193.47712071968, 60930.38465996653 188193.45915536635, 60930.53151274753 188193.4483827614, 60930.678717224604 188193.4448288569, 60930.82591876927 188193.44850221463, 60930.972762760095 188193.45939398507, 60931.11889543707 188193.47747792903, 60931.26396475376 188193.50271048068, 60931.40762122547 188193.5350308526, 60931.54951877119 188193.5743611822, 60931.6893155473 188193.62060671923, 60931.82667477112 188193.6736560542, 60931.96126553225 188193.73338138656, 60932.09276358975 188193.79963883277, 60932.22085215329 188193.87226877286, 60932.3452226463 188193.95109623493, 60932.46557544937 188194.03593131673, 60932.58162062205 188194.12656964306, 60932.69307860136 188194.22279285835, 60932.799680875265 188194.32436915234, 60932.90117062954 188194.43105381893, 60932.997303366494 188194.54258984537, 60933.08784749393 188194.6587085316, 60933.17258488313 188194.77913013755, 60933.25131139428 188194.90356455703, 60933.323837368334 188195.0317120166, 60933.38998808386 188195.16326379782, 60933.449604178 188195.2979029809, 60933.50254203035 188195.43530520832, 60933.548674109 188195.57513946603, 60933.58788927772 188195.71706888106, 60933.620093063735 188195.860751533, 60933.64520788531 188196.0058412778, 60933.66317323864 188196.15198858152, 60933.673945843606 188196.29884136253, 60933.67749974806 188196.4460458396, 60933.67382639035 188196.59324738427, 60933.662934619904 188196.7400913751, 60933.644850675955 188196.88622405205, 60933.61961812431 188197.03129336875, 60933.58729775238 188197.17494984047, 60933.54796742279 188197.3168473862, 60933.50172188575 188197.4566441623, 60933.448672550796 188197.59400338613, 60933.38894721843 188197.72859414725, 60933.322689772205 188197.86009220473, 60933.25005983212 188197.9881807683, 60933.171232370056 188198.1125512613, 60933.08639728828 188198.23290406435, 60932.99575896192 188198.34894923706, 60932.89953574666 188198.46040721636, 60932.797959452655 188198.56700949027, 60932.69127478608 188198.66849924455, 60932.57973875964 188198.7646319815, 60932.579738759196 188198.76463198185, 60882.91531141111 188239.48946240728, 60849.498573358294 188288.6863267628, 60849.503713898484 188288.68399065756, 60849.675219447454 188288.61720881518, 60849.850497354084 188288.56106949525, 60850.02888791192 188288.51578399344, 60850.209719699174 188288.4815227542, 60850.39231210585 188288.4584147291, 60850.575977895336 188288.44654689153, 60850.76002579108 188288.44596390933, 60850.943763078365 188288.4566679767, 60851.126498211524 188288.47861880597, 60851.307543416784 188288.51173377916, 60851.486217280864 188288.55588825903, 60851.66184731569 188288.61091605804, 60851.833772489466 188288.676610064, 60852.00134571466 188288.75272301948, 60852.16393628349 188288.83896845256, 60852.32093224177 188288.93502175485, 60852.32093224178 188288.93502175488, 60852.32093224179 188288.93502175485, 61132.70663883302 188472.5327798075, 61180.452491602584 188477.30736508442, 61203.43527203894 188451.4517370935, 61203.539737141495 188451.34007922298, 61203.64975578085 188451.233889126, 61203.76504214768 188451.13344266597, 61203.88529674802 188451.03900078541, 61204.01020718129 188450.9508088279, 61204.13944895186 188450.86909590088, 61204.272686312055 188450.79407428033, 61204.40957313434 188450.72593885937, 61204.54975381051 188450.664866642, 61204.69286417551 188450.61101628328, 61204.83853245345 188450.56452767705, 61204.98638022342 188450.52552159267, 61205.136023402585 188450.49409936115, 61205.28707324395 188450.470342612, 61205.439137346235 188450.45431306117, 61205.591820673304 188450.4460523506, 61240.59182067331 188449.4460523506, 61240.73271498822 188449.44533676893, 61240.87348751284 188449.4512373064, 61241.01382773864 188449.46374094795, 61241.15342611065 188449.48282011366, 61284.15342611066 188456.39192351367, 61284.298191705064 188456.41884397028, 61284.441461998766 188456.45283531104, 61284.58289184109 188456.49381564787, 61284.72214051516 188456.54168625554, 61284.85887255871 188456.59633180953, 61284.99275857228 188456.65762066396, 61285.12347601273 188456.7254051686, 61285.250709970314 188456.7995220246, 61285.37415392726 188456.87979267802, 61285.49351049628 188456.9660237498, 61285.60849213693 188457.05800750174, 61285.71882184838 188457.1555223369, 61285.82423383669 188457.25833333354, 61285.92447415514 188457.3661928109, 61286.019301316024 188457.47884092614, 61286.108486872414 188457.59600630004, 61286.19181596849 188457.71740667094, 61286.269087857145 188457.84274957472, 61286.34011638365 188457.97173304934, 61286.404730434064 188458.10404636236, 61286.46277434746 188458.23937075934, 61286.51410829099 188458.37738023204, 61286.55860859668 188458.5177423035, 61286.59616805938 188458.66011882917, 61286.62669619508 188458.80416681158, 61286.65011945881 188458.9495392265, 61286.666381421885 188459.09588585907, 61286.67544290781 188459.24285414742, 61286.67728208666 188459.39009003207, 61286.6718945277 188459.53723880887, 61286.65929321005 188459.68394598356, 61286.63950849135 188459.82985812565, 61286.61353671026 188459.9701206229, 61286.580926843264 188460.10898997917, 61286.541752618 188460.24615222478, 61286.496102603494 188460.38129724955, 61286.44408000986 188460.51411950405, 61286.385802455006 188460.64431869047, 61286.32140169865 188460.77160044143, 61286.251023344485 188460.89567698556, 61286.174826510935 188461.01626779823, 61286.09298347143 188461.13310023563, 61286.00567926493 188461.24591015128, 61285.913111277514 188461.35444249323, 61285.815488796165 188461.45845188067, 61285.71303253557 188461.5577031588, 61285.60597413911 188461.65197193035, 61285.49455565512 188461.74104506304, 61285.37902898968 188461.82472117143, 61285.259655337046 188461.90281107218, 61285.136704589124 188461.97513821183, 61285.010454725285 188462.04153906592, 61284.88119118387 188462.10186350875, 61284.74920621684 188462.1559751528, 61284.61479822903 188462.203751657, 61284.47827110348 188462.2450850035, 61284.33993351439 188462.27988174168, 61284.20009822925 188462.30806319963, 61284.05908140167 188462.32956566187, 61283.917201856624 188462.34434051346, 61283.7747803696 188462.35235434995, 61283.63213894135 188462.35358905286, 61283.48960006992 188462.34804183067, 61283.34748602146 188462.33572522504, 61283.201573879356 188462.31594050635, 61240.480644529605 188455.4516772919, 61207.05868775907 188456.40659034246, 61183.91972795105 188482.43792012648, 61183.79832581772 188482.56664335914, 61183.66954600327 188482.68798547052, 61183.533836491886 188482.80152434987, 61183.39166937396 188482.9068650314, 61183.243539203846 188483.00364106824, 61183.08996127948 188483.09151580723, 61182.931469849806 188483.17018355997, 61182.76861625629 188483.2393706663, 61182.60196701498 188483.2988364462, 61182.432101845814 188483.348374037, 61182.25961165588 188483.38781111324, 61182.0850964839 188483.41701048572, 61181.90916341287 188483.4358705791, 61181.732424458205 188483.4443257851, 61181.55549443874 188483.44234669072, 61181.37898883795 188483.42994018062, 61131.37898883794 188478.42994018062, 61131.20049842455 188478.4066641054, 61131.02372524879 188478.37272522383, 61130.849305705946 188478.32824571815, 61130.67786771807 188478.2733857176, 61130.5100284734 188478.20834272183, 61130.34639220447 188478.13335088998, 61130.18754801283 188478.0486801977, 61130.03406774821 188477.95463546514, 60849.03406774821 188293.95463546514, 60849.03406774821 188293.95463546514, 60848.91289694894 188293.8709728946, 60848.77455109247 188293.76404948655, 60848.64266938241 188293.6492478936, 60848.517699809076 188293.52695808647, 60848.40006688288 188293.3975954726, 60848.2901701923 188293.2615994852, 60848.18838304651 188293.11943209043, 60848.095051207296 188292.97157621811, 60848.01049171454 188292.81853412135, 60847.93499180924 188292.66082567043, 60847.868807957784 188292.4989865868, 60847.812164980765 188292.33356662325, 60847.76525528929 188292.16512769653, 60847.72823823136 188291.99424197854, 60847.7012395506 188291.8214899527, 60847.6843509591 188291.64745844214, 60847.677629825885 188291.47273861626, 60847.67927592396 188291.36473687447, 60847.15915006882 188292.13047771674, 60847.095145433675 188292.22105791187, 60811.6381661932 188340.4819463225, 60807.69375447637 188385.84268106607, 60817.654333625134 188465.52731425624, 60817.66218021376 188465.5966248146, 60824.662180213774 188534.5966248146, 60824.676774809144 188534.8334594636, 60824.67260605686 188535.07070674954, 60824.64970003648 188535.30688246252, 60824.608200047194 188535.5405090964, 60817.616682337466 188567.5017329123, 60804.62413574034 188635.4627458819, 60804.5913919299 188635.61302464813, 60756.591391929906 188831.61302464813, 60756.554961572445 188831.7480732016, 60756.51227584283 188831.88127684727, 60756.463427536444 188832.01234601106, 60756.4085228456 188832.14099575908, 60756.34768112874 188832.26694641696, 60756.28103465089 188832.38992417807, 60756.208728296195 188832.50966169854, 60756.13091925289 188832.62589867853, 60737.65324958189 188858.88363978997, 60736.68053274965 188896.81959624717, 60739.66679242706 188934.64555216112, 60742.6651796144 188967.62781122187, 60742.67545605999 188967.78869613883, 60742.67707522062 188967.9499007919, 60742.6700324206 188968.11095966562, 60742.654347997646 188968.27140766566, 60742.6300672441 188968.43078146168, 60742.597260276205 188968.58862082526, 60742.55602183161 188968.74446995914, 60742.50647099575 188968.8978788132, 60730.62021736788 189002.57559742552, 60723.65856016772 189064.23598976983, 60723.63293275889 189064.41460500692, 60723.59661319624 189064.591356404, 60691.602020869315 189199.56854278324, 60676.651880120015 189267.34251418008, 60676.607189018985 189267.90953252435, 60676.66245550903 189267.89849736576, 60676.8446555961 189267.87247629603, 60677.02810843433 189267.85767683852, 60677.21212354866 189267.85415469506, 60677.39600834776 189267.86192312214, 60677.57907073075 189267.8809528812, 60677.76062169217 189267.9111723485, 60677.93997791519 189267.95246778484, 60678.11646434349 189268.0046837635, 60678.1164643435 189268.0046837635, 60766.11646434351 189297.0046837635, 60766.244211463505 189297.05000648764, 60766.36978089488 189297.10105346498, 60766.49291628797 189297.15772048323, 60766.61336626222 189297.21989185683, 60766.730884919314 189297.2874406631, 60766.84523234523 189297.3602290013, 60766.9561751 189297.43810827422, 60767.06348669429 189297.5209194916, 60850.563486694286 189365.0209194916, 60850.60500188655 189365.055099423, 60915.60500188655 189419.555099423, 60915.60500188655 189419.555099423, 60915.71547961747 189419.65244653018, 60915.84664248351 189419.78155993138, 60915.96964118702 189419.91847335923, 60916.08401278864 189420.06267150256, 60916.18932681949 189420.2136116321, 60916.23850764991 189420.29311732165, 60916.30756625448 189420.3354466034, 60916.42918011268 189420.41846381727, 61046.41503726751 189513.90829184785, 61074.90077724229 189533.8982848126, 61075.01719039406 189533.98424198848, 61075.129323065 189534.0757128696, 61075.23691435156 189534.17248462708, 61075.33971391682 189534.27433209817, 61075.43748257295 189534.38101831032, 61075.52999283772 189534.4922950325, 61075.617029463814 189534.60790335273, 61075.698389939666 189534.72757428052, 61115.69838993968 189596.72757428052, 61115.73932238356 189596.79284437196, 61154.73932238355 189660.79284437196, 61154.81283661879 189660.9204274646, 61154.887943156966 189661.06807081055, 61154.954785990725 189661.21963460982, 61155.013161327035 189661.37465676886, 61155.0628911889 189661.53266465006, 61155.10382395798 189661.69317651284, 61155.13583483687 189661.85570298243, 61155.15882622955 189662.0197485418, 61155.17272803897 189662.18481304243, 61155.17474045783 189662.24794254772, 61183.07017699934 189620.85471413127, 61227.97702224076 189528.04723396568, 61228.08206328367 189527.84935426293, 61228.20157821125 189527.65986500322, 61267.20157821126 189470.65986500322, 61267.29289219745 189470.53357457014, 61267.39064131739 189470.41219653623, 61267.494561784035 189470.29605845385, 61267.60437315624 189470.18547373475, 61358.60437315624 189383.18547373475, 61358.715044196215 189383.08482723264, 61431.93739366621 189319.75738985318, 61435.73575796793 189300.7655683446, 61449.703685540335 189230.92593048254, 61460.68572377567 189107.1284085569, 61469.683262185674 188962.16806750666, 61469.6959880664 188962.02137108453, 61469.71516623603 188961.88001939777, 61469.74104194656 188961.7397391456, 61469.773556695596 188961.6008474877, 61469.812636970535 188961.4636584442, 61469.85819441478 188961.32848218587, 61469.91012602749 188961.1956243327, 61469.96831439649 188961.0653852631, 61470.03262796366 188960.93805943453, 61470.10292132246 188960.813934718, 61470.17903554663 188960.69329174713, 61470.26079854949 188960.5764032836, 61470.34802547307 188960.46353360056, 61470.44051910599 188960.35493788513, 61470.53807032939 188960.25086166133, 61470.64045858969 188960.15154023518, 61470.74745239725 188960.05719816245, 61470.85880984975 188959.96804874117, 61470.97427917912 188959.88429352926, 61471.09359932072 188959.80612188895, 61471.21650050362 188959.73371055844, 61471.34270486053 188959.6672232526, 61471.47192705598 188959.60681029252, 61471.603874931505 188959.55260826592, 61471.73825016611 188959.50473971813, 61471.87474895082 188959.4633128752, 61472.0130626755 188959.42842139903, 61472.152878626635 188959.40014417583, 61472.293880694306 188959.37854513756, 61472.43575008692 188959.36367311745, 61472.57816605194 188959.3555617397, 61472.7208066011 188959.3542293433, 61472.86334923834 188959.35967894067, 61473.00547168899 188959.3718982108, 61473.146852628386 188959.3908595272, 61473.28717240833 188959.41652002017, 61473.42611377982 188959.4488216739, 61473.563362610264 188959.4876914576, 61473.69860859377 188959.5330414905, 61473.83154595267 188959.5847692408, 61473.96187412887 188959.6427577572, 61474.089298463376 188959.7068759334, 61474.21353086247 188959.77697880464, 61474.33429044912 188959.85290787532, 61474.45130419795 188959.9344914774, 61474.56430755255 188960.0215451585, 61474.67304502362 188960.11387209894, 61474.77727076659 188960.2112635567, 61474.87674913747 188960.31349933942, 61474.97125522558 188960.42034830223, 61475.0605753621 188960.53156887027, 61475.14450760311 188960.64690958496, 61475.2228621862 188960.7661096724, 61475.295461959475 188960.88889963317, 61475.36214278209 188961.0150018514, 61475.42275389537 188961.14413122254, 61475.47715826364 188961.27599579797, 61475.52523288405 188961.41029744508, 61475.56686906468 188961.54673252124, 61475.60197267029 188961.68499256033, 61475.63046433512 188961.82476497028, 61475.65227964237 188961.96573373955, 61475.6673692698 188962.10758015187, 61475.67569910128 188962.24998350666, 61475.67725030389 188962.3926218441, 61475.671737804325 188962.53976599334, 61466.671737804325 189107.53976599334, 61466.66576509945 189107.61900478345, 61455.66576509945 189231.61900478345, 61455.64690573724 189231.7812685231, 61455.61924202207 189231.9422651554, 61441.61924202206 189301.9422651554, 61437.61924202207 189321.9422651554, 61437.560717663764 189322.18280508657, 61437.4825603362 189322.41770078932, 61437.385302243514 189322.64535276583, 61437.26960565454 189322.86421084384, 61437.13625839308 189323.0727847321, 61436.98616847339 189323.26965416857, 61436.82035791708 189323.45347859137, 61436.63995579379 189323.62300626736, 61362.69654636404 189387.5740630715, 61271.97675992616 189474.306166589, 61233.28019388411 189530.86268618895, 61188.377977749245 189623.6605995343, 61188.27822239719 189623.84932404791, 61188.165299277774 189624.03047713623, 61157.165299277774 189670.03047713623, 61157.08003769557 189670.1505281708, 61156.99191895289 189670.26270298407, 61156.89856753999 189670.37056222223, 61156.8001945151 189670.47386202627, 61156.6970222898 189670.5723688457, 61156.58928412621 189670.66585996636, 61156.47722360954 189670.75412401423, 61156.36109409744 189670.83696143312, 61156.24115814715 189670.9141849358, 61156.117686921876 189670.98561992773, 61155.99095957773 189671.0511049015, 61155.861262632585 189671.1104918021, 61155.7288893183 189671.1636463617, 61155.5941389177 189671.21044840314, 61155.45731608801 189671.25079211168, 61155.31873017198 189671.2845862742, 61155.178694498536 189671.31175448553, 61155.03752567435 189671.332235321, 61154.89554286805 189671.34598247547, 61154.753067088575 189671.35296486807, 61154.610420459445 189671.35316671224, 61154.46792549045 189671.34658755167, 61154.32590434849 189671.33324226114, 61154.18467812918 189671.3131610131, 61154.04456613092 189671.28638920916, 61153.90588513293 189671.25298737775, 61153.76894867913 189671.21303103704, 61153.634066369144 189671.16661052438, 61153.501543158425 189671.11383079187, 61153.37167866872 189671.05481116922, 61153.24476651068 189670.98968509393, 61153.121093620015 189670.91859980952, 61153.00093960879 189670.84171603277, 61152.880888574204 189670.75645445054, 61152.76516573389 189670.6654049446, 61152.65404987431 189670.56878686108, 61152.54780868331 189670.4668329615, 61152.44669810522 189670.3597888617, 61152.35096172427 189670.24791244027, 61152.2608301778 189670.13147321733, 61152.176520600595 189670.01075170518, 61152.0982361018 189669.88603873248, 61152.02616527566 189669.75763474376, 61151.960481747075 189669.6258490754, 61151.90134375344 189669.49099921068, 61151.848893763345 189669.3534100147, 61151.80325813342 189669.21341295194, 61151.7645468039 189669.07134528752, 61151.732853033755 189668.9275492749, 61151.70825317607 189668.7823713313, 61151.690806494036 189668.6361612031, 61151.680555018254 189668.48927112325, 61151.67752344542 189668.3420549629, 61151.681719078864 189668.19486737862, 61151.693131810935 189668.0480629582, 61151.71173414736 189667.90199536635, 61151.73748127348 189667.75701649272, 61151.77031116222 189667.61347560407, 61151.81014472349 189667.471718503, 61151.85688599476 189667.33208669478, 61151.910422372224 189667.19491656468, 61151.970624882044 189667.06053856752, 61152.0373484911 189666.92927643168, 61152.110432456386 189666.8014463792, 61152.18970071222 189666.67735636377, 61152.18970071243 189666.67735636348, 61153.20358343896 189665.17288522088, 61153.069353922336 189665.21832158652, 61152.838278372146 189665.28027885297, 61152.603000667004 189665.3236264506, 61152.365017032294 189665.34808871476, 61152.12584090146 189665.35351008002, 61151.88699329155 189665.33985606974, 61151.64999313038 189665.30721351525, 61151.41634759711 189665.2557900037, 61151.187542537475 189665.1859125578, 61150.9650330147 189665.09802555628, 61150.750234056155 189664.99268790788, 61150.544511654654 189664.870569497, 61150.349174081515 189664.73244692362, 61150.16546356678 189664.5791985646, 61149.994548399365 189664.41179898783, 61149.83751549742 189664.2313127544, 61149.695363496205 189664.03888764867, 61149.61567760644 189663.91506540801, 61110.635724742686 189599.9479632726, 61070.97439685024 189538.47290503932, 61042.95422274771 189518.80962496737, 61042.92581987731 189518.7894459627, 60912.92581987731 189425.2894459627, 60912.80842596995 189425.2005614375, 60912.61398543583 189425.0315470612, 60912.434762858604 189424.8464734312, 60912.27207996457 189424.646705424, 60912.12713650357 189424.43371628385, 60912.1165193226 189424.41559721052, 60912.108172554355 189424.4107519848, 60911.92433505254 189424.288377344, 60911.74999810346 189424.15281035696, 60911.74999810345 189424.15281035696, 60911.74999810345 189424.15281035696, 60846.77060252474 189369.67008637174, 60763.71785563127 189302.53163828418, 60676.238535646495 189273.70322601649, 60676.15295127244 189273.67267393367, 60660.67352476382 189470.06789776185, 60657.675797115735 189559.0004846551, 60657.65783251668 189559.2423733553, 60657.62038552695 189559.4820201643, 60618.62038552695 189756.4820201643, 60618.59410654658 189756.601847263, 60572.68891602897 189947.20818180352, 60576.655528667136 190071.16482674598, 60625.3766243306 190171.5899422972, 60625.44066351826 190171.73111740986, 60625.49732462027 190171.87541207197, 60625.546456342505 190172.02244099384, 60625.58792749544 190172.17181158488, 60643.58792749543 190244.17181158488, 60643.620123735236 190244.315495928, 60643.64786768928 190244.4788049072, 60643.66655547089 190244.64339626938, 60643.676130104024 190244.80876820194, 60643.67656239717 190244.97441651253, 60643.667851032355 190245.13983616614, 60643.6500225691 190245.30452282494, 60643.62313136353 190245.46797438577, 60643.58725940259 190245.62969251123, 60643.56159859406 190245.7222537224, 60720.90013694986 190256.3563027463, 60806.41859266947 190257.35070339422, 60875.802060992675 190244.4652021342, 60952.495742099265 190211.59648165994, 60952.68657846687 190211.52229627312, 60952.88203054594 190211.4613005716, 61032.88203054594 190189.4613005716, 61033.053279583306 190189.4195771518, 61033.226683365494 190189.3879827712, 61033.40164332043 190189.3666264904, 61033.5775555043 190189.35558202906, 61093.57755550429 190187.35558202906, 61093.724797203424 190187.3542896108, 61093.867332464644 190187.35992883527, 61094.0094385336 190187.37233716753, 61094.15079412265 190187.39148655356, 61094.291079640934 190187.41733369854, 61094.42997791689 190187.44982016465, 61094.56717491538 190187.48887250322, 61094.702360447685 190187.5344024208, 61094.83522887283 190187.58630697883, 61094.965479788545 190187.64446882627, 61095.09281871053 190187.70875646497, 61095.21695773819 190187.77902454702, 61095.33761620557 190187.8551142033, 61095.45452131593 190187.93685340267, 61095.56740875848 190188.024057341, 61095.676023305976 190188.11652885887, 61095.78011939178 190188.21405888736, 61095.87946166503 190188.3164269209, 61095.97382552276 190188.42340151552, 61096.062997617715 190188.53474081238, 61096.14677634068 190188.65019308444, 61096.22497227634 190188.76949730562, 61096.29740863148 190188.89238374098, 61096.36392163473 190189.01857455657, 61096.424360906836 190189.14778444756, 61096.47858980064 190189.2797212833, 61096.52648571001 190189.41408676773, 61096.5679403471 190189.55057711393, 61096.602859987106 190189.68888373085, 61096.6311656802 190189.82869392104, 61096.65279343003 190189.9696915876, 61096.66769433844 190190.11155794893, 61096.675834715934 190190.2539722593, 61096.67712713417 190190.40121395842, 61096.671193187896 190190.54834171443, 61096.6580471725 190190.69500108366, 61096.63772075789 190190.84083875088, 61096.61026291218 190190.98550338033, 61096.57573978372 190191.12864646228, 61096.53423454176 190191.2699231525, 61096.485847176045 190191.40899310305, 61096.43069425599 190191.54552128224, 61096.36890864982 190191.67917878175, 61096.30063920445 190191.80964360895, 61096.22605038697 190191.93660146266, 61096.14532188836 190192.05974649024, 61096.058648190665 190192.17878202457, 61095.966238098394 190192.29342129861, 61095.868314235566 190192.40338813633, 61095.76511250934 190192.50841761797, 61095.65688154171 190192.6082567183, 61095.54388207057 190192.70266491617, 61095.426386321524 190192.791414774, 61095.30467735214 190192.87429248556, 61095.17904836997 190192.95109839126, 61095.04980202625 190193.02164745887, 61094.91724968674 190193.08576972954, 61094.78171068163 190193.14331072712, 61094.64351153626 190193.19413183027, 61094.502985184474 190193.23811060653, 61094.36047016656 190193.27514110715, 61094.21630981369 190193.30513412243, 61094.070851420765 190193.32801739656, 61093.9244454098 190193.34373580173, 61093.777444485706 190193.35225147093, 61093.7774444857 190193.35225147093, 61034.13144788302 190195.34045135768, 60954.67073476642 190217.19214746475, 60877.859257890734 190250.11135184005, 60877.704993993066 190250.17247242338, 60877.54758675427 190250.2249703948, 60877.38751771939 190250.26868515092, 60877.22527657653 190250.30348295823, 60807.22527657652 190263.30348295823, 60807.08070580639 190263.32669744722, 60806.93517452743 190263.34283023744, 60806.78902942135 190263.3518428977, 60806.642618632104 190263.35371395823, 60720.64261863211 190262.35371395823, 60720.45529784601 190262.3456764671, 60720.268844973565 190262.32595326952, 60640.268844973565 190251.32595326952, 60640.123506296404 190251.30232156988, 60639.979502238595 190251.27158690477, 60639.83717971851 190251.2338233167, 60639.69688160358 190251.18912178144, 60639.558945884244 190251.13758998894, 60639.423704859735 190251.0793520838, 60639.291484337526 190251.0145483662, 60639.16260284843 190250.943334954, 60639.03737087926 190250.86588340654, 60638.91609012478 190250.7823803114, 60638.799052760965 190250.6930268348, 60638.686540741066 190250.59803823716, 60638.5788251164 190250.49764335426, 60638.476165383334 190250.39208404624, 60638.378808858164 190250.28161461465, 60638.28699008129 190250.16650119008, 60638.20093025218 190250.0470210908, 60638.12083669649 190249.9234621549, 60638.04690236664 190249.79612204662, 60637.97930537687 190249.66530753946, 60637.91820857429 190249.53133377703, 60637.863759146414 190249.39452351385, 60637.81608826671 190249.25520633784, 60637.775310778474 190249.11371787626, 60637.74152491827 190248.9703989872, 60637.71481207918 190248.82559493845, 60637.69523661479 190248.67965457562, 60637.682845684096 190248.53292948185, 60637.677669137935 190248.38577313072, 60637.679719447064 190248.2385400348, 60637.688991672105 190248.09158489146, 60637.70546347546 190247.94526172857, 60637.73254991943 190247.78184240832, 60637.768615041605 190247.62016725054, 60637.81354888525 190247.46072917673, 60637.867214454316 190247.30401428792, 60637.92944813112 190247.15050038253, 60638.00006017523 190247.0006554997, 60638.07883530189 190246.85493649237, 60638.165533338426 190246.71378763427, 60638.225620326775 190246.62651667424, 60638.182327628296 190246.56498588898, 60638.06656166486 190246.37691669562, 60637.964944602456 190246.18084081128, 60637.87802711275 190245.97782078822, 60637.80628020913 190245.7689568095, 60637.767072494564 190245.62702533512, 60619.84254592032 190173.92891903815, 60570.978375659404 190073.2088946228, 60570.91342133579 190073.06555274286, 60570.856073129726 190072.91900192588, 60570.80648885046 190072.76964544645, 60570.764804942686 190072.6178942997, 60570.73113611107 190072.46416607042, 60570.7055750046 190072.30888378381, 60570.68819196163 190072.1524747415, 60570.67903481636 190071.9953693457, 60566.679034816356 189946.9953693457, 60566.67934702159 189946.7941628283, 60566.69314563849 189946.593429776, 60566.72036859757 189946.39407313423, 60566.76089344342 189946.196989657, 60612.74652871619 189755.25663450267, 60651.68739433454 189558.55533894332, 60654.67920287427 189469.79835226492, 60654.68677515548 189469.66369630516, 60670.68677515548 189266.66369630516, 60670.71024442527 189266.45738409043, 60670.74792867461 189266.25318949227, 60684.868304973985 189202.2408169351, 60649.976653451915 189198.84857303713, 60582.56646501348 189196.35189939127, 60582.38620010214 189196.33977879176, 60520.88620010214 189190.33977879176, 60520.79493476738 189190.32946221592, 60454.13059572534 189181.7583329105, 60431.62451569427 189299.91525307368, 60431.58687452865 189300.08572261428, 60390.61267479463 189462.9831508251, 60374.63118751836 189552.87901675416, 60374.5927868484 189553.06180273124, 60374.54308609742 189553.24184483808, 60330.58889119209 189695.09401930528, 60310.619242022076 189794.9422651554, 60310.56096064497 189795.1819594301, 60310.48318384944 189795.41605521034, 60310.3864374936 189795.64296974684, 60310.271375690994 189795.8611688436, 60267.444964801754 189869.56243409484, 60252.54609986153 189918.23205956627, 60252.48893559549 189918.40073567626, 60252.421862773466 189918.56572240283, 60252.34511778533 189918.7264382707, 60252.258971109244 189918.8823168568, 60252.16372635849 189919.0328087863, 60252.059719211386 189919.17738366913, 60251.9473162282 189919.315531969, 60251.826913559315 189919.44676679946, 60215.17751919758 189957.08668533314, 60126.39163056355 190145.63199939867, 60126.34763008958 190145.7215443594, 60084.34763008958 190227.7215443594, 60084.34763008957 190227.7215443594, 60084.34763008957 190227.7215443594, 60084.27730749479 190227.85091406596, 60084.20072173604 190227.97667737483, 60084.11805731509 190228.09853131123, 60084.0295133778 190228.21618231834, 60083.935303234255 190228.3293469646, 60083.835653844944 190228.43775262643, 60083.730805273975 190228.5411381451, 60083.62101011075 190228.63925445586, 60083.506532861415 190228.73186518793, 60083.387649311706 190228.81874723392, 60083.2646458625 190228.89969128737, 60083.13781883988 190228.974502347, 60083.00747378126 190229.04300018636, 60082.87392469929 190229.1050197882, 60082.73749332542 190229.16041174188, 60082.59850833477 190229.20904260327, 60082.45730455436 190229.25079521642, 60082.314222156456 190229.28556899558, 60082.1696058391 190229.31328016773, 60082.02380399566 190229.33386197416, 60081.87716787555 190229.34726483157, 60081.730050738035 190229.35345645124, 60081.58280700117 190229.35242191705, 60081.435791388016 190229.34416372128, 60081.28935807208 190229.32870175864, 60081.14385982402 190229.30607327833, 60080.99964716188 190229.2763327944, 60080.85706750659 190229.23955195423, 60080.71646434502 190229.1958193661, 60080.578176402516 190229.14524038564, 60080.44253682683 190229.08793686208, 60080.30987238559 190229.02404684457, 60080.18449249353 190228.9560175552, 60080.06248814239 190228.8821051757, 60079.94413517181 190228.80247681454, 60079.82970116607 190228.71731250352, 60079.71944484902 190228.62680479063, 60079.61361549918 190228.53115830477, 60079.512452386145 190228.43058929313, 60079.41618422963 190228.32532513217, 60079.32502868231 190228.21560381365, 60079.23919183779 190228.10167340655, 60079.1588677646 190227.98379149608, 60079.084238067444 190227.86222460156, 60079.01547147663 190227.73724757356, 60078.95272346655 190227.60914297265, 60078.89613590419 190227.47820043055, 60078.84583672838 190227.3447159953, 60078.80193966054 190227.20899146184, 60078.764543947545 190227.07133368985, 60078.73373413738 190226.93205390975, 60078.709579887945 190226.79146701927, 60078.69213580959 190226.6498908713, 60078.681441341636 190226.5076455554, 60078.6775206632 190226.365052674, 60078.68038263856 190226.2224346154, 60078.690020797054 190226.08011382478, 60078.70641334778 190225.93841207522, 60078.72952322882 190225.79764974027, 60078.75929819104 190225.65814506952, 60078.79567091622 190225.52021346905, 60078.83855916925 190225.38416678848, 60078.88786598408 190225.25031261577, 60078.943479882924 190225.1189535818, 60079.00736990042 190224.9862891406, 60079.373685678154 190224.2711011936, 60079.30964906861 190224.2865584855, 60079.05570531084 190224.3299813896, 60078.79897237373 190224.35145648473, 60078.54134360507 190224.35082539686, 60078.28471895924 190224.3280927801, 60078.03099098543 190224.28342628243, 60077.782030870505 190224.21715530925, 60077.53967463946 190224.1297685941, 60077.30570961513 190224.0219105944, 60077.17644974366 190223.95138631537, 59878.17834016806 190108.95247877168, 59720.18023221716 190017.95356849616, 59719.996396291266 190017.83864819165, 59719.821339896596 190017.7107514258, 59719.655977261755 190017.5705461369, 59719.50117198986 190017.41876454436, 59719.35773254842 190017.25619932462, 59719.22640804712 190017.08369947132, 59719.10788432559 190016.90216586154, 59719.00278037166 190016.71254655108, 59718.91164508866 190016.51583182305, 59718.83495442883 190016.31304901626, 59718.77310890765 190016.10525715994, 59718.726431512136 190015.89354144305, 59718.69516601407 190015.67900754674, 59718.67947569691 190015.4627758701, 59718.67944250304 190015.24597567884, 59718.6950666058 190015.0297392077, 59723.695066605804 189969.0297392077, 59723.726551861335 189968.81363431242, 59723.77367473108 189968.60039247264, 59764.457612300925 189811.8183891547, 59744.575488585404 189778.6815162955, 59664.40333936084 189741.06989073337, 59664.27160761622 189741.00409912472, 59664.14721920509 189740.93427345093, 59664.02629060607 189740.85861384822, 59663.909095226634 189740.77729137545, 59663.795898033844 189740.69048989454, 59663.68695495524 189740.598405655, 59663.58251230027 189740.50124685012, 59663.48280620334 189740.39923314625, 59663.38806208997 189740.2925951862, 59663.29849416716 189740.18157406774, 59663.214304939036 189740.0664207985, 59663.13568474903 189739.9473957286, 59663.06281134955 189739.8247679618, 59662.995849500076 189739.69881474724, 59662.93495059467 189739.56982085257, 59662.880252319665 189739.43807792012, 59662.83187834242 189739.30388380747, 59662.789938031645 189739.16754191415, 59662.754526210214 189739.02936049554, 59662.72572294072 189738.88965196608, 59662.703593344464 189738.74873219273, 59662.68818745427 189738.60691978113, 59662.67954010131 189738.4645353549, 59662.67767083639 189738.32190083107, 59662.682583885726 189738.17933869202, 59662.69426814141 189738.03717125652, 59662.71269718649 189737.895719951, 59662.737829354766 189737.75530458268, 59662.769607824885 189737.6162426167, 59662.80796074891 189737.4788484583, 59662.852801414716 189737.34343274197, 59662.904028442026 189737.2103016291, 59662.96152601164 189737.07975611583, 59663.0251641273 189736.95209135258, 59663.09479890958 189736.8275959766, 59663.17027292118 189736.7065514595, 59663.251415522915 189736.5892314709, 59663.338043259435 189736.47590125952, 59663.4299602741 189736.3668170537, 59663.526958751696 189736.26222548194, 59663.62881938837 189736.16236301532, 59663.735311887365 189736.0674554329, 59663.8461954798 189735.97771731127, 59663.96121946892 189735.89335153936, 59664.08012379697 189735.81454885975, 59664.20263963314 189735.74148743745, 59664.328489981366 189735.674332457, 59664.45739030656 189735.6132357492, 59664.58904917795 189735.55833544748, 59664.72316892799 189735.50975567603, 59664.859446325296 189735.46760626885, 59664.99757326028 189735.43198252152, 59665.13723744175 189735.4029649758, 59665.27812310291 189735.38061923746, 59665.41991171535 189735.36499582796, 59665.56228270918 189735.3561300703, 59665.70491419779 189735.354042009, 59665.84748370563 189735.35873636507, 59665.98966889726 189735.370202525, 59666.13114830617 189735.3884145649, 59666.27160206153 189735.41333130922, 59666.41071261144 189735.44489642364, 59666.54816544081 189735.48303854265, 59666.68364978252 189735.52767143067, 59666.81685932001 189735.5786941772, 59666.95166062918 189735.63794276663, 59747.95166062918 189773.63794276663, 59748.14888207247 189773.73952680547, 59748.33805740761 189773.85540737852, 59748.518152147895 189773.98495080427, 59748.68818146296 189774.12744868727, 59748.84721556421 189774.28212179182, 59748.994384789316 189774.4481243033, 59749.12888435785 189774.6245484533, 59749.249978772146 189774.8104294837, 59770.24997877215 189809.8104294837, 59770.32340367931 189809.9399882888, 59770.39030887371 189810.0730311237, 59770.450529495756 189810.20923016057, 59770.503917157126 189810.34824979436, 59770.55034030648 189810.48974746984, 59770.58968455355 189810.63337452573, 59770.62185295106 189810.77877705378, 59770.64676623356 189810.92559677083, 59770.664363012795 189811.07347190168, 59770.67459992892 189811.2220380705, 59770.67745175738 189811.37092919863, 59770.67291147105 189811.51977840674, 59770.660990257544 189811.66821891884, 59770.64171749166 189811.81588496594, 59770.615140663 189811.96241268734, 59770.581325258936 189812.10744102736, 59729.63628770747 189969.89563451835, 59724.8715188801 190013.73150773015, 59881.17476777286 190103.75426500384, 59881.17855024635 190103.75644718463, 60080.17855024634 190218.75644718463, 60080.30419395628 190218.83322899535, 60080.485219653165 190218.9597259394, 60080.65644916059 190219.0991972109, 60080.81695457103 190219.2508870029, 60080.965866091756 190219.41397329533, 60081.10237675833 190219.58757230942, 60081.22574680763 190219.7707432971, 60081.33530768666 190219.96249363886, 60081.43046567554 190220.16178422302, 60081.45163356769 190220.21415531402, 60120.984625057856 190143.03069573798, 60209.963369426456 189954.07583410133, 60210.0786600947 189953.85524027637, 60210.21184047624 189953.64496293623, 60210.361993793216 189953.44644957347, 60210.528086430684 189953.26106670054, 60247.02147158637 189915.78137383793, 60261.808900128475 189867.47577393372, 60261.86393146853 189867.31284415556, 60261.92820837015 189867.15333540685, 60262.00151961541 189866.99777184328, 60262.083624299004 189866.8466646564, 60304.833422862204 189793.27724387322, 60324.73575796794 189693.7655683446, 60324.769974931056 189693.61479700156, 60324.81191389257 189693.46598866192, 60368.75655212964 189551.64465616958, 60384.72381247164 189461.82881674584, 60384.768125461356 189461.6221108857, 60425.74682383963 189298.70679782084, 60448.438343772024 189179.57631817576, 60448.42864439893 189179.5555342307, 60448.35386413952 189179.36740471888, 60448.29194234144 189179.17466009167, 60448.243160988306 189178.97817808233, 60448.207742223894 189178.77885344377, 60448.18584734054 189178.57759387387, 60448.17757604462 189178.3753158818, 60448.18296600251 189178.17294061463, 60448.20199266908 189177.97138966236, 60448.241937621846 189177.73551042736, 60448.300550994136 189177.50356412894, 60448.37746003998 189177.27702580675, 60448.47217566388 189177.05733610888, 60448.58409553118 189176.8458921303, 60448.7125078985 189176.64403852823, 60448.856596140045 189176.45305897066, 60449.015443940865 189176.27416797332, 60449.07937781878 189176.2108894303, 60449.73048429573 189172.79258042632, 60449.761577573125 189172.64865337394, 60449.79839891392 189172.5108408549, 60449.84172961483 189172.37493444627, 60449.89147170949 189172.24124141893, 60449.94751273598 189172.11006403944, 60450.00972599112 189171.98169888672, 60450.07797081697 189171.85643618164, 60450.15209291878 189171.73455913062, 60450.23192471389 189171.6163432855, 60450.31728571057 189171.50205592054, 60450.40798291613 189171.39195542806, 60450.503811273236 189171.28629073428, 60450.60455412355 189171.18530073648, 60450.70998369755 189171.089213763, 60450.81986162947 189170.9982470569, 60450.933939496295 189170.9126062848, 60451.05195937935 189170.83248507197, 60451.17365444746 189170.75806456446, 60451.29874956023 189170.68951301958, 60451.42696189009 189170.62698542557, 60451.55800156177 189170.57062315103, 60451.691572307645 189170.52055362548, 60451.8273721376 189170.47689005113, 60451.965094021776 189170.4397311469, 60452.10442658473 189170.4091609254, 60452.245054809464 189170.38524850286, 60452.38666074959 189170.36804794287, 60452.52892424822 189170.35759813417, 60452.671523661775 189170.35392270278, 60452.81413658722 189170.3570299584, 60452.95644059098 189170.3669128759, 60453.09811393789 189170.38354911096, 60453.23883631867 189170.40690105074, 60453.37828957406 189170.4369158988, 60453.51615841417 189170.4735257946, 60453.65213113131 189170.5166479668, 60453.78590030475 189170.5661849205, 60453.917163495746 189170.62202465752, 60454.04562393131 189170.6840409299, 60454.17099117524 189170.75209352493, 60454.2929817847 189170.82602858255, 60454.41131995111 189170.90567894297, 60454.52573812368 189170.99086452465, 60454.63597761435 189171.08139273155, 60454.74178918263 189171.17705888834, 60454.84293359914 189171.27764670347, 60454.93918218644 189171.38292875793, 60455.03031733608 189171.49266701943, 60455.1161330006 189171.6066133808, 60455.196435159334 189171.72451022064, 60455.27104225712 189171.846090986, 60455.339785614764 189171.97108079487, 60455.402509810396 189172.09919705777, 60455.45907303087 189172.23015011667, 60455.509347392384 189172.36364389973, 60455.55321922964 189172.49937659086, 60455.590589352774 189172.63704131197, 60455.621373271686 189172.7763268169, 60455.64550138701 189172.916918195, 60455.662919147464 189173.0584975832, 60455.67358717325 189173.20074488464, 60455.677481345025 189173.34333849238, 60455.67459285845 189173.4859560165, 60455.6649282441 189173.62827501303, 60455.648509352715 189173.76997371292, 60455.62451569427 189173.91525307368, 60455.255316043345 189175.85355124102, 60521.51451152656 189184.37259066026, 60582.87885000288 189190.35935538966, 60650.28853497653 189192.8560103887, 60650.46779791718 189192.8680334047, 60686.200562400765 189196.34205217395, 60717.716711466164 189063.3832983043, 60724.696439822284 189001.56284715017, 60724.720312065685 189001.39440405357, 60724.753694284016 189001.227585025, 60724.7964791239 189001.06292653517, 60724.84852899425 189000.9009581068, 60736.6305148451 188967.5186648627, 60733.6898203756 188935.17102569813, 60733.686805549034 188935.13552591627, 60730.68680554904 188897.13552591627, 60730.6785592209 188896.97913190577, 60730.67848570227 188896.82252065762, 60731.67848570227 188857.82252065762, 60731.69221378638 188857.6026588727, 60731.72203842254 188857.38439720438, 60731.7677987974 188857.16891251152, 60731.82924817275 188856.95736667953, 60731.906055215826 188856.75090035563, 60731.997805785926 188856.5506267986, 60732.10400516739 188856.35762587594, 60732.224080737105 188856.17293824148, 60750.89827384525 188829.63592698253, 60798.74530939089 188634.2605318378, 60811.73086424966 188566.3360910381, 60811.74679994281 188566.2583278236, 60818.644504680764 188534.72596330725, 60811.69634015666 188466.23691299828, 60801.700666364864 188386.27152266377, 60801.68518261506 188386.11398010084, 60801.67803060915 188385.9558401171, 60801.67923026103 188385.79754303413, 60801.688778230404 188385.6395296109, 60805.5729914693 188340.97107736368, 60749.68613690176 188281.16233826507, 60699.924585817454 188245.33402148436, 60699.78012860812 188245.22320455607, 60699.6426596868 188245.1038287939, 60686.96861829046 188233.40471365882, 60619.36770573588 188200.5983884485, 60619.23685126001 188200.5308688628, 60619.11339257256 188200.45941220436, 60618.993470175854 188200.38216765563, 60618.87735520246 188200.2993098588, 60618.76531017673 188200.2110261471, 60618.65758842129 188200.11751612116, 60618.55443348426 188200.01899119787, 60618.456078588686 188199.91567413218, 60618.362746105144 188199.80779851374, 60618.27464704907 188199.6956082385, 60618.19198060363 188199.57935695743, 60618.11493366941 188199.4593075032, 60618.043680441835 188199.3357312955, 60617.97838201734 188199.20890772788, 60617.91918602914 188199.07912353578, 60617.86622631346 188198.94667214825, 60617.81962260693 188198.81185302467, 60617.77948027587 188198.67497097765, 60617.7458900781 188198.53633548378, 60617.71892795769 188198.39625998412, 60617.698654873304 188198.25506117535, 60617.68511666037 188198.11305829394, 60617.67834392742 188197.97057239417, 60617.67835198695 188197.82792562246, 60617.685140820715 188197.68544048895, 60617.69869507985 188197.54343913824, 60617.718984119536 188197.40224262123, 60617.74596206827 188197.26217016918, 60617.779567931604 188197.1235384719, 60617.819725730034 188196.9866609618, 60617.866344670794 188196.8518471053, 60617.91931935311 188196.71940170304, 60617.978530006505 188196.5896242009, 60618.04384276161 188196.4628080128, 60618.115109952814 188196.3392398575, 60618.192170452094 188196.2191991103, 60618.27485003337 188196.10295717127, 60618.362961766354 188195.99077685192, 60618.45630643921 188195.88291178067, 60618.55467300897 188195.77960582977, 60618.657839078616 188195.68109256355, 60618.76557139998 188195.58759471076, 60618.87762640103 188195.49932366068, 60618.9937507366 188195.41647898534, 60619.11368186115 188195.3392479883, 60619.23714862239 188195.2678052811, 60619.363871874295 188195.20231238857, 60619.49356510824 188195.14291738367, 60619.62593510078 188195.0897545525, 60619.76068257657 188195.0429440909, 60619.89750288502 188195.00259183274, 60620.03608668906 188194.9687890104, 60620.17612066456 188194.94161204866, 60620.31728820867 188194.92112239194, 60620.459270155676 188194.90736636534, 60620.601745498556 188194.90037506982, 60620.74439211479 188194.900164312, 60620.88688749463 188194.90673456842, 60621.028909470224 188194.92007098434, 60621.17013694408 188194.9401434075, 60621.31025061497 188194.9669064561, 60621.44893369988 188195.00029962164, 60621.5858726502 188195.0402474054, 60621.72075786062 188195.08665948955, 60621.85328436915 188195.1394309409, 60621.98729425412 188195.2004484715, 60689.98729425412 188228.2004484715, 60690.1816977584 188228.30377035428, 60690.368000633935 188228.42107070598, 60690.54519957487 188228.55171782334, 60690.7123403032 188228.69500812612, 60698.201394974676 188235.60798166902, 60735.67856422794 188175.89859336722, 60735.57762573145 188175.89770974102, 60735.35732498767 188175.88223841027, 60735.1387593 188175.85060267165, 60734.92311309483 188175.802973962, 60734.71155497764 188175.73961038544, 60734.57335464197 188175.6887925192, 60638.57335464198 188137.6887925192, 60638.43781428919 188137.63125469626, 60638.3093543577 188137.56923737976, 60638.18398766691 188137.50118376574, 60638.061997658406 188137.42724771655, 60637.94366013941 188137.34759639428, 60637.82924265924 188137.2624098826, 60637.7190039044 188137.17188077967, 60637.613193113706 188137.0762137628, 60637.512049514786 188136.97562512557, 60637.41580178324 188136.8703422888, 60637.32466752556 188136.76060328653, 60637.23885278722 188136.64665622768, 60637.15855158676 188136.52875873513, 60637.0839454772 188136.40717736335, 60637.01520313549 188136.28218699573, 60636.9524799812 188136.15407022298, 60636.89591782513 188136.02311670434, 60636.845644548666 188135.88962251265, 60636.80177381467 188135.75388946495, 60636.764404810485 188135.61622444008, 60636.7336220237 188135.47693868497, 60636.709495051124 188135.33634711074, 60636.69207844143 188135.19476758098, 60636.68141157185 188135.05252019284, 60636.677518559096 188134.90992655343, 60636.680408204884 188134.7673090528, 60636.69007397601 188134.62499013482, 60636.706494019134 188134.4832915684, 60636.72963121018 188134.34253371984, 60636.75943323827 188134.20303482856, 60636.79583272399 188134.0651102877, 60636.83874737174 188133.92907193076, 60636.888080155775 188133.79522732698, 60636.94371953961 188133.66387908562, 60637.00553972814 188133.5353241719, 60637.0734009521 188133.40985323576, 60637.147149784025 188133.28774995432, 60637.22661948518 188133.16929039103, 60637.3116303825 188133.05474237105, 60637.40199027484 188132.94436487605, 60637.497494867486 188132.83840745853, 60637.59792823411 188132.73710967766, 60637.70306330487 188132.64070055756, 60637.81266237989 188132.54939806965, 60637.92647766659 188132.46340863974, 60638.04425183997 188132.38292668134, 60638.16571862439 188132.30813415613, 60638.290603395566 188132.23920016256, 60638.4186238015 188132.17628055348, 60638.549490400845 188132.11951758387, 60638.68290731727 188132.0690395891, 60638.81857290845 188132.02496069492, 60638.956180448025 188131.98738055927, 60639.09541881909 188131.9563841471, 60639.23597321758 188131.93204153824, 60639.377525864045 188131.91440776887, 60639.51975672207 188131.90352270714, 60639.662344221884 188131.89941096315, 60639.804965987394 188131.90208183313, 60639.947299565014 188131.91152927847, 60640.089023152745 188131.9277319395, 60640.229816327694 188131.95065318357, 60640.36936077056 188131.98024118805, 60640.50734098527 188132.01642905743, 60640.64344501235 188132.05913497455, 60640.78164534802 188132.10995284078, 60736.781645348026 188170.10995284078, 60736.91718570082 188170.16749066373, 60737.14700263349 188170.2839258739, 60737.3659823139 188170.41964941745, 60737.572509816055 188170.5736603637, 60737.76506204595 188170.7448229165, 60737.9422189741 188170.93187479035, 60738.1026741079 188171.13343651974, 60738.245244126745 188171.34802163206, 60738.36887760873 188171.5740476103, 60738.37906939724 188171.59609360594, 60752.74775415015 188148.7036128132, 60718.22057120146 188129.52184450836, 60718.08593481558 188129.44238669483, 60717.95562050188 188129.35602304403, 60717.82998214336 188129.26298808606, 60717.709360924964 188129.16353446772, 60717.59408440701 188129.0579322663, 60717.484465635695 188128.94646825638, 60717.38080229298 188128.82944513083, 60717.283375888204 188128.707180679, 60680.283375888204 188079.707180679, 60680.28337588821 188079.707180679, 60680.197554781415 188079.5875289931, 60680.120110908014 188079.46773522024, 60680.04844903604 188079.34439553626, 60679.98273118583 188079.21778879984, 60679.923105938884 188079.08820125618, 60679.869708101935 188078.9559258898, 60679.822658402154 188078.8212617621, 60679.78206321422 188078.6845133352, 60679.7480143198 188078.54598978366, 60679.720588700045 188078.4060042954, 60679.699848361546 188078.26487336363, 60679.68584019613 188078.1229160713, 60679.67859587487 188077.98045336967, 60679.678131776454 188077.8378073527, 60679.68444895015 188077.6953005288, 60679.69753311347 188077.55325509165, 60679.71735468442 188077.41199219183, 60679.74386884841 188077.27183121064, 60679.77701565957 188077.13308903805, 60679.816720176255 188076.9960793563, 60679.862892630525 188076.86111193054, 60679.915428631066 188076.72849190873, 60679.974209399224 188076.59851913142, 60680.03910203756 188076.47148745417, 60680.10995983029 188076.34768408284, 60680.18662257501 188076.2273889245, 60680.26891694493 188076.11087395455, 60680.35665688067 188075.99840260166, 60680.44964401101 188075.89022915237, 60680.547668101324 188075.78659817603, 60680.65050752893 188075.68774397188, 60680.75792978415 188075.5938900395, 60680.86969199599 188075.5052485732, 60681.06620993 188075.36881062257, 60681.272974704334 188075.24846553188, 60681.488671418796 188075.14497862387, 60681.711928371384 188075.05900801334, 60681.941325781525 188074.99110042187, 60682.175404819005 188074.94168770112, 60682.412676881264 188074.91108408643, 60682.65163306 188074.89948419845)))"^^ . -_:B91b7d25689167ed9e776a0384cd8e81c . -_:B2f8e2bcb20d68d863962d0e519a69db6 "Stad Hasselt"^^ . -_:B2f8e2bcb20d68d863962d0e519a69db6 . -_:B2f8e2bcb20d68d863962d0e519a69db6 . -_:Ba478f8310eaf175a26684ef45874f850 "2021-01-08T23:00:00Z"^^ . -_:Ba478f8310eaf175a26684ef45874f850 "2021-01-15T18:00:00Z"^^ . -_:Ba478f8310eaf175a26684ef45874f850 . -_:B3f1292c5c6e3ee5f31041149291cfdf7 "https://gipod.vlaanderen.be"@nl-BE . -_:B3f1292c5c6e3ee5f31041149291cfdf7 "10590591"^^ . -_:B3f1292c5c6e3ee5f31041149291cfdf7 . - _:Bd15b39267b5705cb5f75861ec1367654 . - _:Bf61d7c2890b939bab2c987f8a7d6616c . - "Wegeniswerken Werken in opdracht van Proximus: aanleggen van ondergrondse leidingen.\nGraafwerken in de Pieter Coutereelstraat tussen de huisnummers 1-9."^^ . - . - _:Bf13648086f1c2a910e208ce8c2424b3d . - "2021-01-06T12:56:37.513Z"^^ . - _:B77e450b21365060ec31549ece2907809 . - . - "10590561"^^ . - "2021-01-06T18:05:35.99Z"^^ . - _:B90d371b504770ee2cc24ce847bad4b40 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T13:13:32.953Z"^^ . - . - . -_:B4fda10c333e39356e881e653d23ef182 "2021-01-29T06:00:00Z"^^ . -_:B4fda10c333e39356e881e653d23ef182 "2021-01-29T17:00:00Z"^^ . -_:B4fda10c333e39356e881e653d23ef182 . -_:B535b4f72e8fb8a9d05ef843e1bc26c12 "Stad Mechelen"^^ . -_:B535b4f72e8fb8a9d05ef843e1bc26c12 . -_:B535b4f72e8fb8a9d05ef843e1bc26c12 . -_:B373138be1b56ee161539c56baa213097 "Gemeente Schoten"^^ . -_:B373138be1b56ee161539c56baa213097 . -_:B373138be1b56ee161539c56baa213097 . -_:Bd0b6f4b6370626e82f760883b3925737 "Gemeente Middelkerke"^^ . -_:Bd0b6f4b6370626e82f760883b3925737 . -_:Bd0b6f4b6370626e82f760883b3925737 . - . - . - "9196966"^^ . -_:B61739fe94ac52f08fb1de62893976ac2 "2021-01-14T06:00:00Z"^^ . -_:B61739fe94ac52f08fb1de62893976ac2 "2021-01-22T18:00:00Z"^^ . -_:B61739fe94ac52f08fb1de62893976ac2 . - . - _:Bccd153013e8d39159a1386664b52baa8 . - . - . - . - "9197110"^^ . -_:Bd75e78a962b73408930a6f544ededf52 "https://gipod.vlaanderen.be"@nl-BE . -_:Bd75e78a962b73408930a6f544ededf52 "10590402"^^ . -_:Bd75e78a962b73408930a6f544ededf52 . -_:B9592d18b6010115929a60f7555da0727 " POLYGON ((130550.011979021 191518.662781236, 130550.151491968 191520.657909336, 130535.188031214 191521.704256442, 130535.048518267 191519.709128342, 130550.011979021 191518.662781236))"^^ . -_:B9592d18b6010115929a60f7555da0727 . -_:Bc34e5290f4708df2f180355fc667f24a "Politiezone Leuven"^^ . -_:Bc34e5290f4708df2f180355fc667f24a . -_:Bc34e5290f4708df2f180355fc667f24a . -_:B082b3c66d0399557d861cff7107a5f9c "Gemeente Ingelmunster"^^ . -_:B082b3c66d0399557d861cff7107a5f9c . -_:B082b3c66d0399557d861cff7107a5f9c . -_:Bbaebd7be7fcd9a575668040e5b3ff7af " POLYGON ((71901.6536408741 178403.966108146, 71903.494650581 178404.747570403, 71901.1502638101 178410.270599523, 71899.3092541032 178409.489137266, 71901.6536408741 178403.966108146))"^^ . -_:Bbaebd7be7fcd9a575668040e5b3ff7af . - . - _:B12e85cd42c81251e30d8a2ef1df9f25b . - _:B3b4f7f432f3cd8b7600c0faedfd1f484 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B27f6b9670796f3535b1779f93f3d23b9 . - _:B5d0961c1cbe3403f95bb18f5e2d763a2 . - . - _:B6a4ba624fb7db4cc094fdb2c8f3c8ab7 . - . - "2021-01-06T12:51:36.327Z"^^ . - "2021-01-06T12:51:36.327Z"^^ . - "10590577"^^ . - "Wegeniswerken"^^ . - "2021-01-06T18:05:39.667Z"^^ . - . - . - "9197136"^^ . -_:B6fe795917dd8918883cedefb5c866447 "Politiezone Brugge"^^ . -_:B6fe795917dd8918883cedefb5c866447 . -_:B6fe795917dd8918883cedefb5c866447 . -_:B06a23e77a887a71a4d6547661e6ce81f "https://gipod.vlaanderen.be"@nl-BE . -_:B06a23e77a887a71a4d6547661e6ce81f "10590357"^^ . -_:B06a23e77a887a71a4d6547661e6ce81f . -_:B03fcf811581adfc0a28f54759586289f "Gemeente Tessenderlo"^^ . -_:B03fcf811581adfc0a28f54759586289f . -_:B03fcf811581adfc0a28f54759586289f . - . - _:B502b1fe71bcbdaff18ca6a139b8f737f . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T13:37:23.24Z"^^ . - . - . - _:Bf790930c6df4defd52b858c82a7748a7 . - _:B30ce14ae5fa5bd577d0830e54f1bb71b . - "10590496"^^ . - "2021-01-06T18:05:12.217Z"^^ . - . - "2021-01-06T13:37:23.24Z"^^ . - _:B35ede7c47881db23a2170eb2d08178ff . - "8670 Koksijde, Vrijheidstraat 4: IOD - Bouwwerf"^^ . - _:B69b6248920f6e5d18c94c86d620c7007 . -_:Baf8d4c9a0aef1453bc6d23c916d253f8 "Stad Kortrijk"^^ . -_:Baf8d4c9a0aef1453bc6d23c916d253f8 . -_:Baf8d4c9a0aef1453bc6d23c916d253f8 . -_:B1140511aaaf7b5d6467c4a41436c89d8 " POLYGON ((138470.06461661682 176496.9186425181, 138470.2964429879 176495.08334043343, 138471.05160638658 176495.26986451447, 138470.77178069585 176496.72890436184, 138470.06461661682 176496.9186425181))"^^ . -_:B1140511aaaf7b5d6467c4a41436c89d8 . -_:B6704d176f24e81d604062b456c5b821c "Gemeente Ingelmunster"^^ . -_:B6704d176f24e81d604062b456c5b821c . -_:B6704d176f24e81d604062b456c5b821c . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:51:35.517Z"^^ . - _:Bb359a98aa50263e7171ac30d795eea48 . - "2021-01-06T14:51:35.517Z"^^ . - . - "Vrachtwagen/werfwagen Bouw van nieuwbouwwoning in halfopen verband."^^ . - "10590402"^^ . - _:B3df20dbe98b47690d58965cfd3d58132 . - "2021-01-06T18:04:40.563Z"^^ . - . - . - _:B449f4c1f172e3bb625bc872f105e860b . - _:Bd75e78a962b73408930a6f544ededf52 . - _:B93c00c7af86cc918ed517e9f69f3a876 . - . -_:B440446dbdd3217dbcfb90003a6b1d88e "2021-01-09T06:00:00Z"^^ . -_:B440446dbdd3217dbcfb90003a6b1d88e "2021-01-09T18:00:00Z"^^ . -_:B440446dbdd3217dbcfb90003a6b1d88e . - _:B9cd89f7248cd3bd59e3d7c2714b5e2fd . - _:Baf8d4c9a0aef1453bc6d23c916d253f8 . - . - "Kraan Hijswerken"^^ . - . - "2021-01-06T18:05:33.07Z"^^ . - _:B7254ec8ea4675d9eee594064a3bd4df4 . - "2021-01-06T13:04:25.21Z"^^ . - . - "10590551"^^ . - . - _:B4c5898f65a3517e24e473abaed5b48a1 . - "2021-01-06T13:04:25.21Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B76127f9a4451277a823492ebf77a3d71 . - . - "2021-01-06T14:34:58.873Z"^^ . - "10590477"^^ . - _:B287be79cbcc13cd0a947361f43672c5b . - _:B18c0a67a064e12f0f3c907ae1c8b44c1 . - "2021-01-06T18:05:05.463Z"^^ . - _:B94c26eb56aedccf2b7f68faf84efe2bd . - _:B0a97a86dbcde233959b00b6c917a70b0 . - "2021-01-06T13:55:10.767Z"^^ . - _:Bcc079400f4dac274b859d6f5e5f6cf71 . - . - . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "8310 Brugge, Karel van Manderstraat 79: Verhuis zonder lift/ levering zonder lift"^^ . -_:Bc1087bbdaf430b6217b863df91868224 "Gemeente Ranst"^^ . -_:Bc1087bbdaf430b6217b863df91868224 . -_:Bc1087bbdaf430b6217b863df91868224 . - . - _:Bbaebd7be7fcd9a575668040e5b3ff7af . - . -_:Bd15b39267b5705cb5f75861ec1367654 "https://gipod.vlaanderen.be"@nl-BE . -_:Bd15b39267b5705cb5f75861ec1367654 "10590561"^^ . -_:Bd15b39267b5705cb5f75861ec1367654 . - . - _:B21f174142b436abc2c98ead817cdc538 . - . -_:B25be844874406019408cc5a7a1d1cfd7 "Gemeente Beveren"^^ . -_:B25be844874406019408cc5a7a1d1cfd7 . -_:B25be844874406019408cc5a7a1d1cfd7 . - . - . - "9197216"^^ . - . - _:B2df1fa890222ea735237d476654f3ecd . - . - _:B24a27fcca8528cbdb5ab883b8f4facea . - "2021-01-06T18:04:53.433Z"^^ . - "10590445"^^ . - "8200 Brugge, Hertsvelde 46: Doorlopende vergunning"^^ . - . - _:Bee2da5e565021c9bb2839050aafd6309 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:37:13.347Z"^^ . - . - . - . - _:Bb908ce178ecde0c7f95d025ff1f591ac . - "2021-01-06T14:20:28.347Z"^^ . - _:B0055edc2a598971f57c3e3943a778d93 . - _:Bd44689c3f385c3f6e838a65679effe5c . -_:B1db1211702ecb8fdb49262bc1a828a6d "2021-01-13T11:00:00Z"^^ . -_:B1db1211702ecb8fdb49262bc1a828a6d "2021-01-13T15:00:00Z"^^ . -_:B1db1211702ecb8fdb49262bc1a828a6d . -_:B94934b6cb6874d475a3d48582bde4d5b "Stad Eeklo"^^ . -_:B94934b6cb6874d475a3d48582bde4d5b . -_:B94934b6cb6874d475a3d48582bde4d5b . - . - _:Be49663129f7da06cf393f6dc810d40be . - . - . - . - "9196961"^^ . -_:B29f9a890a56802ae33d7b8894b250961 "Gemeente Zedelgem"^^ . -_:B29f9a890a56802ae33d7b8894b250961 . -_:B29f9a890a56802ae33d7b8894b250961 . -_:B58f91138101cd967ced7b9503f1c467e "2021-01-01T00:00:00Z"^^ . -_:B58f91138101cd967ced7b9503f1c467e "2021-01-18T00:00:00Z"^^ . -_:B58f91138101cd967ced7b9503f1c467e . - . - "2021-01-06T18:04:50.383Z"^^ . - _:Ba47dc84160bcd5bee505b255a83438c3 . - . - _:B9e1970d85418ade96041828d039a5f6f . - "Noordlaan 95: Verhuis - Parkeerverbod"^^ . - "2021-01-06T14:34:25.487Z"^^ . - "10590434"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - "2021-01-06T14:32:02.437Z"^^ . - _:B757a1734d7d0639b3bf201f4f71bc1dc . - _:B6580400a1eed2bba228db14979796125 . - _:B05151737ca5da6e236e0c93f66b7e60f . -_:B3a448bb4498e4ab0179c31e6f26398f8 "https://gipod.vlaanderen.be"@nl-BE . -_:B3a448bb4498e4ab0179c31e6f26398f8 "10590544"^^ . -_:B3a448bb4498e4ab0179c31e6f26398f8 . - _:B549b0d4c02a08455f7214273a5a2bba5 . - _:Bfb03ece294fa9000c0411fd82d779737 . - "Vrachtwagen/werfwagen "^^ . - . - _:B4d8e8a079f1831cf4bae349bf914ce67 . - "2021-01-06T14:04:55.287Z"^^ . - "2021-01-06T18:05:26.477Z"^^ . - . - "10590528"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - _:B646350dbba56de3248dc11d91db89c43 . - "2021-01-06T13:19:08.42Z"^^ . - _:B067eae8ae3064e99f94cfd2acf77f829 . - . - . - _:B6436f390ec06baf12906abbd2a7aa143 . - _:Ba615b3630c4a9958fffeef2f77908ec3 . - . - _:B4f263ff4e505ede540eaa18e0765baea . - _:Bdf6c8eae91e970b0f77422db3f2113e0 . - "2021-01-06T18:05:30.567Z"^^ . - . - "9300 Aalst, Vooruitgangstraat 16: Werf met combinatie van types"^^ . - "2021-01-06T13:12:10.93Z"^^ . - _:B3a448bb4498e4ab0179c31e6f26398f8 . - "2021-01-06T13:09:19.993Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "10590544"^^ . -_:Bf0fb518404fcabb03588da280c8b04e7 "Stad Lokeren"^^ . -_:Bf0fb518404fcabb03588da280c8b04e7 . -_:Bf0fb518404fcabb03588da280c8b04e7 . - "2021-01-06T18:04:30.56Z"^^ . - . - _:B559c20f13667008cf9ced60c65215a08 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "10590371"^^ . - . - . - "9160 Lokeren, Dennenlaan 1: Inname openbaar domein (buiten parkeerplaats) voor werken"^^ . - _:B1f05de6ef503c1ffc22dad39bb29541f . - _:B2d7d3e4fd598d578d6fc732e08a5b12d . - _:B4cd5a034e737f36536edc23605a41891 . - "2021-01-06T15:17:55.827Z"^^ . - _:B1ea8d63399b224f04af8dc2c7b06ea23 . - "2021-01-06T15:17:55.827Z"^^ . -_:Bef1ed512a983ef627525bb7c5e40f702 "2021-01-17T23:00:00Z"^^ . -_:Bef1ed512a983ef627525bb7c5e40f702 "2021-01-30T22:30:00Z"^^ . -_:Bef1ed512a983ef627525bb7c5e40f702 . - . - . - "9197077"^^ . -_:Bf790930c6df4defd52b858c82a7748a7 "https://gipod.vlaanderen.be"@nl-BE . -_:Bf790930c6df4defd52b858c82a7748a7 "10590496"^^ . -_:Bf790930c6df4defd52b858c82a7748a7 . -_:B4c192abbd0e67d102de8554e07abd262 "2021-01-08T06:00:00Z"^^ . -_:B4c192abbd0e67d102de8554e07abd262 "2021-01-15T18:00:00Z"^^ . -_:B4c192abbd0e67d102de8554e07abd262 . - . - . - "9197350"^^ . -_:B007a310d7331ec2253e6cd3cfc1fde8b "https://gipod.vlaanderen.be"@nl-BE . -_:B007a310d7331ec2253e6cd3cfc1fde8b "10590433"^^ . -_:B007a310d7331ec2253e6cd3cfc1fde8b . - . - . - "9197131"^^ . -_:Bc1dc021dc3655c1011ecc901aa27c78b "Gemeente Zedelgem"^^ . -_:Bc1dc021dc3655c1011ecc901aa27c78b . -_:Bc1dc021dc3655c1011ecc901aa27c78b . -_:B329bbd0cd66334d7a9e7881ecb85634d "Politiezone Brugge"^^ . -_:B329bbd0cd66334d7a9e7881ecb85634d . -_:B329bbd0cd66334d7a9e7881ecb85634d . -_:B424916895c219af5013792dfa08ff8e2 "Gemeente Sint-Lievens-Houtem"^^ . -_:B424916895c219af5013792dfa08ff8e2 . -_:B424916895c219af5013792dfa08ff8e2 . - . - _:Bb9ce466731e03620a44caefb4d8cbb8b . - . - . - _:Bd3c96c1926075c20c9098eddc372854f . - . -_:B3af7174eb17ef7b082bc3bdb9b6e814f " POLYGON ((154536.4910038893 221859.32163325883, 154538.4706818894 221854.19150346238, 154540.80870575312 221855.08900541347, 154538.82902577805 221860.21913343482, 154536.4910038893 221859.32163325883))"^^ . -_:B3af7174eb17ef7b082bc3bdb9b6e814f . - . - . - "9197144"^^ . -_:B13ec1f1ccbeaec9a24cb2059f06c4755 " POLYGON ((71434.1975559373 179225.367885097, 71434.2801842941 179221.566980683, 71453.5325914344 179222.641149322, 71453.202078007 179227.020452234, 71434.1975559373 179225.367885097))"^^ . -_:B13ec1f1ccbeaec9a24cb2059f06c4755 . -_:B6580400a1eed2bba228db14979796125 "https://gipod.vlaanderen.be"@nl-BE . -_:B6580400a1eed2bba228db14979796125 "10590434"^^ . -_:B6580400a1eed2bba228db14979796125 . -_:B233d8235e28f24fa9e720b1a818fcd22 "Stad Ronse"^^ . -_:B233d8235e28f24fa9e720b1a818fcd22 . -_:B233d8235e28f24fa9e720b1a818fcd22 . -_:Befa179c78c4b4091d1fd884a8a2ec448 "Politiezone Leuven"^^ . -_:Befa179c78c4b4091d1fd884a8a2ec448 . -_:Befa179c78c4b4091d1fd884a8a2ec448 . - . - _:B3af7174eb17ef7b082bc3bdb9b6e814f . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . - . -_:B728fb197339a38e644dea1d5f9c5a4e4 " POLYGON ((176062.2960148064 174494.20804738533, 176064.29995645766 174494.21806122083, 176064.28996903508 174496.21664048918, 176062.2860281504 174496.20662665833, 176062.2960148064 174494.20804738533))"^^ . -_:B728fb197339a38e644dea1d5f9c5a4e4 . -_:B256c880ef9bda8783ccedb5dc63dd0a9 "Gemeente Tervuren"^^ . -_:B256c880ef9bda8783ccedb5dc63dd0a9 . -_:B256c880ef9bda8783ccedb5dc63dd0a9 . - . - . - _:B7c98e3ea4db1e3548bc507c677248dbf . - . -_:Bef514783f93c7d47b956b4d42119ec96 "2021-02-14T23:00:00Z"^^ . -_:Bef514783f93c7d47b956b4d42119ec96 "2021-02-28T22:30:00Z"^^ . -_:Bef514783f93c7d47b956b4d42119ec96 . -_:Bc8bae1b4948beef89da065899e4a8a9f "Stad Mechelen"^^ . -_:Bc8bae1b4948beef89da065899e4a8a9f . -_:Bc8bae1b4948beef89da065899e4a8a9f . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Ba3976bbcb1913c8428a32146b3f7f9d9 . - _:B935ca386770ee81a1b877e9b9e1cfb86 . - _:B6155538a0d00bdcec5dcd6162c42a95f . - "2021-01-06T18:04:15.87Z"^^ . - _:Bd3a0e17a8a715193cc59257789bcd6d3 . - . - "Container"^^ . - . - "2021-01-06T16:41:20.3Z"^^ . - _:Beb3acd23a3bc1a67255329c8be083940 . - . - "2021-01-06T16:41:20.3Z"^^ . - . - "10590339"^^ . -_:Bd82a1117a1c47af35064455d0fed52d3 "2021-01-06T23:00:00Z"^^ . -_:Bd82a1117a1c47af35064455d0fed52d3 "2021-01-10T22:30:00Z"^^ . -_:Bd82a1117a1c47af35064455d0fed52d3 . -_:B73bb3af5dd354c14f15736993a33488b "2021-01-11T05:00:00Z"^^ . -_:B73bb3af5dd354c14f15736993a33488b "2021-01-11T19:00:00Z"^^ . -_:B73bb3af5dd354c14f15736993a33488b . - "2021-01-06T14:44:59.677Z"^^ . - "2021-01-06T18:04:44.49Z"^^ . - . - . - . - _:B3209538bdf41ebee1a671dc0b8373fea . - . - _:B0d2fea95dcced889bf72ae4f0dcc9d31 . - "2021-01-06T14:44:59.677Z"^^ . - _:B98e61b89bdf5dd5ba424613172335a30 . - "10590412"^^ . - _:B882084c75b0f736ca2031cf071539132 . - "Container"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B36c086481ee8771d8f33f6fe8ffee4bb . -_:B25589f7b3c1e4c70c309c70532337bb7 "Politiezone Brugge"^^ . -_:B25589f7b3c1e4c70c309c70532337bb7 . -_:B25589f7b3c1e4c70c309c70532337bb7 . - . - _:B4a9bfc9ef223533d100980ec3e0a1d87 . - . - . - _:B41fce9164b7343a8095a9bef933449b6 . - . - . - _:B8bf5afe00720df6b184456687fe18262 . - . -_:B85ec7901826d41ae789470c0445262b8 "https://gipod.vlaanderen.be"@nl-BE . -_:B85ec7901826d41ae789470c0445262b8 "10590399"^^ . -_:B85ec7901826d41ae789470c0445262b8 . - . - _:Bc0261de661a39421e858a0ae410f99cc . - . -_:B7c0ed1c3584c0d78ebeec31effb614b6 "Politiezone Leuven"^^ . -_:B7c0ed1c3584c0d78ebeec31effb614b6 . -_:B7c0ed1c3584c0d78ebeec31effb614b6 . -_:B61b04bcf4117bd895aec6cca0bd695e5 "Politiezone Leuven"^^ . -_:B61b04bcf4117bd895aec6cca0bd695e5 . -_:B61b04bcf4117bd895aec6cca0bd695e5 . -_:B62f97f59f85fa5e70e191ddc2389a84d "https://gipod.vlaanderen.be"@nl-BE . -_:B62f97f59f85fa5e70e191ddc2389a84d "10590370"^^ . -_:B62f97f59f85fa5e70e191ddc2389a84d . -_:Baee2868ba5fa433271fade2e3c0c1324 "2021-01-06T05:00:00Z"^^ . -_:Baee2868ba5fa433271fade2e3c0c1324 "2021-01-06T18:00:00Z"^^ . -_:Baee2868ba5fa433271fade2e3c0c1324 . -_:Ba671bf0bf242444d10cecc1b5d2d54a4 "Stad Izegem"^^ . -_:Ba671bf0bf242444d10cecc1b5d2d54a4 . -_:Ba671bf0bf242444d10cecc1b5d2d54a4 . - . - . - "9196995"^^ . -_:B893cd035b61ca31120a60cb26dba1105 " POLYGON ((144838.020479639 211722.88197916, 144843.985437523 211722.583731266, 144843.538065682 211718.855632588, 144838.020479639 211719.452128377, 144838.020479639 211722.88197916))"^^ . -_:B893cd035b61ca31120a60cb26dba1105 . - . - . - "9196974"^^ . -_:B18c0a67a064e12f0f3c907ae1c8b44c1 "Politiezone Brugge"^^ . -_:B18c0a67a064e12f0f3c907ae1c8b44c1 . -_:B18c0a67a064e12f0f3c907ae1c8b44c1 . - . - _:Ba45a75e83cca14e87dccc0afef62edd7 . - . -_:B5cd443fcf222b3e5a025f8c30d395958 "Gemeente Zedelgem"^^ . -_:B5cd443fcf222b3e5a025f8c30d395958 . -_:B5cd443fcf222b3e5a025f8c30d395958 . -_:B76127f9a4451277a823492ebf77a3d71 "Stad Kortrijk"^^ . -_:B76127f9a4451277a823492ebf77a3d71 . -_:B76127f9a4451277a823492ebf77a3d71 . - . - _:Bfbf685aae6b77ce77407688760d1892c . - . -_:B2b26a6cb95996137118fe5cc31aa8e66 "https://gipod.vlaanderen.be"@nl-BE . -_:B2b26a6cb95996137118fe5cc31aa8e66 "10590363"^^ . -_:B2b26a6cb95996137118fe5cc31aa8e66 . - _:B12ca310fX2D6c7eX2D4721X2Db672X2D83964b1650df . - . -_:B80926c102fab102feeb95363551b05b7 "https://gipod.vlaanderen.be"@nl-BE . -_:B80926c102fab102feeb95363551b05b7 "10590506"^^ . -_:B80926c102fab102feeb95363551b05b7 . - . - . - "9197165"^^ . -_:B7250640df6c41dfcd9794e74d7f98ec5 "2021-01-09T05:00:00Z"^^ . -_:B7250640df6c41dfcd9794e74d7f98ec5 "2021-01-10T19:00:00Z"^^ . -_:B7250640df6c41dfcd9794e74d7f98ec5 . - . - _:Bd5074c8e841f62d032b7ae825279eff4 . - "8430 Middelkerke, Cyriel De Grootelaan 38: Voertuigen"^^ . - "2021-01-06T13:25:16.467Z"^^ . - _:Bfdbff4d375ad7c6bf22501fc79b849f5 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T13:26:12.74Z"^^ . - _:Bd0b6f4b6370626e82f760883b3925737 . - . - "10590512"^^ . - _:Bf0b666079025bb93fe6b92673ce76dbe . - . - . - "2021-01-06T18:05:20.567Z"^^ . - _:Ba0becedce673b730180685ed722187b5 . -_:Bc862238d8ddc1885c53c44895c71eb82 "https://gipod.vlaanderen.be"@nl-BE . -_:Bc862238d8ddc1885c53c44895c71eb82 "10590481"^^ . -_:Bc862238d8ddc1885c53c44895c71eb82 . - "2021-01-06T13:22:37.56Z"^^ . - "10590519"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bd1113f9d873e3398068f0741247f4789 . - . - _:Bef75ae3d5da79ca3c5ed3eed203e3d27 . - . - "2021-01-06T18:05:23.963Z"^^ . - _:B92f70eae04a7e2fc1418c533594e530a . - . - . - "2021-01-06T13:22:14.16Z"^^ . - _:Bda033b82a83b7f056b73533ca8f5c354 . - "9600 Ronse - Ninovestraat 81A - container"^^ . - _:B3811edd26495802358252b248945da0c . -_:B7d9e162f9de34013af6bf8be48622d00 "2021-01-20T07:00:00Z"^^ . -_:B7d9e162f9de34013af6bf8be48622d00 "2021-01-27T20:00:00Z"^^ . -_:B7d9e162f9de34013af6bf8be48622d00 . -_:B646350dbba56de3248dc11d91db89c43 "Politiezone Leuven"^^ . -_:B646350dbba56de3248dc11d91db89c43 . -_:B646350dbba56de3248dc11d91db89c43 . - . - _:B4b342cd7b7bec4e53cb20c8baaef8285 . - . - . - _:B5a2597bff12f53c4e5b37eda691863e1 . - . -_:Bab86dc31f176dc6eb0f88d451f5f02e0 "Gemeente Zonhoven"^^ . -_:Bab86dc31f176dc6eb0f88d451f5f02e0 . -_:Bab86dc31f176dc6eb0f88d451f5f02e0 . -_:B6a8e8fa6e3118abca39e50b57f337073 "Politiezone Leuven"^^ . -_:B6a8e8fa6e3118abca39e50b57f337073 . -_:B6a8e8fa6e3118abca39e50b57f337073 . -_:Baa6508e0e8bf60ee89043bcfa40bb9a9 "Politiezone Leuven"^^ . -_:Baa6508e0e8bf60ee89043bcfa40bb9a9 . -_:Baa6508e0e8bf60ee89043bcfa40bb9a9 . - . - . - "9197232"^^ . -_:Bb8ed70fd711578272bc97111c690df6b "https://gipod.vlaanderen.be"@nl-BE . -_:Bb8ed70fd711578272bc97111c690df6b "10590549"^^ . -_:Bb8ed70fd711578272bc97111c690df6b . -_:B3063d33d42d5efc671446108ea112f6a "Stad Ronse"^^ . -_:B3063d33d42d5efc671446108ea112f6a . -_:B3063d33d42d5efc671446108ea112f6a . - . - . - "9197245"^^ . -_:B9711230236f8575d244a4374a075e956 "Politiezone Leuven"^^ . -_:B9711230236f8575d244a4374a075e956 . -_:B9711230236f8575d244a4374a075e956 . -_:B02a887c34bc5aa0c42b37488d61b1574 "https://gipod.vlaanderen.be"@nl-BE . -_:B02a887c34bc5aa0c42b37488d61b1574 "10590397"^^ . -_:B02a887c34bc5aa0c42b37488d61b1574 . -_:Bdda1ccf6684ac097ca2825a25c4b22c2 "https://gipod.vlaanderen.be"@nl-BE . -_:Bdda1ccf6684ac097ca2825a25c4b22c2 "10590468"^^ . -_:Bdda1ccf6684ac097ca2825a25c4b22c2 . -_:Bced9054e50097f0dc6dd7568be9fa5ad "Gemeente Beernem"^^ . -_:Bced9054e50097f0dc6dd7568be9fa5ad . -_:Bced9054e50097f0dc6dd7568be9fa5ad . -_:B0494d87ca08c9f65da7d223f612a8dc1 "Stad Turnhout"^^ . -_:B0494d87ca08c9f65da7d223f612a8dc1 . -_:B0494d87ca08c9f65da7d223f612a8dc1 . -_:B7c61e3880ca6576368edc137a7160f1b "Gemeente Brasschaat"^^ . -_:B7c61e3880ca6576368edc137a7160f1b . -_:B7c61e3880ca6576368edc137a7160f1b . -_:B187b1c8aec3d87351270e04c56456afa "Stad Kortrijk"^^ . -_:B187b1c8aec3d87351270e04c56456afa . -_:B187b1c8aec3d87351270e04c56456afa . - . - _:B6a7387773f916dd7f787bdce6c90cc7f . - "2021-01-06T18:04:21.707Z"^^ . - "2021-01-06T15:50:33.877Z"^^ . - _:Baaf2d9d6d6397d6d47ad98e513487ce9 . - "2021-01-06T15:51:52.443Z"^^ . - . - . - "10590356"^^ . - _:B02cd47933012cf30d82b5e00e54599d7 . - "8000 Brugge, Vlamingstraat 26: Doorlopende vergunning"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bfa2bb3fa7998c572d70e577cc2b8a4a1 . - . - _:B004ffa730c22d1ffff9352b0c35d95ed . - . - _:Bc2a8b850fd36ae0c4ac6ab3e80324276 . - . -_:B3e28b351247991999af12953754cc8fb "2021-03-01T05:00:00Z"^^ . -_:B3e28b351247991999af12953754cc8fb "2021-12-31T18:00:00Z"^^ . -_:B3e28b351247991999af12953754cc8fb . - . - _:B00d497007e4f44fd4a97f0789cb17795 . - . - "2021-01-06T13:11:44.837Z"^^ . - . - "10590539"^^ . - "2021-01-06T13:12:06.99Z"^^ . - "2021-01-06T18:05:29.22Z"^^ . - _:Bd1ab2c286e86691ed753e647dd9b11f8 . - . - _:B2a0b7ae51f90d0be034e384d5ba17d89 . - . - _:Bbffdefe441d6315be863bc9bc8e348e8 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - "8210 Zedelgem, 't Groenhof 43: Container"^^ . - _:B07470dd5bd6f124ed74be612c385a0c6 . - _:Bb60b70834d2311f1f33e14f4ecf5c9d7 . - . - . - "9197237"^^ . - . - . - "9197093"^^ . -_:B765b1b7550bdc2dc904cdce0a4e142e7 " POLYGON ((70571.71735961756 163197.03797053732, 70452.75933327732 163213.1839089999, 70255.22156604225 163163.3495425349, 70294.44497185564 162980.46134111844, 70243.05308095395 163010.30467268452, 70196.97494606605 163016.29007763974, 70196.15503664713 163012.15095227677, 70242.23320719077 163006.16553594172, 70299.24875559773 162972.83983996417, 70261.60163610228 163159.85577339306, 70452.67914026573 163207.9014612548, 70572.39967801623 163192.12135582976, 70571.71735961756 163197.03797053732))"^^ . -_:B765b1b7550bdc2dc904cdce0a4e142e7 . - . - . - "9197018"^^ . -_:Bd26ae5037e00afe7b14cc1119bc3a482 "2021-01-10T23:00:00Z"^^ . -_:Bd26ae5037e00afe7b14cc1119bc3a482 "2021-01-15T22:30:00Z"^^ . -_:Bd26ae5037e00afe7b14cc1119bc3a482 . -_:Bfc079d72f15166ee6447dab568b37def "Politiezone Leuven"^^ . -_:Bfc079d72f15166ee6447dab568b37def . -_:Bfc079d72f15166ee6447dab568b37def . - . - _:B6ea9b9eabc117fd65fd0aa987686d3cf . - . -_:Bff4aa0386076a33940ed0e19fc284405 "Stad Kortrijk"^^ . -_:Bff4aa0386076a33940ed0e19fc284405 . -_:Bff4aa0386076a33940ed0e19fc284405 . - "2021-01-06T14:40:38.237Z"^^ . - _:B94722e065d79885f7f72d8f29a87c085 . - . - _:Bd5fbe23860cf97058acccfb2b1a7b83d . - _:B2ebf501e7668b39df0972a9e92001ae1 . - "10590418"^^ . - . - _:B98021c0dc6abfb9b4f4d50e9e457086c . - "2021-01-06T14:40:38.237Z"^^ . - . - "8540 Deerlijk, Europalaan 16: parkeerverbod"^^ . - . - "2021-01-06T18:04:46.12Z"^^ . - _:B1eefd8d0c8122b4ae3b817336f347bf6 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . -_:B94c24ee23fed3c5d8c10e41abee43e4c "Stad Waregem"^^ . -_:B94c24ee23fed3c5d8c10e41abee43e4c . -_:B94c24ee23fed3c5d8c10e41abee43e4c . -_:B4a1cac4c4fd02eab99d35d70d20f3d48 "https://gipod.vlaanderen.be"@nl-BE . -_:B4a1cac4c4fd02eab99d35d70d20f3d48 "10590394"^^ . -_:B4a1cac4c4fd02eab99d35d70d20f3d48 . - . - . - "9197160"^^ . - . - _:B9c7674ba0c18dd72477cf08a878e8b7b . - . - . - _:B28ee4490e1b9dd2a9fb3645d9db0fa2d . - . - . - _:B297d962fd42adf93ef0209dd61d76917 . - . -_:Bd38799674605a26821edf7386b02591f "Gemeente Beveren"^^ . -_:Bd38799674605a26821edf7386b02591f . -_:Bd38799674605a26821edf7386b02591f . -_:Bb9de4f89049549fc1b2eb5cf4ba5e71a "2021-01-01T00:00:00Z"^^ . -_:Bb9de4f89049549fc1b2eb5cf4ba5e71a "2021-01-18T00:00:00Z"^^ . -_:Bb9de4f89049549fc1b2eb5cf4ba5e71a . -_:B9693f8857f6c0034ebd65f2e21a4c644 "https://gipod.vlaanderen.be"@nl-BE . -_:B9693f8857f6c0034ebd65f2e21a4c644 "10590432"^^ . -_:B9693f8857f6c0034ebd65f2e21a4c644 . -_:B0004900853979b1ece37f53ac1710889 "Stad Waregem"^^ . -_:B0004900853979b1ece37f53ac1710889 . -_:B0004900853979b1ece37f53ac1710889 . -_:B35ede7c47881db23a2170eb2d08178ff "2021-01-01T05:00:00Z"^^ . -_:B35ede7c47881db23a2170eb2d08178ff "2021-02-26T19:00:00Z"^^ . -_:B35ede7c47881db23a2170eb2d08178ff . -_:B086928356da6493dc3bbf59abe7f0ffc "Stad Dendermonde"^^ . -_:B086928356da6493dc3bbf59abe7f0ffc . -_:B086928356da6493dc3bbf59abe7f0ffc . -_:Bfd77cb3713f87c5f3ae23cf21654e512 "2021-01-13T05:00:00Z"^^ . -_:Bfd77cb3713f87c5f3ae23cf21654e512 "2021-01-20T18:00:00Z"^^ . -_:Bfd77cb3713f87c5f3ae23cf21654e512 . -_:B53a42ffec0b3813bdff4a2d4087b59bb "Politiezone Leuven"^^ . -_:B53a42ffec0b3813bdff4a2d4087b59bb . -_:B53a42ffec0b3813bdff4a2d4087b59bb . - "2021-01-06T14:13:36.103Z"^^ . - "2021-01-06T18:04:56.47Z"^^ . - _:B23c04038d01e34b66befba2717a27bab . - _:Bf9b4828d0f0775512a1db73b0f70aa30 . - "8210 Zedelgem, Berkenhagestraat 15: Parkeerverbod laad- en loszone"^^ . - _:B4fda10c333e39356e881e653d23ef182 . - . - . - _:B6da25e0b9eb7722898f00950b325b05d . - . - "10590453"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:35:56.96Z"^^ . - . - _:B29f9a890a56802ae33d7b8894b250961 . -_:B662e0f78865efc22cb5eee0a86434dec "Stad Ronse"^^ . -_:B662e0f78865efc22cb5eee0a86434dec . -_:B662e0f78865efc22cb5eee0a86434dec . -_:Bcd86c157f68a5a339d557ad72334d31f "Gemeente Tessenderlo"^^ . -_:Bcd86c157f68a5a339d557ad72334d31f . -_:Bcd86c157f68a5a339d557ad72334d31f . -_:Bd140ab71f8928489c4d00c1923a195f6 "Stad Hasselt"^^ . -_:Bd140ab71f8928489c4d00c1923a195f6 . -_:Bd140ab71f8928489c4d00c1923a195f6 . - . - _:B740eb051eba43a5611371ddc30ae3c67 . - . - . - _:B738fe87482258b7467c9b27f5cfa4182 . - . - "Geen doorgang voor gemotoriseerd verkeer"@nl-BE . - _:Bc41d77b0a52e0c4110211518234f805e . - "2021-01-06T14:18:22.283Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B34c942b37ddb828c17e2d737d5bd3111 . - _:Bdd06cc526f9496541eb7d2167d6256be . - _:B373dab693df7b11bdd591b683050d0ef . - "1861 Meise, Seringenlaan 1: Andere"^^ . - "2021-01-06T18:04:55.077Z"^^ . - . - . - "2021-01-06T14:18:22.283Z"^^ . - "10590449"^^ . - . - _:B2acc4a4d23fbf2d28550a78f1bd59a24 . - . - . - "9197000"^^ . -_:B551904432ebf19c55b492dceb57cdb46 "https://gipod.vlaanderen.be"@nl-BE . -_:B551904432ebf19c55b492dceb57cdb46 "10590530"^^ . -_:B551904432ebf19c55b492dceb57cdb46 . -_:Bddf481b0440495144801050e1d456c7e "2021-01-08T11:00:00Z"^^ . -_:Bddf481b0440495144801050e1d456c7e "2021-01-11T11:00:00Z"^^ . -_:Bddf481b0440495144801050e1d456c7e . -_:B6ea9b9eabc117fd65fd0aa987686d3cf " POLYGON ((150241.465509378 193635.657101522, 150241.915411487 193633.708361393, 150247.761631875 193635.058067719, 150247.311729767 193637.006807848, 150241.465509378 193635.657101522))"^^ . -_:B6ea9b9eabc117fd65fd0aa987686d3cf . -_:B06902b2befaecc46610a411650bb8088 "2021-01-08T00:00:00Z"^^ . -_:B06902b2befaecc46610a411650bb8088 "2021-02-26T00:00:00Z"^^ . -_:B06902b2befaecc46610a411650bb8088 . -_:B56d6c510e010c63592df767533b5dc67 " POLYGON ((41789.9982698115 209869.296289082, 41791.0064470437 209867.397321291, 41797.0124847061 209870.585974863, 41796.0043074739 209872.484942653, 41789.9982698115 209869.296289082))"^^ . -_:B56d6c510e010c63592df767533b5dc67 . -_:B06382ca87ed176738ec04d1c2dca4084 "Gemeente Schoten"^^ . -_:B06382ca87ed176738ec04d1c2dca4084 . -_:B06382ca87ed176738ec04d1c2dca4084 . -_:Bf61d7c2890b939bab2c987f8a7d6616c "Politiezone Leuven"^^ . -_:Bf61d7c2890b939bab2c987f8a7d6616c . -_:Bf61d7c2890b939bab2c987f8a7d6616c . - . - _:B728fb197339a38e644dea1d5f9c5a4e4 . - . - . - . - "9196923"^^ . - . - . - "9197279"^^ . -_:Bb0c540633eeba52e5444a717c98ee24f "Gemeente Beernem"^^ . -_:Bb0c540633eeba52e5444a717c98ee24f . -_:Bb0c540633eeba52e5444a717c98ee24f . -_:B3aa11492cc0ff08fcfef33311fed33da "Gemeente Gavere"^^ . -_:B3aa11492cc0ff08fcfef33311fed33da . -_:B3aa11492cc0ff08fcfef33311fed33da . -_:Bda652be0c673821eedde8b8e5191ab80 "Stad Kortrijk"^^ . -_:Bda652be0c673821eedde8b8e5191ab80 . -_:Bda652be0c673821eedde8b8e5191ab80 . - . - . - "9196936"^^ . - . - _:Bc4366e513a0f23205bad1fb7ca60c332 . - . -_:Ba31f6b6d271b130e5be071e94f957be6 "Politiezone Leuven"^^ . -_:Ba31f6b6d271b130e5be071e94f957be6 . -_:Ba31f6b6d271b130e5be071e94f957be6 . - . - . - "9197333"^^ . - . - _:B53d30e1c54d49ea29d4ced2168b104b0 . - . -_:Ba2685a68a33619b544f1ceefea75930a "Stad Izegem"^^ . -_:Ba2685a68a33619b544f1ceefea75930a . -_:Ba2685a68a33619b544f1ceefea75930a . -_:B788add619ef1e97a79a04aab2f18e9f4 "Stad Ronse"^^ . -_:B788add619ef1e97a79a04aab2f18e9f4 . -_:B788add619ef1e97a79a04aab2f18e9f4 . -_:B1a27ba56de51a73dccfb0d93c2d62b4b "https://gipod.vlaanderen.be"@nl-BE . -_:B1a27ba56de51a73dccfb0d93c2d62b4b "10590483"^^ . -_:B1a27ba56de51a73dccfb0d93c2d62b4b . - "10590517"^^ . - . - "2021-01-06T13:24:11.11Z"^^ . - _:B98c1ff7fbddc160e56f2977a1f48de23 . - "2021-01-06T18:05:22.573Z"^^ . - . - _:Bcc07f0baf9677aa7b584323366d2e475 . - _:Bf57ccb8d13ae1bda8b4cb280fbcda52b . - _:B3ee148ba5e6217c46f122ac88b04acec . - "2021-01-06T13:36:44.97Z"^^ . - . - "Vrachtwagen/werfwagen overdracht van +/- 200 fietsen van stad Leuven aan VZW Vélo nr 102"^^ . - . - _:B3cefd09eb44983784d0ace9241806874 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B29b73fb73b8058012596c3ddddc13add . - "10590417"^^ . - . - . - "2021-01-06T14:43:20.78Z"^^ . - _:B021861886bf1cb1f41390bd0f660d595 . - . - _:B42ea4fbd077babddbbedb8c56f3ac4d5 . - _:B4f3f67b6fd78be8a19b7f3d7ffda991d . - "2880 Bornem, Lindestraat 93: Parkeerverbod laad- en loszone"^^ . - _:Bba6401f09ec4d7bf33ec62c031db85db . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:41:33.757Z"^^ . - . - "2021-01-06T18:04:45.92Z"^^ . -_:B583a319ab9fe92071727abb8c243f9a1 " POLYGON ((70942.89242992448 161336.53028756473, 70949.74188989698 161338.88098367397, 70952.49360999571 161333.0820338698, 70953.03854734282 161331.56366360467, 70947.22560407103 161328.91417388804, 70942.89242992448 161336.53028756473))"^^ . -_:B583a319ab9fe92071727abb8c243f9a1 . - . - _:B978187050d27413ae9623979a556474a . - . -_:Bbffdefe441d6315be863bc9bc8e348e8 "Gemeente Zedelgem"^^ . -_:Bbffdefe441d6315be863bc9bc8e348e8 . -_:Bbffdefe441d6315be863bc9bc8e348e8 . -_:B28ee4490e1b9dd2a9fb3645d9db0fa2d " POLYGON ((95386.6135370543 160242.50625911154, 95386.75682518235 160242.51183229304, 95386.89934568385 160242.527658052, 95387.04036591263 160242.5536550339, 95387.17916093489 160242.58968959775, 95387.31501725578 160242.6355765029, 95387.44723648729 160242.69107986146, 95387.57513893837 160242.75591435077, 95387.6980671089 160242.82974668028, 95387.8153890698 160242.9121973048, 95387.92650171147 160243.00284237557, 95388.03083384412 160243.10121591922, 95388.12784913417 160243.20681223302, 95388.2170488612 160243.3190884847, 95388.2979744818 160243.43746750278, 95388.37020998675 160243.5613407437, 95388.43338403951 160243.69007142013, 95388.47109349997 160243.78028907347, 95388.50434839966 160243.87224199635, 95388.53306924917 160243.96571039307, 95388.55718739683 160244.06047084543, 95388.57664519288 160244.1562968469, 95388.59139612719 160244.25295934384, 95388.60140494052 160244.35022728326, 95388.60664770873 160244.44786816486, 95388.60711189998 160244.545648597, 95388.60279640472 160244.64333485437, 95388.59371153831 160244.74069343685, 95388.57987901637 160244.83749162752, 95388.56133190286 160244.93349804898, 95388.5381145311 160245.02848321642, 95388.51028239772 160245.12222008605, 95388.47790203008 160245.21448459805, 95388.4410508272 160245.30505621186, 95388.39981687476 160245.3937184335, 95388.35429873459 160245.48025933304, 95388.30460520899 160245.5644720512, 95388.25085508078 160245.64615529365, 95388.19317682927 160245.7251138124, 95388.13170832317 160245.80115887232, 95388.0665964911 160245.87410870238, 95387.99799697034 160245.94378893008, 95387.92607373481 160246.01003299828, 95387.85099870313 160246.0726825633, 95387.77295132767 160246.13158787345, 95387.69211816562 160246.18660812694, 95387.60869243309 160246.2376118085, 95387.52287354319 160246.28447700365, 95387.4348666294 160246.32709169015, 95387.42367857987 160246.33213403952, 95373.86117857987 160252.39463403952, 95373.8499598017 160252.39960764538, 95373.75951246578 160252.43676283085, 95373.66735722565 160252.469452892, 95373.57371436064 160252.49759968955, 95373.47880770593 160252.52113594397, 95373.3828641176 160252.54000539644, 95373.28611293025 160252.55416294315, 95373.18878540896 160252.56357474322, 95373.09111419639 160252.56821829954, 95372.99333275671 160252.56808251262, 95372.89567481763 160252.56316770698, 95372.79837381159 160252.55348563055, 95372.70166231788 160252.53905942646, 95372.60577150666 160252.51992357778, 95372.51093058643 160252.49612382505, 95372.41736625611 160252.467717057, 95372.32530216317 160252.4347711745, 95372.23495836908 160252.39736492836, 95372.14655082325 160252.35558773097, 95372.06029084686 160252.30953944268, 95371.97638462775 160252.25933013303, 95371.89503272755 160252.2050798177, 95371.81642960227 160252.1469181716, 95371.74076313754 160252.0849842189, 95371.66821419942 160252.01942600083, 95371.59895620219 160251.9504002216, 95371.5331546937 160251.87807187403, 95371.47096695975 160251.8026138451, 95371.41254164817 160251.72420650267, 95371.35801841336 160251.64303726435, 95371.30752758261 160251.5593001496, 95371.26118984452 160251.47319531578, 95371.21911596048 160251.38492857988, 95371.18140650002 160251.29471092654, 95371.14815160034 160251.20275800367, 95371.11943075083 160251.10928960695, 95371.09531260317 160251.01452915458, 95371.07585480712 160250.91870315312, 95371.06110387281 160250.82204065617, 95371.05109505948 160250.72477271676, 95371.04585229127 160250.62713183515, 95371.04538810001 160250.529351403, 95371.04970359527 160250.43166514565, 95371.05878846168 160250.33430656316, 95371.07262098363 160250.2375083725, 95371.09116809713 160250.14150195103, 95371.1143854689 160250.0465167836, 95371.14221760228 160249.95277991396, 95371.17459796992 160249.86051540196, 95371.2114491728 160249.76994378815, 95371.25268312523 160249.6812815665, 95371.29820126541 160249.59474066697, 95371.347894791 160249.51052794882, 95371.40164491921 160249.42884470636, 95371.45932317073 160249.3498861876, 95371.52079167683 160249.2738411277, 95371.5859035089 160249.20089129763, 95371.65450302965 160249.13121106994, 95371.72642626519 160249.06496700173, 95371.80150129687 160249.0023174367, 95371.87954867232 160248.94341212657, 95371.96038183437 160248.88839187307, 95372.04380756691 160248.83738819152, 95372.12962645681 160248.79052299637, 95372.2176333706 160248.74790830986, 95372.22882142013 160248.7428659605, 95385.79132142013 160242.6803659605, 95385.8025401983 160242.67539235463, 95385.89908049809 160242.6359179949, 95385.99754738978 160242.6015301221, 95386.09767308643 160242.5723222562, 95386.1991852898 160242.5483738299, 95386.30180793103 160242.52974997243, 95386.40526192129 160242.51650133257, 95386.50926591086 160242.50866394085, 95386.6135370543 160242.50625911154))"^^ . -_:B28ee4490e1b9dd2a9fb3645d9db0fa2d . -_:B8bbc47823740a9ab41c78afa4342e280 "https://gipod.vlaanderen.be"@nl-BE . -_:B8bbc47823740a9ab41c78afa4342e280 "10590466"^^ . -_:B8bbc47823740a9ab41c78afa4342e280 . -_:B24449f06eee39b22196402f9bf86a933 "Stad Dendermonde"^^ . -_:B24449f06eee39b22196402f9bf86a933 . -_:B24449f06eee39b22196402f9bf86a933 . - . - . - "9197181"^^ . -_:Bceff1f3db91b0e0beb2ab62e34155d3d "Stad Izegem"^^ . -_:Bceff1f3db91b0e0beb2ab62e34155d3d . -_:Bceff1f3db91b0e0beb2ab62e34155d3d . -_:B554d0e38d7b7e0ee0b2a88c7ec1a68fe "Politiezone Leuven"^^ . -_:B554d0e38d7b7e0ee0b2a88c7ec1a68fe . -_:B554d0e38d7b7e0ee0b2a88c7ec1a68fe . - . - . - "9197359"^^ . -_:Be68f336d2fc2dc59343208b96565f4c5 "Gemeente Schoten"^^ . -_:Be68f336d2fc2dc59343208b96565f4c5 . -_:Be68f336d2fc2dc59343208b96565f4c5 . -_:Bfdbf060f7430fbbf84635344a36ff150 "Stad Ninove"^^ . -_:Bfdbf060f7430fbbf84635344a36ff150 . -_:Bfdbf060f7430fbbf84635344a36ff150 . -_:B5ed60047910d786058a4cdf96b6a8899 "Gemeente Brasschaat"^^ . -_:B5ed60047910d786058a4cdf96b6a8899 . -_:B5ed60047910d786058a4cdf96b6a8899 . -_:B882084c75b0f736ca2031cf071539132 "Politiezone Leuven"^^ . -_:B882084c75b0f736ca2031cf071539132 . -_:B882084c75b0f736ca2031cf071539132 . - . - _:B2822f1393c4b45196ea1f0591e8924ef . - _:Bc34e5290f4708df2f180355fc667f24a . - _:B9c22509ea25e80228e802f7b72681d20 . - "2021-01-06T16:47:40.617Z"^^ . - "10590336"^^ . - . - _:B076dc58b13c86c0cc54f40adfa05cbc6 . - "2021-01-06T18:04:15.12Z"^^ . - . - "Stelling Promostand constructie uit scaff/truss materiaal met een bedrukte beursballon op tvv Ekonomika LCC"^^ . - _:B49e2cfe00910157904def2fb499f8cf4 . - "2021-01-06T16:47:40.617Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . -_:B5864fc2cc3a83fe99051c621069b0af2 "Politiezone Leuven"^^ . -_:B5864fc2cc3a83fe99051c621069b0af2 . -_:B5864fc2cc3a83fe99051c621069b0af2 . -_:B50b510735d803f92b766f01d736e0105 "https://gipod.vlaanderen.be"@nl-BE . -_:B50b510735d803f92b766f01d736e0105 "10590580"^^ . -_:B50b510735d803f92b766f01d736e0105 . -_:Bf84bf1a0fb4e36210e98b9f7ab42b60f "2021-02-19T05:00:00Z"^^ . -_:Bf84bf1a0fb4e36210e98b9f7ab42b60f "2021-02-19T18:00:00Z"^^ . -_:Bf84bf1a0fb4e36210e98b9f7ab42b60f . -_:B474cccd608b1809a1885195ec224500b "Stad Kortrijk"^^ . -_:B474cccd608b1809a1885195ec224500b . -_:B474cccd608b1809a1885195ec224500b . -_:B4c5898f65a3517e24e473abaed5b48a1 "2021-01-21T23:00:00Z"^^ . -_:B4c5898f65a3517e24e473abaed5b48a1 "2021-01-22T22:30:00Z"^^ . -_:B4c5898f65a3517e24e473abaed5b48a1 . -_:B4a8d014f90cbf03704da7be6dec1fe33 "2021-01-19T23:00:00Z"^^ . -_:B4a8d014f90cbf03704da7be6dec1fe33 "2021-01-20T22:30:00Z"^^ . -_:B4a8d014f90cbf03704da7be6dec1fe33 . - "2021-01-06T16:03:21.373Z"^^ . - _:B47e6828cb4b75c4930e86a801602c4d1 . - "9300 Aalst, Molenstraat 40A: Werf met combinatie van types"^^ . - "10590350"^^ . - . - _:Beac0e11ff396fea86e1bd52eecb6709f . - _:Be74e41b5751eb2f7b7c46cbba93b0351 . - _:B7a4aa6a2b58dfb826e8fab09e99c6859 . - . - . - _:Bf0a04db3f557fb15fd6ca279acdae8a4 . - "2021-01-06T18:04:19.533Z"^^ . - "2021-01-06T16:03:21.373Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . -_:B3eee490140c869a49e6c5014758a668b "https://gipod.vlaanderen.be"@nl-BE . -_:B3eee490140c869a49e6c5014758a668b "10590579"^^ . -_:B3eee490140c869a49e6c5014758a668b . -_:Bff90fcbb5238b08a09d2d007ea28dde6 "2021-01-14T06:00:00Z"^^ . -_:Bff90fcbb5238b08a09d2d007ea28dde6 "2021-01-15T22:30:00Z"^^ . -_:Bff90fcbb5238b08a09d2d007ea28dde6 . - . - _:B8c9d115755ee1c69e713241bf442d469 . - . -_:Bc91c190ef80262af53242ae7a152dd13 "Politiezone Leuven"^^ . -_:Bc91c190ef80262af53242ae7a152dd13 . -_:Bc91c190ef80262af53242ae7a152dd13 . -_:B22b9c7378a16619f0b8473854e40005e "Politiezone Brugge"^^ . -_:B22b9c7378a16619f0b8473854e40005e . -_:B22b9c7378a16619f0b8473854e40005e . -_:B559c20f13667008cf9ced60c65215a08 "Stad Lokeren"^^ . -_:B559c20f13667008cf9ced60c65215a08 . -_:B559c20f13667008cf9ced60c65215a08 . - . - . - "9197261"^^ . -_:B067eae8ae3064e99f94cfd2acf77f829 "https://gipod.vlaanderen.be"@nl-BE . -_:B067eae8ae3064e99f94cfd2acf77f829 "10590528"^^ . -_:B067eae8ae3064e99f94cfd2acf77f829 . -_:B11623c55c1ab9e6c2dd0bf16f1e280b8 "2021-01-28T07:00:00Z"^^ . -_:B11623c55c1ab9e6c2dd0bf16f1e280b8 "2021-01-28T10:00:00Z"^^ . -_:B11623c55c1ab9e6c2dd0bf16f1e280b8 . -_:B7aa5d977c7133a2f934d19d25cb345f4 "Gemeente Hooglede"^^ . -_:B7aa5d977c7133a2f934d19d25cb345f4 . -_:B7aa5d977c7133a2f934d19d25cb345f4 . -_:B32f7c8b789520dfb0222de53bdf3630e "Politiezone Leuven"^^ . -_:B32f7c8b789520dfb0222de53bdf3630e . -_:B32f7c8b789520dfb0222de53bdf3630e . - "2021-01-06T12:46:35.807Z"^^ . - . - _:B882658eee13a34c675dba589a362700a . - . - _:B09c1e67c591f98911e3ddf7edf01ccd4 . - . - "8310 Brugge, Cesar Gezellestraat: Doorlopende vergunning"^^ . - . - _:Bab1b8fafeb952ff37e4b69c9306a8081 . - "2021-01-06T12:45:30.267Z"^^ . - _:B5e1b5015b72a26c1a2a3a9284b2d2c8f . - _:B8a4a07f866cbb21ea3ed57ea3ac66e0f . - "10590589"^^ . - "2021-01-06T18:05:42.69Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . -_:Bcb0787f28ce58c830826a7b88a525bce "https://gipod.vlaanderen.be"@nl-BE . -_:Bcb0787f28ce58c830826a7b88a525bce "10590588"^^ . -_:Bcb0787f28ce58c830826a7b88a525bce . - . - . - _:B95f57e82eadf8d077be263158a94d3d7 . - . - _:Ba19308a7c2bc284ac2c05b2607ffe98e . - . - "2021-01-06T12:49:41.2Z"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - _:B71ebc59b03c453818badeb8f2b653222 . - _:B1968f916fa99c456e63ddb93469c3828 . - "2021-01-06T12:49:41.2Z"^^ . - "2021-01-06T18:05:40.987Z"^^ . - "10590582"^^ . - . - _:B755f29f5030f578fae5540e3ef1bf516 . - "Wegeniswerken Nutswerken in opdracht van Fluvius.\nAfsluiten Koningsplein tussen Eikenboslaan en Mechelbaan"^^ . - _:Bec7ad8cd43354830013ee6de5c42890d . -_:B791cc74711b7e0ea61f69eb69f5c884b "Stad Eeklo"^^ . -_:B791cc74711b7e0ea61f69eb69f5c884b . -_:B791cc74711b7e0ea61f69eb69f5c884b . -_:Bbf8209aad005cfb82b8af6d2114d6c55 "Stad Tielt"^^ . -_:Bbf8209aad005cfb82b8af6d2114d6c55 . -_:Bbf8209aad005cfb82b8af6d2114d6c55 . - . - _:Be7eff8a28e3b3b986b1a0878d3e07fe5 . - _:B98b35b4f952250f8ee90a9249a188cd2 . - "2021-01-06T16:30:20.843Z"^^ . - . - _:B0f2517b39960535cb3cee38b90f4297d . - "10590343"^^ . - "2021-01-06T16:30:20.843Z"^^ . - . - _:B7c26155ba3970a308e9251fec9088a26 . - "2021-01-06T18:04:17.05Z"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Ba64c87db2d87a50214a4e84ec467a26d . - "Container Inname van de parkeerstrook thv. hoek t.e.m. nr. 10 met container (10 meter)"^^ . -_:B7f7a86d3300e0bc4e0fcdcb6d16e7212 "https://gipod.vlaanderen.be"@nl-BE . -_:B7f7a86d3300e0bc4e0fcdcb6d16e7212 "10590377"^^ . -_:B7f7a86d3300e0bc4e0fcdcb6d16e7212 . -_:B5b95217a0b61636754dee5030ac70b7b "https://gipod.vlaanderen.be"@nl-BE . -_:B5b95217a0b61636754dee5030ac70b7b "10590507"^^ . -_:B5b95217a0b61636754dee5030ac70b7b . -_:Bbbc55d6c1509ef7bcb9d406ed9139b6a "Gemeente Willebroek"^^ . -_:Bbbc55d6c1509ef7bcb9d406ed9139b6a . -_:Bbbc55d6c1509ef7bcb9d406ed9139b6a . -_:Bba6401f09ec4d7bf33ec62c031db85db "Gemeente Bornem"^^ . -_:Bba6401f09ec4d7bf33ec62c031db85db . -_:Bba6401f09ec4d7bf33ec62c031db85db . -_:Bd82438e74e68143ab48f0511ba0b8852 " POLYGON ((31911.9435411384 202135.449671577, 31910.9493693553 202139.59200243, 31915.5887769979 202140.586165111, 31916.0858628894 202138.76353808, 31922.2165100031 202140.08907922, 31922.7135958946 202137.603686169, 31911.9435411384 202135.449671577))"^^ . -_:Bd82438e74e68143ab48f0511ba0b8852 . -_:Bc049830191c39214aa5a49f5c0b1f660 "Stad Dendermonde"^^ . -_:Bc049830191c39214aa5a49f5c0b1f660 . -_:Bc049830191c39214aa5a49f5c0b1f660 . -_:Bd6f06861a4222e76fe9d45816bcbc242 " POLYGON ((66997.8263678326 210458.209941162, 66999.8263678326 210458.209941162, 66999.8263678326 210473.209941162, 66997.8263678326 210473.209941162, 66998.2298720442 210469.885411681, 66997.8263678326 210458.209941162))"^^ . -_:Bd6f06861a4222e76fe9d45816bcbc242 . - . - . - "9197047"^^ . - . - . - "9197341"^^ . - . - . - "9197026"^^ . -_:B5a2597bff12f53c4e5b37eda691863e1 " MULTIPOLYGON (((157093.9943871432 189882.05818946913, 157097.38625531216 189885.73177495546, 157096.6515382149 189886.41014858926, 157093.25967004595 189882.73656310292, 157093.9943871432 189882.05818946913)), ((157106.61270871043 189882.0469190538, 157109.88310030193 189885.8290532183, 157108.3702466361 189887.13720985493, 157105.0998550446 189883.35507569043, 157106.61270871043 189882.0469190538)), ((157097.5125848579 189871.63092276864, 157104.06825055153 189879.1822966379, 157102.5579757778 189880.49342977654, 157096.00231008418 189872.94205590728, 157097.5125848579 189871.63092276864)))"^^ . -_:B5a2597bff12f53c4e5b37eda691863e1 . - . - . - "9196957"^^ . -_:Bd42539aa93615e17339515791ffa41a6 "2021-01-16T06:00:00Z"^^ . -_:Bd42539aa93615e17339515791ffa41a6 "2021-01-17T17:00:00Z"^^ . -_:Bd42539aa93615e17339515791ffa41a6 . -_:Bd279c21fe103b5919dd6abf3bc45cf9b "Gemeente Brasschaat"^^ . -_:Bd279c21fe103b5919dd6abf3bc45cf9b . -_:Bd279c21fe103b5919dd6abf3bc45cf9b . -_:B5b79b2110a2493e0f1ef78a16a8b6e86 "https://gipod.vlaanderen.be"@nl-BE . -_:B5b79b2110a2493e0f1ef78a16a8b6e86 "10590349"^^ . -_:B5b79b2110a2493e0f1ef78a16a8b6e86 . -_:B229f66aea275390235ca619d73ff522e "Stad Mechelen"^^ . -_:B229f66aea275390235ca619d73ff522e . -_:B229f66aea275390235ca619d73ff522e . -_:Bff665acc76cabc37a2bcbe923a20ec37 "Stad Aalst"^^ . -_:Bff665acc76cabc37a2bcbe923a20ec37 . -_:Bff665acc76cabc37a2bcbe923a20ec37 . -_:Bd91cdc624e9b5fb860c6340311cc86c8 "2021-01-13T05:00:00Z"^^ . -_:Bd91cdc624e9b5fb860c6340311cc86c8 "2021-01-15T21:00:00Z"^^ . -_:Bd91cdc624e9b5fb860c6340311cc86c8 . -_:B246e9e71720dc4411f25bff5f8f79cab " POLYGON ((217698.17381502953 180882.8639460653, 217694.95469114612 180887.32479899935, 217696.98787766823 180888.7842719294, 217700.20700242172 180884.32342147827, 217703.42613265305 180879.86256914958, 217706.6452683629 180875.4017149387, 217709.8644095504 180870.9408588577, 217707.8312195483 180869.4813759923, 217704.61207923066 180873.94223456178, 217701.39294439112 180878.40309125464, 217698.17381502953 180882.8639460653))"^^ . -_:B246e9e71720dc4411f25bff5f8f79cab . -_:Bcbf97350e14fddf633678992c9e8c01b "Stad Turnhout"^^ . -_:Bcbf97350e14fddf633678992c9e8c01b . -_:Bcbf97350e14fddf633678992c9e8c01b . -_:B78b6fe3ee5403d1af3420e2bdd07a05c "https://gipod.vlaanderen.be"@nl-BE . -_:B78b6fe3ee5403d1af3420e2bdd07a05c "10590498"^^ . -_:B78b6fe3ee5403d1af3420e2bdd07a05c . - "2021-01-06T13:36:14.697Z"^^ . - "inname parkeerverbod"^^ . - _:B05f03d7343018fbc06975dbfaef5599f . - _:B78b6fe3ee5403d1af3420e2bdd07a05c . - . - . - _:B95a6b931f69326cbcaff2c0002697de9 . - "2021-01-06T13:36:14.697Z"^^ . - "2021-01-06T18:05:13.317Z"^^ . - . - _:B07b01fc2567337d912a97a3571b68193 . - _:B461855ec4d7f09b839a94408be4a4180 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "10590498"^^ . - _:Bac9dabc3586ef6d20cc103d4a1dbe1e6 . - "1620 Drogenbos, Rue de l'Eglise 64: Conteneur"^^ . - "2021-01-06T18:05:03.01Z"^^ . - _:Bf97926170a04cf173d43eed7a95555af . - . - _:Bdda1ccf6684ac097ca2825a25c4b22c2 . - _:B8e601aad769f4287c155fe6990002743 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:03:07.993Z"^^ . - _:B0bb31d5873d93cea29cc79f0e14da762 . - . - . - "2021-01-06T14:03:07.993Z"^^ . - "10590468"^^ . -_:B38fb4e8605ecce97331864416378a99e "Stad Ronse"^^ . -_:B38fb4e8605ecce97331864416378a99e . -_:B38fb4e8605ecce97331864416378a99e . -_:B3cefd09eb44983784d0ace9241806874 "2021-02-02T06:00:00Z"^^ . -_:B3cefd09eb44983784d0ace9241806874 "2021-02-03T15:30:00Z"^^ . -_:B3cefd09eb44983784d0ace9241806874 . -_:Bb0e140fb560c96d9ac0b48d1aecc675a "2021-01-25T06:00:00Z"^^ . -_:Bb0e140fb560c96d9ac0b48d1aecc675a "2021-01-27T18:00:00Z"^^ . -_:Bb0e140fb560c96d9ac0b48d1aecc675a . -_:Bc41d77b0a52e0c4110211518234f805e "Gemeente Meise"^^ . -_:Bc41d77b0a52e0c4110211518234f805e . -_:Bc41d77b0a52e0c4110211518234f805e . - . - _:B961716da1d25bb3e1ecd92f0b3e56575 . - . -_:B7c98e3ea4db1e3548bc507c677248dbf " POLYGON ((159738.0210830518 167789.84480044607, 159738.20391662043 167789.84990892914, 159738.38609906973 167789.86614979035, 159738.5669532031 167789.89346266023, 159738.74580676135 167789.9317460132, 159742.80830676135 167790.9317460132, 159742.94663554407 167790.96932287572, 159743.08301149282 167791.01346439053, 159743.21712326325 167791.06406978314, 159743.3486646801 167791.12102352217, 159743.4773354361 167791.18419558305, 159743.6028417778 167791.25344174483, 159743.724897176 167791.3286039195, 159743.8432229799 167791.40951051292, 159743.95754905342 167791.49597681643, 159744.0676143917 167791.58780542872, 159744.17316771718 167791.68478670635, 159744.27396805305 167791.78669924245, 159744.36978527365 167791.8933103721, 159744.46040062956 167792.00437670367, 159744.5456072472 167792.1196446742, 159744.62521060108 167792.23885112864, 159744.6990289579 167792.3617239203, 159744.76689379135 167792.4879825323, 159744.828650167 167792.6173387181, 159744.88415709592 167792.74949715924, 159744.93328785655 167792.88415613995, 159744.9759302841 167793.02100823566, 159745.01198702646 167793.159741015, 159745.04137576665 167793.30003775295, 159745.06402941054 167793.44157815407, 159745.07989624023 167793.5840390836, 159745.08894003194 167793.72709530528, 159745.09114013883 167793.87042022374, 159745.08649153807 167794.0136866303, 159745.0750048424 167794.15656744968, 159745.05670627573 167794.29873648705, 159745.03163761346 167794.4398691725, 159742.90663761346 167804.9398691725, 159742.8744143502 167805.08138952454, 159742.83538393 167805.22118571564, 159742.78963771163 167805.35893052403, 159742.73728277342 167805.49430152975, 159742.6784416629 167805.6269818691, 159742.6132521098 167805.75666097656, 159742.54186670363 167805.88303531148, 159742.46445253657 167806.0058090688, 159742.38119081245 167806.12469487128, 159742.2922764224 167806.23941444233, 159742.1979174888 167806.3496992572, 159742.09833487816 167806.45529117165, 159741.993761684 167806.5559430261, 159741.88444268136 167806.6514192242, 159741.77063375383 167806.74149628432, 159741.6526012946 167806.82596336256, 159741.53062158288 167806.9046227464, 159741.40498013722 167806.9772903174, 159741.27597104723 167807.04379598214, 159741.1438962852 167807.10398407053, 159741.0090649993 167807.1577136999, 159740.87179278975 167807.20485910508, 159740.7324009704 167807.2453099325, 159740.59121581644 167807.27897149877, 159740.44856780072 167807.30576501202, 159740.30479082023 167807.32562775654, 159740.1602214145 167807.33851323952, 159740.01519797795 167807.3443912998, 159739.8700599677 167807.3432481786, 159739.72514710913 167807.33508655164, 159739.58079860048 167807.31992552284, 159739.43735231913 167807.29780057975, 159735.24985231913 167806.54780057975, 159735.2317429472 167806.54449973736, 159735.0882262603 167806.51423879818, 159734.9463601363 167806.47699948135, 159734.80648367878 167806.43287080032, 159734.66893123544 167806.3819582362, 159734.53403159886 167806.32438348557, 159734.40210722058 167806.26028416984, 159734.2734734404 167806.18981350603, 159734.1484377326 167806.1131399407, 159734.02729897082 167806.03044674717, 159733.91034671396 167805.9419315876, 159733.79786051385 167805.84780604037, 159733.690109247 167805.7482950945, 159733.58735047205 167805.64363661167, 159733.48982981406 167805.5340807578, 159733.3977803773 167805.419889405, 159733.3114221882 167805.3013355057, 159733.2309616694 167805.17870244014, 159733.1565911462 167805.052283339, 159733.088488387 167804.92238038272, 159733.02681617835 167804.7893040793, 159732.9717219357 167804.65337252195, 159732.9233373512 167804.51491062884, 159732.88177807897 167804.3742493664, 159732.84714345835 167804.23172495828, 159732.81951627674 167804.08767808156, 159732.79896257157 167803.94245305253, 159732.78553147253 167803.79639700358, 159732.77925508408 167803.64985905352, 159732.7801484087 167803.50318947306, 159732.78820931105 167803.35673884756, 159732.80341852314 167803.21085723897, 159732.82573969025 167803.06589334915, 159732.86591814042 167802.87686811126, 159732.91818317396 167802.69082184095, 159732.98231792086 167802.50852652377, 159733.05805625863 167802.33073858093, 159733.14508391652 167802.15819573065, 159733.2430397796 167801.99161392698, 159733.35151738705 167801.83168438904, 159733.47006661896 167801.6790707329, 159733.48052441905 167801.66654616216, 159735.07146998472 167792.34031353577, 159735.1268347528 167792.0839423711, 159735.20438028508 167791.8333867445, 159735.30351386295 167791.59056177593, 159735.4234777596 167791.35732349622, 159735.56335503195 167791.13545466043, 159735.72207652908 167790.9266511213, 159735.89842906446 167790.73250886705, 159736.0910646888 167790.55451182256, 159736.2985109932 167790.3940205069, 159736.5191823634 167790.2522616342, 159736.75139209945 167790.13031873733, 159736.993365308 167790.0291238859, 159737.24325246867 167789.94945056198, 159737.49914357087 167789.89190774804, 159737.75908271284 167789.8569352721, 159738.0210830518 167789.84480044607))"^^ . -_:B7c98e3ea4db1e3548bc507c677248dbf . -_:B4c72b3cb5ce785c4fea35f879d9b4470 "Stad Ronse"^^ . -_:B4c72b3cb5ce785c4fea35f879d9b4470 . -_:B4c72b3cb5ce785c4fea35f879d9b4470 . -_:B3da0c7a0842f1e5f7be400ca0dd432eb " POLYGON ((141048.114224491 198441.596095978, 141048.698967901 198443.50870549, 141037.223310829 198447.017165947, 141036.63856742 198445.104556435, 141048.114224491 198441.596095978))"^^ . -_:B3da0c7a0842f1e5f7be400ca0dd432eb . -_:B9e6d0f18186056f19fad6d06e04c70e2 "2021-01-08T00:00:00Z"^^ . -_:B9e6d0f18186056f19fad6d06e04c70e2 "2021-01-09T00:00:00Z"^^ . -_:B9e6d0f18186056f19fad6d06e04c70e2 . -_:B2f8cdac853c594488761e0251eaf57a6 "2021-01-09T23:00:00Z"^^ . -_:B2f8cdac853c594488761e0251eaf57a6 "2021-02-26T22:30:00Z"^^ . -_:B2f8cdac853c594488761e0251eaf57a6 . - . - _:B25be844874406019408cc5a7a1d1cfd7 . - . - . - "2021-01-06T18:05:40.267Z"^^ . - _:Bcf111921130256590d0fbc205e50303a . - _:B3eee490140c869a49e6c5014758a668b . - "2021-01-06T12:51:06.697Z"^^ . - "2021-01-06T12:51:06.697Z"^^ . - . - _:B85673478c049f1f0a8a484d58c96ef05 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "9120 Beveren, Peerkenswegel: Andere / Verlenging"^^ . - _:B0f5098c18fc6ce7e31b389fdf69f1c82 . - "10590579"^^ . -_:B2875372ad8817c68a6307051a6285cf8 "https://gipod.vlaanderen.be"@nl-BE . -_:B2875372ad8817c68a6307051a6285cf8 "10590398"^^ . -_:B2875372ad8817c68a6307051a6285cf8 . - . - _:B3f5c987ded226ca5fc056c70c560e0bd . - . - _:Bb946f072c1a9eff67c656a25448b1b0d . - _:Bcb4b8b535b3219132806600b33b1c218 . - . - "2021-01-06T14:50:42.043Z"^^ . - . - "10590404"^^ . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B11f25870b71146e6a5e7e003b38af672 . - "2021-01-06T18:04:40.907Z"^^ . - _:B98809bbe17e7bbcb37bca25b53db2cab . - "2021-01-06T15:00:09.257Z"^^ . - _:Bbf8209aad005cfb82b8af6d2114d6c55 . - . - "8700 Tielt, Hoogstraat 61: Andere"^^ . -_:B64bbd77b487cdb1c6fb9db9330e902f3 "https://gipod.vlaanderen.be"@nl-BE . -_:B64bbd77b487cdb1c6fb9db9330e902f3 "10590331"^^ . -_:B64bbd77b487cdb1c6fb9db9330e902f3 . -_:B373dab693df7b11bdd591b683050d0ef "2021-01-14T05:00:00Z"^^ . -_:B373dab693df7b11bdd591b683050d0ef "2021-01-29T18:00:00Z"^^ . -_:B373dab693df7b11bdd591b683050d0ef . -_:B491da6c1584d4f3a873ec326ed8e1827 "2021-01-25T06:00:00Z"^^ . -_:B491da6c1584d4f3a873ec326ed8e1827 "2021-01-29T15:00:00Z"^^ . -_:B491da6c1584d4f3a873ec326ed8e1827 . -_:B83d1c90f9c49df818758b17e43e8b5cd "Stad Kortrijk"^^ . -_:B83d1c90f9c49df818758b17e43e8b5cd . -_:B83d1c90f9c49df818758b17e43e8b5cd . -_:B208176cbe7ad80a85aea2af7af433ee2 " POLYGON ((158111.560433029 210304.282692933, 158113.323102725 210302.374038777, 158114.952701199 210300.609476813, 158115.540415778 210301.15223972, 158113.608266242 210303.244410052, 158112.148147609 210304.825455841, 158111.560433029 210304.282692933))"^^ . -_:B208176cbe7ad80a85aea2af7af433ee2 . -_:Bd5074c8e841f62d032b7ae825279eff4 "Gemeente Middelkerke"^^ . -_:Bd5074c8e841f62d032b7ae825279eff4 . -_:Bd5074c8e841f62d032b7ae825279eff4 . -_:B9c0090a5a5e5dc02d4377c2de46b2ae9 " POLYGON ((141895.362657633 211697.184120154, 141896.776871196 211698.598333717, 141888.291589821 211707.083615091, 141886.877376259 211705.669401528, 141895.362657633 211697.184120154))"^^ . -_:B9c0090a5a5e5dc02d4377c2de46b2ae9 . -_:Bacffa69584d2f4cd98a2cec77c33e603 "https://gipod.vlaanderen.be"@nl-BE . -_:Bacffa69584d2f4cd98a2cec77c33e603 "10590438"^^ . -_:Bacffa69584d2f4cd98a2cec77c33e603 . -_:Bc27cbcdaaf5253d142b41d4fa46f97b8 "Gemeente De Panne"^^ . -_:Bc27cbcdaaf5253d142b41d4fa46f97b8 . -_:Bc27cbcdaaf5253d142b41d4fa46f97b8 . -_:B449d569f3e3c8d24db0f59b4b516a714 " POLYGON ((157088.985195837 189924.497635204, 157076.757032174 189935.980179131, 157075.042106783 189934.190691766, 157087.344832419 189922.559023891, 157088.985195837 189924.497635204))"^^ . -_:B449d569f3e3c8d24db0f59b4b516a714 . -_:Be111c5d349d6bb08d9aa691d82d6fd92 "Stad Ronse"^^ . -_:Be111c5d349d6bb08d9aa691d82d6fd92 . -_:Be111c5d349d6bb08d9aa691d82d6fd92 . -_:Befe7a910e2256da64b278bf858b0aeaa "https://gipod.vlaanderen.be"@nl-BE . -_:Befe7a910e2256da64b278bf858b0aeaa "10590431"^^ . -_:Befe7a910e2256da64b278bf858b0aeaa . -_:B30cde8411d882f9deb8846c954b1239a "2021-01-18T06:00:00Z"^^ . -_:B30cde8411d882f9deb8846c954b1239a "2021-01-22T15:00:00Z"^^ . -_:B30cde8411d882f9deb8846c954b1239a . - . - . - "9197282"^^ . -_:B0f30b09e4cce5676dba1ff52299e567c " POLYGON ((27524.4034135322 201988.833729775, 27522.0174303784 201991.517960823, 27529.7718756281 201996.140803184, 27531.2631150992 201993.605696083, 27524.4034135322 201988.833729775))"^^ . -_:B0f30b09e4cce5676dba1ff52299e567c . - "Voertuig"^^ . - "2021-01-06T18:04:50.82Z"^^ . - _:Bcd8a9500cf54a7d5300ec25340213365 . - . - _:B36dc3725ee2232b55309a54effab7884 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:30:19.53Z"^^ . - "10590436"^^ . - _:Ba3d67d4a20f41eaa99abe3cb6ffa55a3 . - . - . - _:B2e9e248b0ca99229c013eede120b8625 . - "2021-01-06T14:33:09.633Z"^^ . - . - _:B337ad647f64a339581ecb9999d77acda . - . - . - "9197207"^^ . -_:B021861886bf1cb1f41390bd0f660d595 "https://gipod.vlaanderen.be"@nl-BE . -_:B021861886bf1cb1f41390bd0f660d595 "10590417"^^ . -_:B021861886bf1cb1f41390bd0f660d595 . -_:B24916225ce8ba57d38ba10fac44844c0 "Gemeente Borsbeek"^^ . -_:B24916225ce8ba57d38ba10fac44844c0 . -_:B24916225ce8ba57d38ba10fac44844c0 . -_:B71ebc59b03c453818badeb8f2b653222 "Stad Lier"^^ . -_:B71ebc59b03c453818badeb8f2b653222 . -_:B71ebc59b03c453818badeb8f2b653222 . -_:Bf0319fa96cbfb0aa6809d755de1197f4 "Stad Mechelen"^^ . -_:Bf0319fa96cbfb0aa6809d755de1197f4 . -_:Bf0319fa96cbfb0aa6809d755de1197f4 . - . - . - "9197021"^^ . -_:Bec7ad8cd43354830013ee6de5c42890d "2021-01-06T06:00:00Z"^^ . -_:Bec7ad8cd43354830013ee6de5c42890d "2021-01-08T16:00:00Z"^^ . -_:Bec7ad8cd43354830013ee6de5c42890d . -_:B5b7916b34c838724b909519aed62afbc "Politiezone Leuven"^^ . -_:B5b7916b34c838724b909519aed62afbc . -_:B5b7916b34c838724b909519aed62afbc . - . - . - "9196952"^^ . - . - _:B3116cdf962227edf601b9edad0a3b920 . - . -_:B2e413b2e3c7375032680f9f4bbe118f7 "Stad Eeklo"^^ . -_:B2e413b2e3c7375032680f9f4bbe118f7 . -_:B2e413b2e3c7375032680f9f4bbe118f7 . -_:B2cd3e5821b881512d27c7673618b8288 "Gemeente De Panne"^^ . -_:B2cd3e5821b881512d27c7673618b8288 . -_:B2cd3e5821b881512d27c7673618b8288 . -_:B5bc3875e7421f9aeeeced16fafd37705 "Stad Ninove"^^ . -_:B5bc3875e7421f9aeeeced16fafd37705 . -_:B5bc3875e7421f9aeeeced16fafd37705 . -_:Bdaa1e756271be914c975342dfa9f9608 " POLYGON ((173399.96068849083 174176.82021483406, 173399.36556751415 174174.39347594883, 173405.2053363041 174172.9691500673, 173405.80045473712 174175.39589028992, 173399.96068849083 174176.82021483406))"^^ . -_:Bdaa1e756271be914c975342dfa9f9608 . -_:Bb359a98aa50263e7171ac30d795eea48 "Politiezone Leuven"^^ . -_:Bb359a98aa50263e7171ac30d795eea48 . -_:Bb359a98aa50263e7171ac30d795eea48 . - . - . - "9197034"^^ . -_:B8fd98df698a7b354fa59984538285c4d "Stad Kortrijk"^^ . -_:B8fd98df698a7b354fa59984538285c4d . -_:B8fd98df698a7b354fa59984538285c4d . - . - _:B5abafb94c4b55d9436cdc2faeed82de8 . - . -_:Bcc07f0baf9677aa7b584323366d2e475 "Politiezone Leuven"^^ . -_:Bcc07f0baf9677aa7b584323366d2e475 . -_:Bcc07f0baf9677aa7b584323366d2e475 . - "2021-01-06T18:05:19.343Z"^^ . - . - "2021-01-06T13:28:26.213Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - "8770 Ingelmunster, Maandagstraat: Signalisatievergunning werken"^^ . - _:B5b95217a0b61636754dee5030ac70b7b . - . - _:Bad260bfa2fd7140279c5f2ef8bc44d9a . - "10590507"^^ . - _:Bd7683bb97ee280285d320de50ae61f32 . - "2021-01-06T13:28:26.213Z"^^ . - _:B880ee73f963dc1266a94aedab96b2c6b . - _:B4b1df86a842da75755f71cceb6b73799 . -_:B912e9ffc5b68382ef6e70bdb52cf65cc "Stad Izegem"^^ . -_:B912e9ffc5b68382ef6e70bdb52cf65cc . -_:B912e9ffc5b68382ef6e70bdb52cf65cc . -_:B3209538bdf41ebee1a671dc0b8373fea "2021-01-14T06:00:00Z"^^ . -_:B3209538bdf41ebee1a671dc0b8373fea "2021-01-18T18:00:00Z"^^ . -_:B3209538bdf41ebee1a671dc0b8373fea . -_:Bdb72d87646d206dbf48de3c911a2343d "Stad Eeklo"^^ . -_:Bdb72d87646d206dbf48de3c911a2343d . -_:Bdb72d87646d206dbf48de3c911a2343d . -_:Bccd153013e8d39159a1386664b52baa8 " POLYGON ((160172.51874962 168235.86729065, 160174.51874962 168235.86729065, 160174.53715727397 168235.86734712415, 160174.7921851765 168235.87977780544, 160175.04523238016 168235.91384928385, 160175.29446587412 168235.96931475413, 160175.53808027325 168236.04577243823, 160175.7743108956 168236.14266849577, 160176.00144654556 168236.25930103596, 160176.2178419092 168236.39482520174, 160176.4219294725 168236.5482592899, 160176.61223087614 168236.71849186224, 160176.78736762426 168236.9042897965, 160176.94607106998 168237.10430721883, 160177.08719160513 168237.31709525295, 160177.20970698784 168237.5411125155, 160177.31272974724 168237.7747362813, 160177.3955136122 168238.01627423818, 160177.45745891705 168238.26397674548, 160177.45773730447 168238.26535419404, 160177.45901152852 168238.2696982844, 160177.4606755286 168238.27532483306, 160177.46160208757 168238.27853002978, 160177.46254117825 168238.28173158184, 160177.46415808468 168238.28737185596, 160177.46578752933 168238.29300850804, 160177.46669440344 168238.29621932708, 160177.46761383282 168238.29942658366, 160177.46919610104 168238.30507667377, 160177.47079092887 168238.3107232168, 160177.47167808533 168238.31393954222, 160177.4725778174 168238.31715237757, 160177.4741253864 168238.3228120658, 160177.4756855388 168238.32846829237, 160177.4765529439 168238.33169000194, 160177.4774329451 168238.33490829627, 160177.47894575718 168238.3405773715, 160177.48047117487 168238.34624306666, 160177.48131879605 168238.3494700397, 160177.48217903313 168238.3526936712, 160177.48365703222 168238.35837192318, 160177.48514765687 168238.36404687044, 160177.48597546076 168238.36727897968, 160177.48681590284 168238.37050783276, 160177.48825903423 168238.37619505153, 160177.48971480876 168238.38187903343, 160177.49052276515 168238.38511616088, 160177.4913433796 168238.3883501103, 160177.49275158736 168238.3940460755, 160177.49417245857 168238.39973888424, 160177.49496053762 168238.4029809104, 160177.49576129296 168238.40621983202, 160177.49713452454 168238.41192433104, 160177.49852043847 168238.41762575047, 160177.499288609 168238.42087254694, 160177.50006947663 168238.42411632516, 160177.50140768048 168238.429829144, 160177.5027585848 168238.4355389587, 160177.50350681992 168238.43879041192, 160177.50426776835 168238.4420389159, 160177.50557089373 168238.44775983784, 160177.50688673795 168238.4534778345, 160177.5076150071 168238.45673381165, 160177.50835601013 168238.45998692952, 160177.50962400984 168238.46571574756, 160177.51090474252 168238.47144170248, 160177.51161301963 168238.47470208668, 160177.512334048 168238.47795969024, 160177.5135668707 168238.48369617263, 160177.51481244725 168238.48942988628, 160177.51550070735 168238.49269456294, 160177.51620173216 168238.49595652142, 160177.5173993315 168238.50170045186, 160177.51860970497 168238.5074417087, 160177.51927792045 168238.51071054713, 160177.51995891705 168238.51397674548, 160177.52112125154 168238.51972792478, 160177.52229637274 168238.5254764916, 160177.52294451668 168238.52874935963, 160177.52360546123 168238.53201968395, 160177.52473248623 168238.53777789202, 160177.5258723118 168238.54353355596, 160177.52650036267 168238.54681034508, 160177.52714122733 168238.55008465756, 160177.52823289795 168238.5558496647, 160177.52933738744 168238.56161222194, 160177.52994532036 168238.56489280227, 160177.5305660823 168238.56817098614, 160177.53162235938 168238.5739425855, 160177.53269146927 168238.5797118089, 160177.53327926132 168238.5829960568, 160177.53387989718 168238.58627798877, 160177.53490074122 168238.59205596475, 160177.53593443095 168238.59783163542, 160177.5365020598 168238.601119426, 160177.53708254718 168238.60440498372, 160177.53806791943 168238.6101891172, 160177.53906615044 168238.61597101926, 160177.53961359485 168238.61926222933, 160177.54017391175 168238.62255128854, 160177.54112377448 168238.62834135804, 160177.5420865098 168238.6341292775, 160177.54261374986 168238.63742378727, 160177.5431538745 168238.64071622, 160177.5440681913 168238.64651200332, 160177.54499539535 168238.6523057265, 160177.54550241138 168238.65560341338, 160177.5460223232 168238.6588990942, 160177.54690105957 168238.66470037232, 160177.54779269753 168238.6704996819, 160177.54827947 168238.67380041935, 160177.5487791499 168238.67709922662, 160177.54962227424 168238.6829057906, 160177.55047831102 168238.68871045875, 160177.5509448208 168238.6920141167, 160177.5514242508 168238.695315932, 160177.55223173116 168238.70112756215, 160177.55305213475 168238.7069373714, 160177.55349836525 168238.71024383212, 160177.55395752628 168238.71354852448, 160177.55472933123 168238.71936499444, 160177.5555140718 168238.72517973362, 160177.55594000593 168238.72848887098, 160177.556378881 168238.73179631762, 160177.5571149828 168238.73761741817, 160177.55786402946 168238.74343685858, 160177.55826965076 168238.74674854454, 160177.5586882238 168238.7500586244, 160177.55938859395 168238.7558841305, 160177.56010191928 168238.76170805894, 160177.560487213 168238.7650221727, 160177.5608854677 168238.76833475727, 160177.5615500804 168238.7741644542, 160177.56222765698 168238.77999264677, 160177.5625926082 168238.7833090605, 160177.56297053 168238.78662402811, 160177.56359935986 168238.7924576934, 160177.56424116256 168238.79828993368, 160177.56458575762 168238.8016085226, 160177.56494333223 168238.80492574838, 160177.5655363559 168238.8107631659, 160177.56614236019 168238.8165992308, 160177.56646658637 168238.81991987253, 160177.56680380003 168238.823239229, 160177.56736099423 168238.82908016932, 160177.5679311783 168238.83491984877, 160177.56823502373 168238.8382424223, 160177.5685518634 168238.8415637805, 160177.56907320727 168238.84740802387, 160177.56960754952 168238.85325109784, 160177.5698910023 168238.8565754727, 160177.57018745656 168238.85989871298, 160177.57067293147 168238.8657460509, 160177.57117141076 168238.87159228788, 160177.57143445985 168238.8749183349, 160177.5717105179 168238.87824333608, 160177.57216010545 168238.8840935479, 160177.57262270313 168238.8899427283, 160177.57286533905 168238.89327032727, 160177.57312099004 168238.8965969592, 160177.57353467285 168238.90244981827, 160177.573961372 168238.90830172822, 160177.57418358547 168238.9116307513, 160177.57441881995 168238.9149588913, 160177.57479658283 168238.92081418374, 160177.57518736695 168238.92666859648, 160177.5753891497 168238.9299989194, 160177.5756039587 168238.93332844108, 160177.57594578672 168238.93918593516, 160177.57630064187 168238.94504264154, 160177.57648198662 168238.9483741451, 160177.57667636173 168238.95170491695, 160177.57698224226 168238.95756439547, 160177.5773011548 168238.96342317166, 160177.57746205435 168238.96675572442, 160177.57763598862 168238.970087627, 160177.57790591038 168238.9759488732, 160177.57818886806 168238.98180949478, 160177.57832931637 168238.98514297017, 160177.57848280328 168238.9884758792, 160177.5787167561 168238.99433867363, 160177.57896374827 168239.00020091873, 160177.57908374016 168239.00353519508, 160177.57921677377 168239.00686898117, 160177.5794147486 168239.0127330956, 160177.57962576623 168239.018596751, 160177.57972529717 168239.02193170186, 160177.5798378725 168239.02526624047, 160177.57999986224 168239.03113146548, 160177.580174897 168239.03699629905, 160177.58025396304 168239.04033179095, 160177.5803460761 168239.04366696443, 160177.58047207448 168239.04953307446, 160177.58061111998 168239.05539887014, 160177.58066971845 168239.0587347908, 160177.58074136538 168239.0620704603, 160177.58083136758 168239.06793723017, 160177.58093441866 168239.07380377143, 160177.58097254712 168239.07713998278, 160177.58102372554 168239.08047603513, 160177.58107772827 168239.0863432542, 160177.5811447809 168239.09221030996, 160177.58116243806 168239.09554669398, 160177.58119314586 168239.09888299604, 160177.58121114696 168239.1047504278, 160177.58124219882 168239.11061779276, 160177.58123938396 168239.11395422727, 160177.58124962 168239.11729065, 160177.58124962 168246.86729065, 160177.57790908057 168247.00882537177, 160177.5678949017 168247.150044892, 160177.55122938525 168247.29063471113, 160177.52794964577 168247.43028173185, 160177.49810752782 168247.56867495665, 160177.46176949062 168247.70550618015, 160177.41901645993 168247.84047067564, 160177.36994364785 168247.9732678736, 160177.31466034084 168248.10360203122, 160177.25328965625 168248.23118289086, 160177.18596826826 168248.35572632664, 160177.11284610332 168248.476954977, 160177.03408600646 168248.59459886258, 160176.94986337848 168248.70839598734, 160176.86036578534 168248.81809292213, 160176.76579254057 168248.92344536894, 160176.66635426128 168249.0242187051, 160176.5622723991 168249.1201885058, 160176.45377874715 168249.2111410437, 160176.34111492353 168249.29687376515, 160176.22453183364 168249.3771957411, 160176.10428911104 168249.45192809243, 160175.98065453942 168249.5209043882, 160175.85390345627 168249.58397101637, 160175.72431813955 168249.64098752596, 160175.59218717917 168249.69182693964, 160175.45780483427 168249.73637603672, 160175.32147037785 168249.77453560522, 160175.18348743033 168249.80622066272, 160175.0441632834 168249.83136064583, 160174.90380821555 168249.8498995671, 160174.76273480122 168249.86179613988, 160172.70023480122 168249.98679613988, 160172.554605158 168249.9920763724, 160172.4088909121 168249.9902784859, 160172.26343588243 168249.98140672257, 160172.1185832761 168249.96548201572, 160171.9746748789 168249.9425419403, 160171.83205024863 168249.91264062445, 160171.69104591408 168249.8758486215, 160171.5519945808 168249.83225274377, 160171.4152243462 168249.7819558575, 160171.28105792528 168249.7250766403, 160171.14981188937 168249.661749301, 160171.02179591887 168249.5921232632, 160170.89731207283 168249.5163628123, 160170.776654076 168249.4346467083, 160170.66010662602 168249.34716776374, 160170.54794472136 168249.2541323888, 160170.44043301273 168249.15576010433, 160170.33782517846 168249.0522830238, 160170.240363326 168248.9439453057, 160170.14827742064 168248.83100257738, 160170.0617847429 168248.7137213319, 160169.98108937585 168248.59237829922, 160169.90638172356 168248.46725979325, 160169.83783806182 168248.33866103634, 160169.7756201223 168248.20688546254, 160169.71987471075 168248.07224400187, 160169.6707333608 168247.93505434637, 160169.62831202353 168247.79564020078, 160169.59271079383 168247.65433051856, 160169.56401367427 168247.51145872578, 160169.54228837692 168247.36736193436, 160169.52758616352 168247.22238014665, 160169.40258616352 168245.59738014665, 160169.3949912544 168245.4535939799, 160169.39430419993 168245.3096090073, 160169.51930419993 168238.8096090073, 160169.52562495318 168238.66430117068, 160169.53898098585 168238.51947045675, 160169.55934090487 168238.37545728724, 160169.58665685466 168238.23260016215, 160169.62086462963 168238.0912348643, 160169.6618838251 168237.95169367, 160169.70961802625 168237.81430456802, 160169.7639550348 168237.6793904887, 160169.82476713273 168237.54726854482, 160169.89191138238 168237.41824928642, 160169.9652299626 168237.29263597066, 160170.0445505395 168237.1707238491, 160170.12968667166 168237.05279947375, 160170.2204382483 168236.93914002346, 160170.31659195968 168236.83001265253, 160170.41792179842 168236.72567386262, 160170.5241895908 168236.62636889995, 160170.63514555647 168236.53233117887, 160170.75052889567 168236.44378173316, 160170.87006840218 168236.3609286965, 160170.99348310078 168236.2839668133, 160171.12048290775 168236.21307698087, 160171.25076931252 168236.14842582442, 160171.38403607954 168236.09016530513, 160171.51996996798 168236.03843236322, 160171.65825146792 168235.99334859592, 160171.7985555515 168235.9550199717, 160171.94055243678 168235.92353658125, 160172.08390836293 168235.89897242564, 160172.2282863747 168235.8813852424, 160172.3733471145 168235.8708163699, 160172.51874962 168235.86729065))"^^ . -_:Bccd153013e8d39159a1386664b52baa8 . - . - . - "9197354"^^ . -_:Be01be9360e4dfb033470d29771f94a26 " POLYGON ((191160.45195027534 223673.65576376487, 191351.0524982662 223690.47001247946, 191388.0631114387 223692.2581880642, 191387.38385393526 223683.67357679084, 191351.48612715196 223683.01332873292, 191206.85351506388 223670.29530087672, 191161.26521162994 223665.45604893658, 191160.45195027534 223673.65576376487))"^^ . -_:Be01be9360e4dfb033470d29771f94a26 . -_:Bbfaa89dfe34b30010ef1f7aa141e9fe8 "2021-01-11T08:00:00Z"^^ . -_:Bbfaa89dfe34b30010ef1f7aa141e9fe8 "2021-01-22T14:00:00Z"^^ . -_:Bbfaa89dfe34b30010ef1f7aa141e9fe8 . - . - _:B6d29089cac520f817fa2da565e5f958f . - . -_:B72598c6858d088da7d3d25e4a640ce08 "2021-01-31T23:00:00Z"^^ . -_:B72598c6858d088da7d3d25e4a640ce08 "2021-02-19T22:30:00Z"^^ . -_:B72598c6858d088da7d3d25e4a640ce08 . - . - . - "9197114"^^ . - . - . - _:B59149b8ba210ccab319d9b3e32c1ddfe . - _:B8896060a4f5e386e46e973e5ffbc8fbc . - . - "10590397"^^ . - _:B11623c55c1ab9e6c2dd0bf16f1e280b8 . - _:B02a887c34bc5aa0c42b37488d61b1574 . - . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T14:54:46.903Z"^^ . - "2840 Rumst, Jeroen Boschlaan 23: Parkeerverbod laad- en loszone"^^ . - _:Bc8d6e752a870ff96c6a39a08d245b4c4 . - "2021-01-06T14:54:46.903Z"^^ . - "2021-01-06T18:04:39.033Z"^^ . -_:Bdfbd4fbcd994b458a7a7201e84d89aea " POLYGON ((69515.68094104598 163280.33009271417, 69610.17651786553 163273.21844994463, 69739.46985057215 163240.289370141, 69738.24815992337 163234.6470189644, 69608.96627234787 163268.3307893537, 69513.29504844519 163272.8187013194, 69515.68094104598 163280.33009271417))"^^ . -_:Bdfbd4fbcd994b458a7a7201e84d89aea . - . - . - _:B1cab394929f807dc1c9d25b1a14ca149 . - . -_:Bc2623d413cc7638797ba72c5c45975dc "Stad Sint-Niklaas"^^ . -_:Bc2623d413cc7638797ba72c5c45975dc . -_:Bc2623d413cc7638797ba72c5c45975dc . -_:B386a6308462421f3c6e9c1916463c3b2 "Stad Aalst"^^ . -_:B386a6308462421f3c6e9c1916463c3b2 . -_:B386a6308462421f3c6e9c1916463c3b2 . - . - _:B8efb6464dde7dfaeb9df93198c359b14 . - . -_:B7e4588eab28352a074b617dc4f12e3e9 "2021-01-14T10:00:00Z"^^ . -_:B7e4588eab28352a074b617dc4f12e3e9 "2021-01-14T19:00:00Z"^^ . -_:B7e4588eab28352a074b617dc4f12e3e9 . -_:B076dc58b13c86c0cc54f40adfa05cbc6 "Politiezone Leuven"^^ . -_:B076dc58b13c86c0cc54f40adfa05cbc6 . -_:B076dc58b13c86c0cc54f40adfa05cbc6 . -_:Bf765709b93efce410c1f658d3303bc34 "2021-01-18T08:00:00Z"^^ . -_:Bf765709b93efce410c1f658d3303bc34 "2021-02-05T21:00:00Z"^^ . -_:Bf765709b93efce410c1f658d3303bc34 . -_:Bf1e9ef27044da4e27548e862f8c5e2fc "2021-01-06T00:00:00Z"^^ . -_:Bf1e9ef27044da4e27548e862f8c5e2fc "2021-01-08T00:00:00Z"^^ . -_:Bf1e9ef27044da4e27548e862f8c5e2fc . -_:B65bf02e9ffdb7e587fb868197d95fb00 " POLYGON ((140966.168182794 208028.856880975, 140973.177008308 208043.471027792, 140991.966625643 208054.655323825, 140994.20348485 208050.330729359, 140975.562991462 208040.786796744, 140969.299785683 208027.514765451, 140966.168182794 208028.856880975))"^^ . -_:B65bf02e9ffdb7e587fb868197d95fb00 . -_:B7254ec8ea4675d9eee594064a3bd4df4 "Stad Kortrijk"^^ . -_:B7254ec8ea4675d9eee594064a3bd4df4 . -_:B7254ec8ea4675d9eee594064a3bd4df4 . - . - . - _:B715ef0ae88d3af0daefc86ae70936d9a . - . -_:B747a72281dc774b82cf59dd894426daa " MULTIPOLYGON (((71601.70879325763 170660.86798544694, 71601.74621981726 170663.3659324171, 71596.23596919695 170663.44849500898, 71596.19854000506 170660.95054807793, 71601.70879325763 170660.86798544694)), ((71595.94034132389 170660.48333154712, 71595.9777706356 170662.98127847165, 71590.46752011016 170663.0638471339, 71590.4300881662 170660.5659002494, 71595.94034132389 170660.48333154712)))"^^ . -_:B747a72281dc774b82cf59dd894426daa . - . - _:Bc857560bb6686086619e59d1fbe06552 . - . -_:B42ea4fbd077babddbbedb8c56f3ac4d5 "Gemeente Bornem"^^ . -_:B42ea4fbd077babddbbedb8c56f3ac4d5 . -_:B42ea4fbd077babddbbedb8c56f3ac4d5 . -_:B5a43357e16bf05741b36522ff1ea50b9 "Gemeente Tervuren"^^ . -_:B5a43357e16bf05741b36522ff1ea50b9 . -_:B5a43357e16bf05741b36522ff1ea50b9 . - . - . - "9196960"^^ . -_:Bf56f2d86166aacecdbe10e22fff05133 "https://gipod.vlaanderen.be"@nl-BE . -_:Bf56f2d86166aacecdbe10e22fff05133 "10590351"^^ . -_:Bf56f2d86166aacecdbe10e22fff05133 . - . - . - "9197063"^^ . -_:B86e9502ec4a0699ba709d2df67f21898 "Stad Hasselt"^^ . -_:B86e9502ec4a0699ba709d2df67f21898 . -_:B86e9502ec4a0699ba709d2df67f21898 . -_:B53d30e1c54d49ea29d4ced2168b104b0 " POLYGON ((146419.240171641 164345.608603172, 146421.209787147 164345.261306817, 146424.682750701 164364.957461877, 146422.713135194 164365.304758233, 146419.240171641 164345.608603172))"^^ . -_:B53d30e1c54d49ea29d4ced2168b104b0 . -_:Bff9c528d8b7641097d2a939373b29571 "Gemeente Hamme"^^ . -_:Bff9c528d8b7641097d2a939373b29571 . -_:Bff9c528d8b7641097d2a939373b29571 . - . - "2021-01-06T15:27:46.443Z"^^ . - _:Bb61a2744b697518282e0e9b126fd865a . - _:B02a2e167c901548ad4294d439dd6905a . - _:B7e7081e8e638c98abea87621b06d3689 . - "2021-01-06T15:26:24.207Z"^^ . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - _:Bd44374711b33f21b96a7596116f19e00 . - . - _:B34f6d2384772f14827f6a4d4f83a9d01 . - "2021-01-06T18:04:29.137Z"^^ . - "Lange Dijkstraat 92: werken in voetpad"^^ . - "10590368"^^ . - "Snelheidsbeperking"@nl-BE . -_:B949ad322d189dfd48f935b9c661e91a8 " POLYGON ((72970.62733999577 168785.37761287857, 72965.15944908657 168784.69309164304, 72964.84727165668 168787.17185769044, 72970.31516002594 168787.85637823585, 72975.78304688178 168788.54090439342, 72976.09522939163 168786.06213972252, 72970.62733999577 168785.37761287857))"^^ . -_:B949ad322d189dfd48f935b9c661e91a8 . -_:Bf97926170a04cf173d43eed7a95555af "Gemeente Drogenbos"^^ . -_:Bf97926170a04cf173d43eed7a95555af . -_:Bf97926170a04cf173d43eed7a95555af . - . - _:B22bef797dfc603dc747542d467fc6dd3 . - . - . - . - "9197055"^^ . -_:B4c36cf2deeb3df6a604c600bed7bf38e "Stad Dendermonde"^^ . -_:B4c36cf2deeb3df6a604c600bed7bf38e . -_:B4c36cf2deeb3df6a604c600bed7bf38e . - . - _:B2f0c66eb76b307f0a89fae86b7101617 . - . -_:B1b68cc2867ff82a27fa057b1e25d7582 "https://gipod.vlaanderen.be"@nl-BE . -_:B1b68cc2867ff82a27fa057b1e25d7582 "10590548"^^ . -_:B1b68cc2867ff82a27fa057b1e25d7582 . - . - . - _:B183efe1939299fa8e55e27be381b8e50 . - . - . - . - "9197130"^^ . - . - "2021-01-06T14:32:31.22Z"^^ . - _:B83bdbf9c3300f1f5769bdf6663042192 . - _:B7e8bde071d030b1b4a4beb0d6434faee . - "10590432"^^ . - "2021-01-06T14:46:54.823Z"^^ . - "2021-01-06T18:04:49.7Z"^^ . - "Container"^^ . - _:Bff9c528d8b7641097d2a939373b29571 . - . - _:B2bdd5c6338062c8b9df3bb0a27fe640a . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B9693f8857f6c0034ebd65f2e21a4c644 . - . - . -_:B621b8f532ecf61433b83c9163099742c "https://gipod.vlaanderen.be"@nl-BE . -_:B621b8f532ecf61433b83c9163099742c "10590552"^^ . -_:B621b8f532ecf61433b83c9163099742c . -_:Bad260bfa2fd7140279c5f2ef8bc44d9a "2021-01-14T05:00:00Z"^^ . -_:Bad260bfa2fd7140279c5f2ef8bc44d9a "2021-01-22T18:00:00Z"^^ . -_:Bad260bfa2fd7140279c5f2ef8bc44d9a . -_:Be47de5c37f0ff7266204b843b4f77a37 "https://gipod.vlaanderen.be"@nl-BE . -_:Be47de5c37f0ff7266204b843b4f77a37 "10590590"^^ . -_:Be47de5c37f0ff7266204b843b4f77a37 . -_:B2acc4a4d23fbf2d28550a78f1bd59a24 "Gemeente Meise"^^ . -_:B2acc4a4d23fbf2d28550a78f1bd59a24 . -_:B2acc4a4d23fbf2d28550a78f1bd59a24 . -_:B502b1fe71bcbdaff18ca6a139b8f737f "Gemeente Koksijde"^^ . -_:B502b1fe71bcbdaff18ca6a139b8f737f . -_:B502b1fe71bcbdaff18ca6a139b8f737f . -_:B337ad647f64a339581ecb9999d77acda "Stad Hasselt"^^ . -_:B337ad647f64a339581ecb9999d77acda . -_:B337ad647f64a339581ecb9999d77acda . -_:Bf63aed11e551b2ac3b50e101784329bc "2021-01-14T06:00:00Z"^^ . -_:Bf63aed11e551b2ac3b50e101784329bc "2021-01-15T18:00:00Z"^^ . -_:Bf63aed11e551b2ac3b50e101784329bc . -_:B1f7f00bc4bb20e1856dac2349160dda3 " POLYGON ((200285.041372709 195391.292061819, 200285.041372709 195391.292061819, 200290.409834804 195392.559615369, 200293.243189799 195381.002509468, 200288.471223492 195379.958641838, 200285.041372709 195391.292061819))"^^ . -_:B1f7f00bc4bb20e1856dac2349160dda3 . -_:B699087a36a9a05b2de41551dab9596a9 " POLYGON ((147141.971441615 180503.489699355, 147141.41998685 180503.28534037, 147140.839259673 180503.192491572, 147140.251577105 180503.214721091, 147139.679523456 180503.351174656, 147139.145082428 180503.596608436, 147138.668792289 180503.941590546, 147138.268956602 180504.372863518, 147137.96094083 180504.873853774, 147137.756581844 180505.425308539, 147137.663733047 180506.006035716, 147137.685962565 180506.593718284, 147137.822416131 180507.165771933, 147138.06784991 180507.700212961, 147138.412832021 180508.1765031, 147138.844104993 180508.576338786, 147139.345095249 180508.884354559, 147157.478563577 180517.712494048, 147158.030018342 180517.916853034, 147158.610745518 180518.009701831, 147159.198428087 180517.987472313, 147159.770481735 180517.851018747, 147160.304922764 180517.605584968, 147160.781212902 180517.260602857, 147161.181048589 180516.829329885, 147161.489064361 180516.328339629, 147161.693423347 180515.776884864, 147161.786272144 180515.196157687, 147161.764042626 180514.608475119, 147161.62758906 180514.03642147, 147161.382155281 180513.501980442, 147161.037173171 180513.025690303, 147160.605900198 180512.625854617, 147160.104909942 180512.317838844, 147141.971441615 180503.489699355))"^^ . -_:B699087a36a9a05b2de41551dab9596a9 . - "Kraan Ruiming van puin van riolen, bermen en grachten in naam van Stad Kortrijk."^^ . - "2021-01-06T14:44:50.49Z"^^ . - "10590413"^^ . - "2021-01-06T14:45:13.087Z"^^ . - "2021-01-06T18:04:44.793Z"^^ . - . - . - . - _:B1f799de34684d804ce4f1c183d309ba3 . - _:B72598c6858d088da7d3d25e4a640ce08 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B83d1c90f9c49df818758b17e43e8b5cd . - . - _:B8652f81a1c7a30f0845ed298b024ea5f . - _:Bafbdbc308babf7ff74e61e445dbf2da6 . - . - . - _:Bb7057d4e6693feac6667c19035d3d3d6 . - . -_:B6d29089cac520f817fa2da565e5f958f " MULTIPOLYGON (((25342.3067263747 200679.074335255, 25348.2344032722 200683.697177615, 25354.2739231301 200687.201590372, 25350.3967005053 200692.905581349, 25342.9405031499 200688.692829843, 25340.1071481549 200693.091986283, 25335.7452727019 200690.445036222, 25342.3067263747 200679.074335255)), ((25336.5281734243 200675.756327432, 25338.3549417763 200676.874757035, 25337.2737931598 200678.477839466, 25335.4097438209 200677.583095784, 25336.5281734243 200675.756327432)))"^^ . -_:B6d29089cac520f817fa2da565e5f958f . -_:B71861004d17562ca734960aba3134283 "Stad Turnhout"^^ . -_:B71861004d17562ca734960aba3134283 . -_:B71861004d17562ca734960aba3134283 . -_:Bafbdbc308babf7ff74e61e445dbf2da6 "Stad Kortrijk"^^ . -_:Bafbdbc308babf7ff74e61e445dbf2da6 . -_:Bafbdbc308babf7ff74e61e445dbf2da6 . - . - "2021-01-06T18:04:37Z"^^ . - "2021-01-06T15:02:39.113Z"^^ . - "10590388"^^ . - _:B2ef9ba39a4cdc6523dfc2d80dc09cbb5 . - "2021-01-06T15:02:39.113Z"^^ . - _:B3b3edc706c6c72ca705caff67b48a3c6 . - _:B71861004d17562ca734960aba3134283 . - _:B3aa48cb3ad4b143a2091b2ca3bef9c3e . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - . - _:B04975fca22d5bd582bcac20a849a00c4 . - "Wegeniswerken Plaatsen van signalisatie voor nutswerken.\n\nDeze aanvraag betreft pagina 4 van 4 pagina's !"^^ . - . -_:B3b9131646e8134379924ca8dc82908ca "2021-01-15T05:00:00Z"^^ . -_:B3b9131646e8134379924ca8dc82908ca "2021-01-16T19:00:00Z"^^ . -_:B3b9131646e8134379924ca8dc82908ca . - _:B6f0651555d9f314faad60457f42be97e . - "2021-01-06T13:17:42.847Z"^^ . - "10590530"^^ . - "2021-01-06T13:17:42.847Z"^^ . - _:B551904432ebf19c55b492dceb57cdb46 . - . - . - "Bouwlift, vaste (bouw-)kraan "^^ . - _:B7b825a853d895934d03713edb9a1224f . - . - _:Bd406762db6a01711c0572b38c3e5414a . - . - _:Be79329ea18e3c8a5f3d24c69c32d397d . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:05:27.02Z"^^ . -_:B59149b8ba210ccab319d9b3e32c1ddfe "Gemeente Rumst"^^ . -_:B59149b8ba210ccab319d9b3e32c1ddfe . -_:B59149b8ba210ccab319d9b3e32c1ddfe . -_:B4f7d32f9b8f72e1aa14df44a9c536c10 " POLYGON ((190158.33379769782 224319.3191513531, 190156.8094365317 224314.03647996206, 190154.40193168752 224314.72745623533, 190155.92629509635 224320.0101262005, 190157.4506553548 224325.2927912725, 190159.85815571356 224324.60181785375, 190158.33379769782 224319.3191513531))"^^ . -_:B4f7d32f9b8f72e1aa14df44a9c536c10 . - "2021-01-06T13:24:40.317Z"^^ . - . - _:Ba0a975f9b52748ce7a562386ff13418a . - _:B30c6e021ccad7731b1dc78be1815f3ef . - "10590514"^^ . - . - . - _:B0d8a0c2f042f44af45521045af6814a2 . - "9600 Ronse - Hogerlucht 47 - container"^^ . - _:B4c72b3cb5ce785c4fea35f879d9b4470 . - "2021-01-06T13:25:01.567Z"^^ . - . - _:B4bbc057628364cdc723560a8f45327cf . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - "2021-01-06T18:05:21.107Z"^^ . -_:B92f70eae04a7e2fc1418c533594e530a "https://gipod.vlaanderen.be"@nl-BE . -_:B92f70eae04a7e2fc1418c533594e530a "10590519"^^ . -_:B92f70eae04a7e2fc1418c533594e530a . -_:B8b393797ec177d413efa54f4f47bcf9d "Gemeente Heist-op-den-Berg"^^ . -_:B8b393797ec177d413efa54f4f47bcf9d . -_:B8b393797ec177d413efa54f4f47bcf9d . -_:B287be79cbcc13cd0a947361f43672c5b "2021-02-20T06:00:00Z"^^ . -_:B287be79cbcc13cd0a947361f43672c5b "2021-02-20T16:00:00Z"^^ . -_:B287be79cbcc13cd0a947361f43672c5b . - _:B793027b93d20d3d2436bd8c299dd3df6 . - _:B079946227c9438a37a5295f02c985530 . - "2021-01-06T18:04:22.143Z"^^ . - . - . - "8000 Brugge, Rode-Haanstraat 3: Doorlopende vergunning"^^ . - "10590358"^^ . - _:Bbddb0e518d31887851b7cedd17c02cfc . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:B6ee5e3dd0a877a618286d888fbc51600 . - . - . - "2021-01-06T15:49:57.93Z"^^ . - _:B52cfba17ee38fd79ee713c96ed96f012 . - "2021-01-06T15:49:57.93Z"^^ . -_:B954b1356ca3be49980358b266be7185b " POLYGON ((217673.59383116564 180665.38600781746, 217672.56509309646 180659.98629868496, 217675.02604338323 180659.5201087594, 217676.05477901147 180664.91981888562, 217673.59383116564 180665.38600781746))"^^ . -_:B954b1356ca3be49980358b266be7185b . -_:B10ee9f7864f928e1efe560ab563bfcf3 "2021-01-20T07:00:00Z"^^ . -_:B10ee9f7864f928e1efe560ab563bfcf3 "2021-01-27T20:00:00Z"^^ . -_:B10ee9f7864f928e1efe560ab563bfcf3 . -_:B6df4668f97c6741c302bf4be16b76599 "Politiezone Leuven"^^ . -_:B6df4668f97c6741c302bf4be16b76599 . -_:B6df4668f97c6741c302bf4be16b76599 . -_:Bcce77798d3a689528c52c86b37308d5e "2021-01-10T23:00:00Z"^^ . -_:Bcce77798d3a689528c52c86b37308d5e "2021-01-11T22:30:00Z"^^ . -_:Bcce77798d3a689528c52c86b37308d5e . - . - _:B949ad322d189dfd48f935b9c661e91a8 . - . -_:B8c5c205ad2b8bb45016fdf302a0419b7 "2021-01-21T06:00:00Z"^^ . -_:B8c5c205ad2b8bb45016fdf302a0419b7 "2021-02-19T22:30:00Z"^^ . -_:B8c5c205ad2b8bb45016fdf302a0419b7 . - . - _:B9592d18b6010115929a60f7555da0727 . - . -_:B4272cba92665121e08c5b25dabb4b75c "Stad Turnhout"^^ . -_:B4272cba92665121e08c5b25dabb4b75c . -_:B4272cba92665121e08c5b25dabb4b75c . -_:Bd73840cade6318e39b3a373f2858c52e "Stad Hasselt"^^ . -_:Bd73840cade6318e39b3a373f2858c52e . -_:Bd73840cade6318e39b3a373f2858c52e . -_:B5d0961c1cbe3403f95bb18f5e2d763a2 "2021-01-24T23:00:00Z"^^ . -_:B5d0961c1cbe3403f95bb18f5e2d763a2 "2021-01-27T22:30:00Z"^^ . -_:B5d0961c1cbe3403f95bb18f5e2d763a2 . - . - . - "9196981"^^ . -_:Beb3acd23a3bc1a67255329c8be083940 "Politiezone Leuven"^^ . -_:Beb3acd23a3bc1a67255329c8be083940 . -_:Beb3acd23a3bc1a67255329c8be083940 . -_:B04975fca22d5bd582bcac20a849a00c4 "2021-03-08T05:00:00Z"^^ . -_:B04975fca22d5bd582bcac20a849a00c4 "2021-03-12T22:30:00Z"^^ . -_:B04975fca22d5bd582bcac20a849a00c4 . - . - . - "9197084"^^ . - _:B1db1211702ecb8fdb49262bc1a828a6d . - "10590474"^^ . - . - "2021-01-06T18:05:04.657Z"^^ . - "2021-01-06T13:57:39.943Z"^^ . - . - _:B9c1a589d1f2b2b1eae00b53b15a07645 . - . - "2021-01-06T13:58:35.47Z"^^ . - _:B4dd1eaae9e68b94b6d1edd6c185475d3 . - _:B9105ba7bc9b454c424def620f55e8060 . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - _:Bfe1ab231461adccbf4470720a0efbb7e . - "3980 Tessenderlo, Kolmen 60: Laden & lossen - met hinder"^^ . - . -_:B7a4aa6a2b58dfb826e8fab09e99c6859 "2021-02-01T05:00:00Z"^^ . -_:B7a4aa6a2b58dfb826e8fab09e99c6859 "2021-02-14T21:00:00Z"^^ . -_:B7a4aa6a2b58dfb826e8fab09e99c6859 . -_:Bdadb49a628b919297dda7e478ea1d458 " POLYGON ((191159.88514910135 223650.89769429527, 191296.30006834437 223662.42977409624, 191381.93259291374 223663.8604878625, 191451.87939825648 223662.5557685513, 191489.2731284798 223663.22871811967, 191485.82362340775 223673.64529171772, 191415.48506251676 223677.18445980176, 191336.57819218643 223676.5529767461, 191254.36216324076 223668.8091286756, 191159.44288597885 223659.47339513246, 191159.88514910135 223650.89769429527))"^^ . -_:Bdadb49a628b919297dda7e478ea1d458 . -_:B45bb39b56303c4a7006860ac979d1a29 "Stad Mechelen"^^ . -_:B45bb39b56303c4a7006860ac979d1a29 . -_:B45bb39b56303c4a7006860ac979d1a29 . -_:B740eb051eba43a5611371ddc30ae3c67 " POLYGON ((163171.4399788629 209039.98442828326, 163180.8951646189 209036.72874673826, 163181.5463009279 209038.61978389026, 163172.0911151719 209041.87546543425, 163171.4399788629 209039.98442828326))"^^ . -_:B740eb051eba43a5611371ddc30ae3c67 . - . - . - "9196919"^^ . -_:B25e024da598c0cc368a5cd7101324920 "Politiezone Leuven"^^ . -_:B25e024da598c0cc368a5cd7101324920 . -_:B25e024da598c0cc368a5cd7101324920 . -_:B2bdd5c6338062c8b9df3bb0a27fe640a "Gemeente Hamme"^^ . -_:B2bdd5c6338062c8b9df3bb0a27fe640a . -_:B2bdd5c6338062c8b9df3bb0a27fe640a . -_:B29b73fb73b8058012596c3ddddc13add "Gemeente Bornem"^^ . -_:B29b73fb73b8058012596c3ddddc13add . -_:B29b73fb73b8058012596c3ddddc13add . -_:B58a3e6b48c9df8309e0e8be501cfa665 "2021-02-01T06:00:00Z"^^ . -_:B58a3e6b48c9df8309e0e8be501cfa665 "2021-03-31T17:00:00Z"^^ . -_:B58a3e6b48c9df8309e0e8be501cfa665 . - _:Befe7a910e2256da64b278bf858b0aeaa . - "MobilityHindranceWasImportedFromLegacy"@nl-BE . - . - "2811 Mechelen, Kapellebaan 38: Nutswerken / Verlenging"^^ . - . - . - "2021-01-06T14:33:04.653Z"^^ . - "10590431"^^ . - "2021-01-06T14:51:49.157Z"^^ . - _:B054f47eba38f668342fe128caa4e8ee8 . - _:Bdb962510044918d11ac26e4e5b4a7cfd . - "2021-01-06T18:04:49.55Z"^^ . - _:Bfe648790bda1c41f2143f751aee80a35 . - . - _:Bdae77f0e31c13f592e0cf7a0904ef9ee . -_:Bc62ccceb9774caaaaf750f128eb04743 " MULTIPOLYGON (((97333.85718414078 160452.8637570646, 97333.95532554598 160452.86590530683, 97334.0532433263 160452.87286653192, 97334.05324332652 160452.87286653195, 97344.49074332608 160453.8728665319, 97344.4907433263 160453.87286653192, 97344.58820158924 160453.88462396967, 97344.68496554931 160453.90114929536, 97344.78080209366 160453.92240269805, 97344.87548034366 160453.94833297646, 97344.96877221108 160453.97887766224, 97345.06045294768 160454.01396317055, 97345.15030168653 160454.05350497738, 97345.23810197413 160454.09740782302, 97345.32364229191 160454.1455659417, 97345.40671656575 160454.19786331625, 97345.48712466244 160454.25417395774, 97345.56467287184 160454.31436220888, 97345.63917437353 160454.37828307095, 97345.71044968684 160454.44578255294, 97345.77832710333 160454.51669804272, 97345.84264310032 160454.59085869865, 97345.90324273497 160454.66808586122, 97345.95998001746 160454.74819348342, 97346.01271826267 160454.830988579, 97346.06133041959 160454.91627168728, 97346.10569937724 160455.0038373538, 97346.14571824693 160455.09347462523, 97346.1812906197 160455.1849675575, 97346.21233079859 160455.2780957361, 97346.23876400507 160455.37263480717, 97346.26052655926 160455.4683570177, 97346.27756603326 160455.5650317646, 97346.28984137744 160455.66242614988, 97346.29732301948 160455.76030554195, 97346.2999929354 160455.85843414077, 97346.29784469317 160455.95657554595, 97346.29088346809 160456.0544933263, 97346.27912603035 160456.15195158924, 97346.26260070463 160456.2487155493, 97346.24134730194 160456.34455209365, 97346.21541702354 160456.43923034365, 97346.18487233778 160456.53252221108, 97346.14978682944 160456.62420294769, 97346.11024502262 160456.71405168652, 97346.06634217697 160456.80185197413, 97346.01818405831 160456.8873922919, 97345.96588668376 160456.97046656572, 97345.90957604226 160457.05087466244, 97345.84938779111 160457.1284228718, 97345.78546692905 160457.2029243735, 97345.71796744705 160457.27419968683, 97345.64705195728 160457.3420771033, 97345.57289130134 160457.4063931003, 97345.49566413877 160457.46699273496, 97345.41555651657 160457.52373001745, 97345.332761421 160457.57646826265, 97345.24747831271 160457.62508041956, 97345.15991264618 160457.66944937722, 97345.07027537476 160457.7094682469, 97344.9787824425 160457.7450406197, 97344.88565426388 160457.77608079856, 97344.79111519284 160457.80251400504, 97344.69539298228 160457.82427655923, 97344.5987182354 160457.8413160332, 97344.50132385011 160457.8535913774, 97344.40344445805 160457.86107301945, 97344.30531585922 160457.86374293538, 97344.20717445403 160457.86159469315, 97344.1092566737 160457.85463346806, 97344.10925667349 160457.85463346803, 97333.67175667392 160456.8546334681, 97333.6717566737 160456.85463346806, 97333.57429841076 160456.8428760303, 97333.47753445069 160456.82635070462, 97333.38169790634 160456.80509730193, 97333.28701965635 160456.77916702352, 97333.19372778892 160456.74862233773, 97333.10204705232 160456.71353682943, 97333.01219831347 160456.6739950226, 97332.92439802588 160456.63009217696, 97332.83885770809 160456.58193405828, 97332.75578343426 160456.52963668373, 97332.67537533757 160456.47332604224, 97332.59782712816 160456.4131377911, 97332.52332562648 160456.34921692903, 97332.45205031316 160456.28171744704, 97332.38417289668 160456.21080195726, 97332.31985689969 160456.13664130133, 97332.25925726503 160456.05941413876, 97332.20251998254 160455.97930651656, 97332.14978173733 160455.896511421, 97332.10116958042 160455.8112283127, 97332.05680062277 160455.72366264617, 97332.01678175307 160455.63402537475, 97331.9812093803 160455.5425324425, 97331.95016920142 160455.44940426387, 97331.92373599493 160455.3548651928, 97331.90197344075 160455.25914298228, 97331.88493396675 160455.1624682354, 97331.87265862257 160455.0650738501, 97331.86517698053 160454.96719445803, 97331.86250706461 160454.8690658592, 97331.86465530684 160454.77092445403, 97331.87161653192 160454.6730066737, 97331.88249909379 160454.58162164016, 97331.89757413656 160454.49083398908, 97331.91680974013 160454.40083595543, 97331.94016517478 160454.3118181023, 97331.96759098736 160454.22396891727, 97331.99902910611 160454.13747441344, 97332.03441296353 160454.0525177354, 97332.07366763735 160453.96927877166, 97332.1167100092 160453.88793377345, 97332.16344894054 160453.80865498184, 97332.21378546576 160453.73161026277, 97332.2676130016 160453.65696275182, 97332.32481757291 160453.58487050864, 97332.38527805393 160453.51548618232, 97332.44886642483 160453.44895668817, 97332.51544804273 160453.38542289668, 97332.5848819268 160453.3250193351, 97332.65702105679 160453.26787390283, 97332.73171268431 160453.21410760036, 97332.80879865632 160453.16383427317, 97332.8881157499 160453.11716037072, 97332.96949601796 160453.07418472093, 97333.05276714482 160453.03499832106, 97333.13775281108 160452.9996841449, 97333.2242730669 160452.9683169672, 97333.31214471313 160452.9409632052, 97333.40118168914 160452.9176807782, 97333.49119546682 160452.89851898467, 97333.5819954498 160452.88351839807, 97333.67338937691 160452.87271078082, 97333.76518372945 160452.86611901718, 97333.85718414078 160452.8637570646)), ((97320.97970162675 160442.3012652037, 97321.07784562287 160442.30329162496, 97321.17577196848 160442.31013130292, 97321.1757719685 160442.31013130292, 97321.1757719685 160442.31013130292, 97364.8007719685 160446.43513130292, 97364.8007719685 160446.43513130292, 97364.82519188127 160446.43759161717, 97364.92175678366 160446.45030459546, 97365.01758825262 160446.46770372597, 97365.11245901429 160446.4897477449, 97365.20614407312 160446.5163843727, 97365.29842124564 160446.54755043788, 97365.38907168731 160446.58317202705, 97365.47788041152 160446.62316466, 97365.5646367995 160446.66743349025, 97365.64913509983 160446.7158735298, 97365.73117491628 160446.7683698983, 97365.81056168326 160446.8247980953, 97365.88710712708 160446.8850242957, 97365.9606297126 160446.9489056671, 97366.03095507361 160447.01629070836, 97366.09791642652 160447.08701960914, 97366.16135496575 160447.16092462878, 97366.22112024047 160447.23783049415, 97366.27707051135 160447.31755481524, 97366.32907308673 160447.3999085179, 97366.3770046373 160447.4846962921, 97366.4207514886 160447.57171705508, 97366.46020989056 160447.66076442844, 97366.49528626367 160447.7516272274, 97366.52589742078 160447.84408996179, 97366.55197076449 160447.93793334693, 97366.57344445924 160448.0329348239, 97366.59026757801 160448.12886908712, 97366.60240022311 160448.22550861893, 97366.60981362074 160448.32262422904, 97366.61249018929 160448.419985598, 97366.61042358102 160448.51736182364, 97366.60361869709 160448.61452196847, 97366.59198223978 160448.71199475043, 97366.57557703638 160448.8087791482, 97366.55444260844 160448.9046419998, 97366.52862987068 160448.99935236317, 97366.49820100822 160449.09268207275, 97366.46322932687 160449.18440628907, 97366.42379907645 160449.2743040405, 97366.38000524792 160449.36215875545, 97366.33195334442 160449.44775878426, 97366.27975912721 160449.5308979089, 97366.22354833674 160449.61137584, 97366.16345638971 160449.68899869913, 97366.09962805288 160449.76357948605, 97366.03221709433 160449.8349385291, 97365.96138591293 160449.9029039181, 97365.88730514723 160449.96731191844, 97365.81015326426 160450.02800736568, 97365.7301161297 160450.0848440391, 97365.64738655995 160450.13768501423, 97365.56216385786 160450.1864029925, 97365.47465333235 160450.23088060803, 97365.38506580394 160450.27101071033, 97365.29361709686 160450.30669662255, 97365.20052751902 160450.33785237413, 97365.10602133138 160450.36440290813, 97365.01032620763 160450.38628426206, 97364.9136726857 160450.40344372173, 97364.81629361238 160450.41583994858, 97364.71842358241 160450.42344307894, 97364.62029837325 160450.42623479626, 97364.52215437713 160450.424208375, 97364.42422803152 160450.41736869706, 97364.42422803151 160450.41736869706, 97364.42422803151 160450.41736869706, 97320.79922803151 160446.29236869706, 97320.79922803151 160446.29236869706, 97320.77480811873 160446.2899083828, 97320.67824321635 160446.27719540452, 97320.58241174738 160446.259796274, 97320.48754098572 160446.23775225508, 97320.39385592689 160446.2111156273, 97320.30157875437 160446.1799495621, 97320.21092831269 160446.14432797293, 97320.12211958849 160446.10433533997, 97320.0353632005 160446.06006650973, 97319.95086490018 160446.01162647016, 97319.86882508373 160445.9591301017, 97319.78943831674 160445.90270190468, 97319.71289287292 160445.84247570427, 97319.6393702874 160445.7785943329, 97319.5690449264 160445.71120929162, 97319.50208357349 160445.64048039084, 97319.43864503426 160445.5665753712, 97319.37887975953 160445.48966950583, 97319.32292948866 160445.40994518474, 97319.27092691328 160445.32759148208, 97319.22299536271 160445.2428037079, 97319.17924851141 160445.1557829449, 97319.13979010945 160445.06673557154, 97319.10471373633 160444.97587277257, 97319.07410257922 160444.8834100382, 97319.04802923552 160444.78956665305, 97319.02655554077 160444.6945651761, 97319.009732422 160444.59863091286, 97318.99759977689 160444.50199138105, 97318.99018637926 160444.40487577094, 97318.98750981071 160444.30751440197, 97318.98957641899 160444.21013817634, 97318.99638130292 160444.1129780315, 97319.00715042351 160444.02157956027, 97319.02211276327 160443.930773267, 97319.04123664075 160443.84075142624, 97319.06448156279 160443.75170465143, 97319.09179831027 160443.6638214914, 97319.12312904235 160443.57728803123, 97319.15840741887 160443.49228749797, 97319.19755874097 160443.40899987295, 97319.24050010908 160443.32760151048, 97319.28714059856 160443.2482647646, 97319.3373814522 160443.17115762402, 97319.39111628935 160443.09644335642, 97319.44823133112 160443.02428016285, 97319.50860564134 160442.9548208426, 97319.57211138263 160442.88821246978, 97319.63861408706 160442.8245960819, 97319.70797294092 160442.76410638113, 97319.78004108279 160442.7068714492, 97319.85466591462 160442.65301247616, 97319.93168942479 160442.6026435037, 97320.01094852266 160442.55587118378, 97320.09227538394 160442.51279455275, 97320.175497806 160442.47350482165, 97320.2604395726 160442.43808518312, 97320.34692082684 160442.40661063514, 97320.43475845215 160442.37914782236, 97320.52376645994 160442.35575489493, 97320.61375638345 160442.33648138537, 97320.70453767678 160442.3213681036, 97320.7959181184 160442.31044705078, 97320.8877042181 160442.30374135124, 97320.97970162675 160442.3012652037)))"^^ . -_:Bc62ccceb9774caaaaf750f128eb04743 . -_:B4c62b2bc2c77e81bf293fc8a223d111a "Gemeente Beveren"^^ . -_:B4c62b2bc2c77e81bf293fc8a223d111a . -_:B4c62b2bc2c77e81bf293fc8a223d111a . -_:B83957ea2aa5de8738e11fe87532433ff "Stad Dendermonde"^^ . -_:B83957ea2aa5de8738e11fe87532433ff . -_:B83957ea2aa5de8738e11fe87532433ff . diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/services/TreeNodeConverterImpl.java b/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/services/TreeNodeConverterImpl.java index 4065869a1..97841cadb 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/services/TreeNodeConverterImpl.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/services/TreeNodeConverterImpl.java @@ -1,12 +1,15 @@ package be.vlaanderen.informatievlaanderen.ldes.server.rest.treenode.services; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.PrefixAdder; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.UriPrefixConstructor; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.entities.TreeNode; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.springframework.stereotype.Component; +import java.util.Map; + import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.RdfConstants.TREE_MEMBER; import static org.apache.jena.rdf.model.ResourceFactory.createResource; import static org.apache.jena.rdf.model.ResourceFactory.createStatement; @@ -15,10 +18,10 @@ public class TreeNodeConverterImpl implements TreeNodeConverter { private final PrefixAdder prefixAdder; - private final PrefixConstructor prefixConstructor; + private final UriPrefixConstructor prefixConstructor; private final TreeNodeStatementCreator treeNodeStatementCreator; - public TreeNodeConverterImpl(PrefixAdder prefixAdder, PrefixConstructor prefixConstructor, TreeNodeStatementCreator treeNodeStatementCreator) { + public TreeNodeConverterImpl(PrefixAdder prefixAdder, UriPrefixConstructor prefixConstructor, TreeNodeStatementCreator treeNodeStatementCreator) { this.prefixAdder = prefixAdder; this.prefixConstructor = prefixConstructor; this.treeNodeStatementCreator = treeNodeStatementCreator; @@ -43,6 +46,13 @@ public Model toModel(final TreeNode treeNode) { .forEach(model::add); } - return prefixAdder.addPrefixesToModel(model); + return prefixAdder.addPrefixesToModel(model).setNsPrefixes(createTreeNodePrefixes(treeNode)); + } + + private Map createTreeNodePrefixes(TreeNode treeNode) { + if(prefixConstructor instanceof HostNamePrefixConstructor hostNamePrefixConstructor) { + return hostNamePrefixConstructor.buildFragmentUri(treeNode.getCollectionName(), treeNode.getFragmentId()); + } + return Map.of(); } } diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java index 4f1e83922..42c7a50d4 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java @@ -6,7 +6,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.PrefixAdderImpl; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.RdfModelConverter; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.ShaclValidationException; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import be.vlaanderen.informatievlaanderen.ldes.server.rest.caching.CachingStrategy; import be.vlaanderen.informatievlaanderen.ldes.server.rest.caching.EtagCachingStrategy; import be.vlaanderen.informatievlaanderen.ldes.server.rest.config.RestConfig; @@ -66,7 +67,8 @@ RestResponseEntityExceptionHandler.class, EventStreamWriter.class, EventStreamReader.class, KafkaSourceReader.class, ViewSpecificationConverter.class, PrefixAdderImpl.class, EventStreamResponseHttpConverter.class, RetentionModelExtractor.class, HttpModelConverter.class, FragmentationConfigExtractor.class, - PrefixConstructor.class, RdfModelConverter.class, VersionHeaderControllerAdvice.class + HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, + RdfModelConverter.class, VersionHeaderControllerAdvice.class }) class EventStreamControllerTest { private static final String COLLECTION = "mobility-hindrances"; diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java index 5d35f71f6..f0d0d989a 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java @@ -8,7 +8,9 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.entities.Member; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.entities.TreeNode; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.services.StreamingTreeNodeFactory; @@ -75,7 +77,7 @@ @Import(TreeNodeControllerTest.TreeNodeControllerTestConfiguration.class) @ContextConfiguration(classes = {TreeNodeController.class, RestConfig.class, TreeViewWebConfig.class, - RestResponseEntityExceptionHandler.class, PrefixConstructor.class, + RestResponseEntityExceptionHandler.class, HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, RdfModelConverter.class, TreeNodeStreamConverterImpl.class, PrefixAdderImpl.class, TreeNodeStatementCreatorImpl.class, CharsetEncodingConfig.class, VersionHeaderControllerAdvice.class, }) @@ -305,8 +307,8 @@ public static class TreeNodeControllerTestConfiguration { @Bean public TreeNodeConverter ldesFragmentConverter(@Value(HOST_NAME_KEY) String hostName, @Autowired TreeNodeStatementCreator treeNodeStatementCreator) { - PrefixAdder prefixAdder = new PrefixAdderImpl(); - PrefixConstructor prefixConstructor = new PrefixConstructor(hostName, false); + PrefixAdder prefixAdder = new PrefixAdderImpl(List.of()); + HostNamePrefixConstructor prefixConstructor = new HostNamePrefixConstructor(hostName); return new TreeNodeConverterImpl(prefixAdder, prefixConstructor, treeNodeStatementCreator); } diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/services/TreeNodeConverterImplTest.java b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/services/TreeNodeConverterImplTest.java index b081099cc..b0b9406f2 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/services/TreeNodeConverterImplTest.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/services/TreeNodeConverterImplTest.java @@ -7,7 +7,8 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.DcatView; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewName; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.PrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.entities.Member; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.entities.TreeNode; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.valueobjects.LdesFragmentIdentifier; @@ -37,8 +38,8 @@ class TreeNodeConverterImplTest { private static final String PREFIX = HOST_NAME + "/" + COLLECTION_NAME + "/"; private static final String VIEW_NAME = "view"; private static final Resource VIEW_URI = createResource(HOST_NAME + "/" + COLLECTION_NAME + "/" + VIEW_NAME); - private final PrefixAdder prefixAdder = new PrefixAdderImpl(); - private final PrefixConstructor prefixConstructor = new PrefixConstructor(HOST_NAME, false); + private final PrefixAdder prefixAdder = new PrefixAdderImpl(List.of()); + private final HostNamePrefixConstructor prefixConstructor = new HostNamePrefixConstructor(HOST_NAME); private final TreeNodeStatementCreatorImpl treeNodeStatementCreator = new TreeNodeStatementCreatorImpl(); private TreeNodeConverterImpl treeNodeConverter; @@ -167,7 +168,7 @@ private Condition size(int size) { @Test void testHandleDcatViewEvents() { - final TreeNode treeNode = new TreeNode(PREFIX + VIEW_NAME, false, true, List.of(), List.of(), + final TreeNode treeNode = new TreeNode("/" + COLLECTION_NAME + "/" + VIEW_NAME, false, true, List.of(), List.of(), COLLECTION_NAME, null); final ViewName viewName = new ViewName(COLLECTION_NAME, VIEW_NAME); final Model dcat = RDFParser.source("eventstream/streams/dcat-view-valid.ttl").lang(Lang.TURTLE).build().toModel(); @@ -189,4 +190,15 @@ void test_HandleEventStreamDeleted() { assertThatThrownBy(() -> treeNodeConverter.toModel(treeNode)).isInstanceOf(MissingResourceException.class); } + + @Test + void given_RelativeUrlEnabled_when_Convert_then_DoNotCreateTreeNodePrefixes() { + treeNodeConverter = new TreeNodeConverterImpl(model -> model, new RelativeUriPrefixConstructor(), treeNodeStatementCreator); + TreeNode treeNode = new TreeNode("/" + COLLECTION_NAME + "/" + VIEW_NAME, false, true, List.of(), List.of(), + COLLECTION_NAME, null); + + final Model result = treeNodeConverter.toModel(treeNode); + + assertThat(result.getNsPrefixMap()).isEmpty(); + } } From 8ebb0f297f0dcf5745a81842113cd30febd3b89b Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Tue, 19 Nov 2024 18:31:33 +0100 Subject: [PATCH 08/45] chore: make version header to all endpoints accessible (#1422) --- .../AdminVersionHeaderControllerAdvice.java | 21 ---------- .../AdminEventStreamsRestControllerTest.java | 30 +++++++++----- .../versioning/VersionHeaderFilter.java | 23 +++++++++++ .../versioning/VersionHeaderFilterConfig.java | 18 ++++++++ .../src/main/java/module-info.java | 1 + .../VersionHeaderControllerAdvice.java | 21 ---------- .../EventStreamControllerTest.java | 5 +-- .../rest/treenode/TreeNodeControllerTest.java | 4 +- .../PostgresBucketisationIntegrationTest.java | 3 +- .../ingest/PostgresIngestIntegrationTest.java | 3 ++ .../pagination/postgres/PaginationSteps.java | 3 +- .../resources/application-postgres-test.yml | 8 +++- .../rest/MemberIngestControllerTest.java | 41 ++++++++++++++----- 13 files changed, 109 insertions(+), 72 deletions(-) delete mode 100644 ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/versioning/AdminVersionHeaderControllerAdvice.java create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/versioning/VersionHeaderFilter.java create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/versioning/VersionHeaderFilterConfig.java delete mode 100644 ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/versioning/VersionHeaderControllerAdvice.java diff --git a/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/versioning/AdminVersionHeaderControllerAdvice.java b/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/versioning/AdminVersionHeaderControllerAdvice.java deleted file mode 100644 index c695dfc46..000000000 --- a/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/versioning/AdminVersionHeaderControllerAdvice.java +++ /dev/null @@ -1,21 +0,0 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.versioning; - -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.boot.info.BuildProperties; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ModelAttribute; - -@ControllerAdvice -public class AdminVersionHeaderControllerAdvice { - private static final String APP_VERSION_HEADER_KEY = "X-App-Version"; - private final String appVersion; - - public AdminVersionHeaderControllerAdvice(BuildProperties buildProperties) { - this.appVersion = buildProperties.getVersion(); - } - - @ModelAttribute - public void addVersionHeader(HttpServletResponse response) { - response.setHeader(APP_VERSION_HEADER_KEY, appVersion); - } -} diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java index b1ea3d948..0c3afa72a 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerTest.java @@ -6,7 +6,6 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.converters.EventStreamHttpConverter; import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.converters.EventStreamListHttpConverter; import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.exceptionhandling.AdminRestResponseEntityExceptionHandler; -import be.vlaanderen.informatievlaanderen.ldes.server.admin.rest.versioning.AdminVersionHeaderControllerAdvice; import be.vlaanderen.informatievlaanderen.ldes.server.admin.spi.*; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.HttpModelConverter; import be.vlaanderen.informatievlaanderen.ldes.server.domain.converter.PrefixAdderImpl; @@ -18,6 +17,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.ViewSpecification; import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.HostNamePrefixConstructorConfig; import be.vlaanderen.informatievlaanderen.ldes.server.domain.rest.RelativeUriPrefixConstructor; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.versioning.VersionHeaderFilterConfig; import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.RDFDataMgr; import org.junit.jupiter.api.BeforeEach; @@ -28,8 +28,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.ActiveProfiles; @@ -45,6 +46,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Properties; import java.util.stream.Collectors; import static org.apache.jena.riot.WebContent.contentTypeNQuads; @@ -53,8 +55,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @WebMvcTest @ActiveProfiles({"test", "rest"}) @@ -63,17 +64,14 @@ EventStreamWriter.class, EventStreamReader.class, KafkaSourceReader.class, ViewSpecificationConverter.class, PrefixAdderImpl.class, ValidatorsConfig.class, AdminRestResponseEntityExceptionHandler.class, RetentionModelExtractor.class, CharsetEncodingConfig.class, - FragmentationConfigExtractor.class, HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, - RdfModelConverter.class, AdminVersionHeaderControllerAdvice.class}) -@Import(BuildProperties.class) + FragmentationConfigExtractor.class, HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, RdfModelConverter.class, VersionHeaderFilterConfig.class}) +@Import(AdminEventStreamsRestControllerTest.VersionConfig.class) class AdminEventStreamsRestControllerTest { private static final String COLLECTION = "name1"; public static final String TIMESTAMP_PATH = "http://purl.org/dc/terms/created"; public static final String VERSION_OF_PATH = "http://purl.org/dc/terms/isVersionOf"; @MockBean private EventStreamService eventStreamService; - @SpyBean - private AdminVersionHeaderControllerAdvice adminVersionHeaderControllerAdvice; @Autowired private MockMvc mockMvc; @@ -128,12 +126,12 @@ void when_StreamsPresent_then_StreamsAreReturned() throws Exception { mockMvc.perform(get("/admin/api/v1/eventstreams").accept(contentTypeNQuads)) .andExpect(status().isOk()) + .andExpect(header().exists("X-App-Version")) .andExpect(content().encoding(StandardCharsets.UTF_8)) .andExpect(content().contentTypeCompatibleWith(contentTypeNQuads)) .andExpect(IsIsomorphic.with(expectedEventStreamsModel)); verify(eventStreamService).retrieveAllEventStreams(); - verify(adminVersionHeaderControllerAdvice).addVersionHeader(any()); } } @@ -154,12 +152,12 @@ void when_StreamPresent_Then_StreamIsReturned() throws Exception { mockMvc.perform(get("/admin/api/v1/eventstreams/" + COLLECTION).accept(contentTypeNQuads)) .andExpect(status().isOk()) + .andExpect(header().exists("X-App-Version")) .andExpect(content().encoding(StandardCharsets.UTF_8)) .andExpect(content().contentTypeCompatibleWith(contentTypeNQuads)) .andExpect(IsIsomorphic.with(model)); verify(eventStreamService).retrieveEventStream(COLLECTION); - verify(adminVersionHeaderControllerAdvice).addVersionHeader(any()); } @Test @@ -348,4 +346,14 @@ private String readDataFromFile(String fileName) return Files.lines(path).collect(Collectors.joining()); } + @TestConfiguration + static class VersionConfig { + @Bean + public BuildProperties buildProperties() { + final Properties properties = new Properties(); + properties.setProperty("version", "1.0.0"); + return new BuildProperties(properties); + } + } + } diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/versioning/VersionHeaderFilter.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/versioning/VersionHeaderFilter.java new file mode 100644 index 000000000..5c2c55302 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/versioning/VersionHeaderFilter.java @@ -0,0 +1,23 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.versioning; + +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +public class VersionHeaderFilter implements Filter { + private static final String APP_VERSION_HEADER_KEY = "X-App-Version"; + private final String appVersion; + + public VersionHeaderFilter(String appVersion) { + this.appVersion = appVersion; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + if (response instanceof HttpServletResponse httpResponse) { + httpResponse.setHeader(APP_VERSION_HEADER_KEY, appVersion); + } + chain.doFilter(request, response); + } +} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/versioning/VersionHeaderFilterConfig.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/versioning/VersionHeaderFilterConfig.java new file mode 100644 index 000000000..0bc6c2282 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/versioning/VersionHeaderFilterConfig.java @@ -0,0 +1,18 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.versioning; + +import org.springframework.boot.info.BuildProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class VersionHeaderFilterConfig { + + @Bean + public FilterRegistrationBean registerVersionHeaderFilter(BuildProperties buildProperties) { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); + filterRegistrationBean.setFilter(new VersionHeaderFilter(buildProperties.getVersion())); + filterRegistrationBean.addUrlPatterns("/*"); + return filterRegistrationBean; + } +} diff --git a/ldes-server-domain/src/main/java/module-info.java b/ldes-server-domain/src/main/java/module-info.java index 8101c51f5..53c87c5af 100644 --- a/ldes-server-domain/src/main/java/module-info.java +++ b/ldes-server-domain/src/main/java/module-info.java @@ -6,6 +6,7 @@ exports be.vlaanderen.informatievlaanderen.ldes.server.domain.model; exports be.vlaanderen.informatievlaanderen.ldes.server.domain.rest; exports be.vlaanderen.informatievlaanderen.ldes.server.domain.encodig; + exports be.vlaanderen.informatievlaanderen.ldes.server.domain.versioning; // Events exports be.vlaanderen.informatievlaanderen.ldes.server.domain.events.retention; diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/versioning/VersionHeaderControllerAdvice.java b/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/versioning/VersionHeaderControllerAdvice.java deleted file mode 100644 index 28aa26f15..000000000 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/versioning/VersionHeaderControllerAdvice.java +++ /dev/null @@ -1,21 +0,0 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.rest.versioning; - -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.boot.info.BuildProperties; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ModelAttribute; - -@ControllerAdvice -public class VersionHeaderControllerAdvice { - private static final String APP_VERSION_HEADER_KEY = "X-App-Version"; - private final String appVersion; - - public VersionHeaderControllerAdvice(BuildProperties buildProperties) { - this.appVersion = buildProperties.getVersion(); - } - - @ModelAttribute - public void addVersionHeader(HttpServletResponse response) { - response.setHeader(APP_VERSION_HEADER_KEY, appVersion); - } -} diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java index 42c7a50d4..76fb10395 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/eventstream/EventStreamControllerTest.java @@ -13,7 +13,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.rest.config.RestConfig; import be.vlaanderen.informatievlaanderen.ldes.server.rest.eventstream.converters.EventStreamResponseHttpConverter; import be.vlaanderen.informatievlaanderen.ldes.server.rest.exceptionhandling.RestResponseEntityExceptionHandler; -import be.vlaanderen.informatievlaanderen.ldes.server.rest.versioning.VersionHeaderControllerAdvice; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.versioning.VersionHeaderFilterConfig; import org.apache.jena.rdf.model.*; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFParser; @@ -67,8 +67,7 @@ RestResponseEntityExceptionHandler.class, EventStreamWriter.class, EventStreamReader.class, KafkaSourceReader.class, ViewSpecificationConverter.class, PrefixAdderImpl.class, EventStreamResponseHttpConverter.class, RetentionModelExtractor.class, HttpModelConverter.class, FragmentationConfigExtractor.class, - HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, - RdfModelConverter.class, VersionHeaderControllerAdvice.class + HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, RdfModelConverter.class, VersionHeaderFilterConfig.class }) class EventStreamControllerTest { private static final String COLLECTION = "mobility-hindrances"; diff --git a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java index f0d0d989a..da79174b2 100644 --- a/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java +++ b/ldes-server-fetch/ldes-server-fetch-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/rest/treenode/TreeNodeControllerTest.java @@ -24,7 +24,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.rest.exceptionhandling.RestResponseEntityExceptionHandler; import be.vlaanderen.informatievlaanderen.ldes.server.rest.treenode.config.TreeViewWebConfig; import be.vlaanderen.informatievlaanderen.ldes.server.rest.treenode.services.*; -import be.vlaanderen.informatievlaanderen.ldes.server.rest.versioning.VersionHeaderControllerAdvice; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.versioning.VersionHeaderFilterConfig; import org.apache.jena.rdf.model.*; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFParser; @@ -79,7 +79,7 @@ RestConfig.class, TreeViewWebConfig.class, RestResponseEntityExceptionHandler.class, HostNamePrefixConstructorConfig.class, RelativeUriPrefixConstructor.class, RdfModelConverter.class, TreeNodeStreamConverterImpl.class, PrefixAdderImpl.class, - TreeNodeStatementCreatorImpl.class, CharsetEncodingConfig.class, VersionHeaderControllerAdvice.class, + TreeNodeStatementCreatorImpl.class, CharsetEncodingConfig.class, VersionHeaderFilterConfig.class, }) class TreeNodeControllerTest { private static final String COLLECTION_NAME = "ldes-1"; diff --git a/ldes-server-infra-postgres/postgres-fragmentation-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/PostgresBucketisationIntegrationTest.java b/ldes-server-infra-postgres/postgres-fragmentation-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/PostgresBucketisationIntegrationTest.java index ef86a1855..08406c2ba 100644 --- a/ldes-server-infra-postgres/postgres-fragmentation-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/PostgresBucketisationIntegrationTest.java +++ b/ldes-server-infra-postgres/postgres-fragmentation-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/PostgresBucketisationIntegrationTest.java @@ -11,6 +11,7 @@ import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; @@ -39,7 +40,7 @@ "be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.postgres" }) @ContextConfiguration(classes = {BucketisedMemberItemWriterConfig.class}) -@Import(PostgresBucketisationIntegrationTest.EventStreamControllerTestConfiguration.class) +@Import({PostgresBucketisationIntegrationTest.EventStreamControllerTestConfiguration.class, BuildProperties.class}) @SuppressWarnings("java:S2187") public class PostgresBucketisationIntegrationTest { @MockBean diff --git a/ldes-server-infra-postgres/postgres-ingest-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/PostgresIngestIntegrationTest.java b/ldes-server-infra-postgres/postgres-ingest-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/PostgresIngestIntegrationTest.java index 30d28f9f5..6af775cd3 100644 --- a/ldes-server-infra-postgres/postgres-ingest-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/PostgresIngestIntegrationTest.java +++ b/ldes-server-infra-postgres/postgres-ingest-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/PostgresIngestIntegrationTest.java @@ -10,9 +10,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; @@ -31,6 +33,7 @@ @EnableJpaRepositories(basePackageClasses = {MemberEntityRepository.class, EventStreamEntityRepository.class}) @Sql(value = {"init-collections.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(statements = "DELETE FROM collections;", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +@Import(BuildProperties.class) @SuppressWarnings("java:S2187") public class PostgresIngestIntegrationTest { diff --git a/ldes-server-infra-postgres/postgres-pagination-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/postgres/PaginationSteps.java b/ldes-server-infra-postgres/postgres-pagination-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/postgres/PaginationSteps.java index ed78933c2..19a6f5fef 100644 --- a/ldes-server-infra-postgres/postgres-pagination-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/postgres/PaginationSteps.java +++ b/ldes-server-infra-postgres/postgres-pagination-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/postgres/PaginationSteps.java @@ -95,8 +95,7 @@ private void saveMembers(List memberIds) { final List batchArgs = memberIds.stream() .map(member -> new Object[]{ "http://example.com/es/%d".formatted(member), collectionId, eventStream, - LocalDateTime.now(), 0, new byte[]{}, - "%s/%s/%d".formatted(eventStream, eventStream, member) + LocalDateTime.now(), 0, new byte[]{} }) .toList(); diff --git a/ldes-server-infra-postgres/postgres-pagination-repository/src/test/resources/application-postgres-test.yml b/ldes-server-infra-postgres/postgres-pagination-repository/src/test/resources/application-postgres-test.yml index b8c8bf725..44347ce39 100644 --- a/ldes-server-infra-postgres/postgres-pagination-repository/src/test/resources/application-postgres-test.yml +++ b/ldes-server-infra-postgres/postgres-pagination-repository/src/test/resources/application-postgres-test.yml @@ -1,3 +1,9 @@ spring: liquibase: - change-log: classpath:/db/changelog/master.xml \ No newline at end of file + change-log: classpath:/db/changelog/master.xml +zonky: + test: + database: + postgres: + docker: + image: postgres:14-alpine \ No newline at end of file diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java index 11bdcbf75..a64531b0c 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java @@ -6,6 +6,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.ShaclValidationException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.VersionCreationProperties; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.versioning.VersionHeaderFilterConfig; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.MemberIngester; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.exceptions.MemberSubjectNotFoundException; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.rest.converters.IngestedModelConverter; @@ -27,9 +28,12 @@ import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.info.BuildProperties; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.context.TestConfiguration; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Bean; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.MockMvc; @@ -41,22 +45,23 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Objects; +import java.util.Properties; import java.util.stream.Stream; import static org.hamcrest.core.StringContains.containsString; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @WebMvcTest @ActiveProfiles("test") @ContextConfiguration(classes = {IngestedModelConverter.class, MemberIngestController.class, IngestionRestResponseEntityExceptionHandler.class, RdfModelConverter.class, MemberIngestValidator.class, - BlankNodesValidator.class, PathsValidator.class}) + BlankNodesValidator.class, PathsValidator.class, VersionHeaderFilterConfig.class, + MemberIngestControllerTest.VersionConfig.class}) class MemberIngestControllerTest { - + private static final String VERSION = "4.0.4-SNAPSHOT"; @Autowired private MockMvc mockMvc; @@ -81,7 +86,8 @@ void when_POSTRequestIsPerformed_LDesMemberIsSaved(String contentType, Lang rdfF byte[] ldesMemberBytes = readLdesMemberDataFromFile("example-ldes-member.nq", rdfFormat); mockMvc.perform(post("/mobility-hindrances").contentType(contentType).content(ldesMemberBytes)) - .andExpect(status().isOk()); + .andExpect(status().isOk()) + .andExpect(header().exists("X-App-Version")); verify(memberIngester, times(1)).ingest(anyString(), any(Model.class)); } @@ -96,7 +102,8 @@ void when_POSTRequestIsPerformedWithMultipleNamedNodes_ThrowException() throws E .contentType("application/n-quads") .content(ldesMemberBytes)) .andExpect(status().isBadRequest()) - .andExpect(content().string(containsString("Only 1 member is allowed per request on collection with version creation disabled"))); + .andExpect(header().exists("X-App-Version")) + .andExpect(content().string(containsString("Only 1 member is allowed per request on collection with version creation disabled"))); } @Test @@ -106,6 +113,7 @@ void when_POSTRequestIsPerformedWithoutTimestampPath_ThrowException() throws Exc mockMvc.perform(post("/mobility-hindrances").contentType("application/n-quads").content(ldesMemberBytes)) .andExpect(status().isBadRequest()) + .andExpect(header().exists("X-App-Version")) .andExpect(content().string(containsString("Member must have exactly 1 statement with timestamp path: http://www.w3.org/ns/prov#generatedAtTime"))); verifyNoInteractions(memberIngester); } @@ -120,7 +128,8 @@ void when_POSTRequestIsPerformed_WithoutVersionOf_ThenTheRequestFails() throws E mockMvc.perform(post("/mobility-hindrances").contentType("application/n-quads").content(ldesMemberBytes)) .andExpect(status().isBadRequest()) - .andExpect(content().string(containsString("Member must have exactly 1 statement with versionOf path: http://purl.org/dc/terms/isVersionOf"))); + .andExpect(header().exists("X-App-Version")) + .andExpect(content().string(containsString("Member must have exactly 1 statement with versionOf path: http://purl.org/dc/terms/isVersionOf"))); } @Test @@ -135,7 +144,8 @@ void when_POSTRequestIsPerformedUsingAnotherCollectionName_ResponseIs404() mockMvc.perform(post("/another-collection-name") .contentType("application/n-quads") .content(ldesMemberBytes)) - .andExpect(status().isNotFound()); + .andExpect(status().isNotFound()) + .andExpect(header().exists("X-App-Version")); } @Test @@ -143,7 +153,8 @@ void when_memberConformToShapeIsIngested_then_status200IsReturned() throws Excep String modelString = readModelStringFromFile("menu-items/example-data-old.ttl"); mockMvc.perform(post("/restaurant").contentType("text/turtle").content(modelString)) - .andExpect(status().isOk()); + .andExpect(status().isOk()) + .andExpect(header().exists("X-App-Version")); verify(memberIngester).ingest(anyString(), any(Model.class)); } @@ -154,7 +165,8 @@ void whenIngestValidationExceptionIsThrown_thenStatus400IsReturned() throws Exce doThrow(new ShaclValidationException("", ModelFactory.createDefaultModel())).when(memberIngester).ingest(anyString(), any(Model.class)); mockMvc.perform(post("/restaurant").contentType("text/turtle").content(modelString)) - .andExpect(status().isBadRequest()); + .andExpect(status().isBadRequest()) + .andExpect(header().exists("X-App-Version")); } private byte[] readLdesMemberDataFromFile(String fileName, Lang rdfFormat) { @@ -196,4 +208,13 @@ public Stream provideArguments(ExtensionContext context) { } } + @TestConfiguration + static class VersionConfig { + @Bean + public BuildProperties buildProperties() { + final Properties properties = new Properties(); + properties.setProperty("version", VERSION); + return new BuildProperties(properties); + } + } } From 0afff05bf35124308d68de3e355c03bd069f8eb7 Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Thu, 21 Nov 2024 10:10:45 +0100 Subject: [PATCH 09/45] chore: upgrade deprecated gh actions (#1423) * chore: upgrade deprecated gh actions * chore: upgrade deprecated gh actions --- .github/workflows/3.approve-snapshot.yml | 2 +- .github/workflows/add-issue-to-project.yml | 2 +- .github/workflows/build-documentation.yml | 4 ++-- .github/workflows/build-project.yml | 8 ++++---- .github/workflows/pr-merged.yml | 14 +++++++------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/3.approve-snapshot.yml b/.github/workflows/3.approve-snapshot.yml index 1040281b7..03f762852 100644 --- a/.github/workflows/3.approve-snapshot.yml +++ b/.github/workflows/3.approve-snapshot.yml @@ -41,7 +41,7 @@ jobs: echo "Already released. Current version: $VERSION" fi - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v7 if: ${{ env.NEW_VERSION != '' }} with: author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> diff --git a/.github/workflows/add-issue-to-project.yml b/.github/workflows/add-issue-to-project.yml index 2748e0a1b..9af79f1a5 100644 --- a/.github/workflows/add-issue-to-project.yml +++ b/.github/workflows/add-issue-to-project.yml @@ -10,7 +10,7 @@ jobs: name: Add issue to project runs-on: ubuntu-latest steps: - - uses: actions/add-to-project@v0.4.0 + - uses: actions/add-to-project@v1 with: project-url: https://github.com/orgs/Informatievlaanderen/projects/4 github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} \ No newline at end of file diff --git a/.github/workflows/build-documentation.yml b/.github/workflows/build-documentation.yml index 6ad874275..f746feb2f 100644 --- a/.github/workflows/build-documentation.yml +++ b/.github/workflows/build-documentation.yml @@ -35,7 +35,7 @@ jobs: export VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout) echo "version=$VERSION" >> $>> $GITHUB_OUTPUT - name: Setup Ruby - uses: ruby/setup-ruby@0a29871fe2b0200a17a4497bae54fe5df0d973aa + uses: ruby/setup-ruby@v1 with: ruby-version: '3.0' # Not needed with a .ruby-version file bundler-cache: true # runs 'bundle install' and caches installed gems automatically @@ -47,7 +47,7 @@ jobs: bundle exec jekyll build --baseurl "${{env.base_url}}/${{steps.version.outputs.version}}" -s "./" -d "./_site" env: JEKYLL_ENV: production - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 16 registry-url: https://npm.pkg.github.com/ diff --git a/.github/workflows/build-project.yml b/.github/workflows/build-project.yml index 6c7d2fcaa..4fb55c274 100644 --- a/.github/workflows/build-project.yml +++ b/.github/workflows/build-project.yml @@ -50,18 +50,18 @@ jobs: needs: build steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Download JARs uses: actions/download-artifact@v4 with: name: artifacts path: .github - name: Build and push Docker image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v6 with: context: .github push: false diff --git a/.github/workflows/pr-merged.yml b/.github/workflows/pr-merged.yml index 936fcd9d9..69da6fc7d 100644 --- a/.github/workflows/pr-merged.yml +++ b/.github/workflows/pr-merged.yml @@ -54,7 +54,7 @@ jobs: id: determine-version run: | export VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout) - echo "::set-output name=version::$VERSION" + echo "version=$VERSION" >> $GITHUB_ENV - name: Analyse & publish package run: | mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar deploy -Dsonar.projectKey=Informatievlaanderen_VSDS-LDESServer4J -Pcoverage @@ -77,9 +77,9 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Download JARs uses: actions/download-artifact@v4 with: @@ -100,13 +100,13 @@ jobs: fi - name: Log in to the DockerHub Container registry if: github.ref_name == 'main' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Log in to the GitHub Container registry if: github.ref_name != 'main' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: Informatievlaanderen @@ -114,14 +114,14 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.IMAGES }} tags: | type=raw,value=${{env.IMAGE_TAG}} type=raw,value=${{env.LATEST}} - name: Build and push Docker image - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v6 with: context: .github push: true From 31c0420f3d2fde355b9a14c7432834c13293f4cd Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:04:10 +0100 Subject: [PATCH 10/45] fix: well-known-prefixes.csv was not loaded in Docker image (#1425) --- .../domain/collections/WellKnownPrefixes.java | 18 ++++++++++ .../collections/WellKnownPrefixesConfig.java | 33 ----------------- .../domain/constants/WellKnownPrefix.java | 35 +++++++++++++++++++ .../main/resources/well-known-prefixes.csv | 15 -------- 4 files changed, 53 insertions(+), 48 deletions(-) create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixes.java delete mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixesConfig.java create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/constants/WellKnownPrefix.java delete mode 100644 ldes-server-domain/src/main/resources/well-known-prefixes.csv diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixes.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixes.java new file mode 100644 index 000000000..6fc5b7245 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixes.java @@ -0,0 +1,18 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.collections; + +import be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.WellKnownPrefix; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +public class WellKnownPrefixes implements Prefixes { + @Override + public Map getPrefixes() { + return Arrays.stream(WellKnownPrefix.values()).collect( + Collectors.toMap(WellKnownPrefix::getPrefix, WellKnownPrefix::getUri) + ); + } +} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixesConfig.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixesConfig.java deleted file mode 100644 index 24b221f59..000000000 --- a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/collections/WellKnownPrefixesConfig.java +++ /dev/null @@ -1,33 +0,0 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.domain.collections; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.ResourceUtils; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Map; -import java.util.stream.Collectors; - -@Configuration -public class WellKnownPrefixesConfig { - - @Bean - public Prefixes wellKnownPrefixes() { - final Map prefixes = readPrefixes(); - return () -> prefixes; - } - - - private Map readPrefixes() { - try { - final File wellKnownPrefixes = ResourceUtils.getFile("classpath:well-known-prefixes.csv"); - return Files.readAllLines(wellKnownPrefixes.toPath()).stream() - .map(line -> line.split(",")) - .collect(Collectors.toMap(line -> line[0], line -> line[1])); - } catch (IOException e) { - return Map.of(); - } - } -} diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/constants/WellKnownPrefix.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/constants/WellKnownPrefix.java new file mode 100644 index 000000000..e040a70f8 --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/constants/WellKnownPrefix.java @@ -0,0 +1,35 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.constants; + +public enum WellKnownPrefix { + FOAF("foaf", "http://xmlns.com/foaf/0.1/"), + RDF("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"), + RDFS("rdfs", "http://www.w3.org/2000/01/rdf-schema#"), + SKOS("skos", "http://www.w3.org/2004/02/skos/core#"), + OWL("owl", "http://www.w3.org/2002/07/owl#"), + XSD("xsd", "http://www.w3.org/2001/XMLSchema#"), + GEO("geo", "http://www.opengis.net/ont/geosparql#"), + DCAT("dcat", "http://www.w3.org/ns/dcat#"), + DCT("dct", "http://purl.org/dc/terms/"), + PROV("prov", "http://www.w3.org/ns/prov#"), + M8G("m8g", "http://data.europa.eu/m8g/"), + TREE("tree", "https://w3id.org/tree#"), + LDES("ldes", "https://w3id.org/ldes#"), + SH("sh", "http://www.w3.org/ns/shacl#"), + SHSH("shsh", "http://www.w3.org/ns/shacl-shacl#"); + + private final String prefix; + private final String uri; + + WellKnownPrefix(String prefix, String uri) { + this.prefix = prefix; + this.uri = uri; + } + + public String getPrefix() { + return prefix; + } + + public String getUri() { + return uri; + } +} \ No newline at end of file diff --git a/ldes-server-domain/src/main/resources/well-known-prefixes.csv b/ldes-server-domain/src/main/resources/well-known-prefixes.csv deleted file mode 100644 index 477e3d3d9..000000000 --- a/ldes-server-domain/src/main/resources/well-known-prefixes.csv +++ /dev/null @@ -1,15 +0,0 @@ -foaf,http://xmlns.com/foaf/0.1/ -rdf,http://www.w3.org/1999/02/22-rdf-syntax-ns# -rdfs,http://www.w3.org/2000/01/rdf-schema# -skos,http://www.w3.org/2004/02/skos/core# -owl,http://www.w3.org/2002/07/owl# -xsd,http://www.w3.org/2001/XMLSchema# -geo,http://www.opengis.net/ont/geosparql# -dcat,http://www.w3.org/ns/dcat# -dct,http://purl.org/dc/terms/ -prov,http://www.w3.org/ns/prov# -m8g,http://data.europa.eu/m8g/ -tree,https://w3id.org/tree# -ldes,https://w3id.org/ldes# -sh,http://www.w3.org/ns/shacl# -shsh,http://www.w3.org/ns/shacl-shacl# \ No newline at end of file From 114b9f3bdb3b2b99951b7dcbd343226009f08624 Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:18:09 +0100 Subject: [PATCH 11/45] fix: unnecessary hibernate deep copy (#1424) * feat: usage of a projection * chore: implement PR remarks --- .../instrumentation/PyroscopeInitialiser.java | 17 ++++++----------- .../postgres/TreeNodePostgresRepository.java | 8 ++++---- .../fetch/postgres/mapper/TreeNodeMapper.java | 5 +++-- .../projection/TreeMemberProjection.java | 8 -------- .../postgres/projection/TreeNodeProjection.java | 17 +++++++++++++++++ .../repository/FetchPageEntityRepository.java | 3 ++- 6 files changed, 32 insertions(+), 26 deletions(-) delete mode 100644 ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/projection/TreeMemberProjection.java create mode 100644 ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/projection/TreeNodeProjection.java diff --git a/ldes-server-application/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/instrumentation/PyroscopeInitialiser.java b/ldes-server-application/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/instrumentation/PyroscopeInitialiser.java index 9a8456ab5..d3d122662 100644 --- a/ldes-server-application/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/instrumentation/PyroscopeInitialiser.java +++ b/ldes-server-application/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/instrumentation/PyroscopeInitialiser.java @@ -3,20 +3,15 @@ import io.pyroscope.javaagent.PyroscopeAgent; import io.pyroscope.javaagent.config.Config; import jakarta.annotation.PostConstruct; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; @Component +@ConditionalOnProperty(value = "pyroscope.agent.enabled", havingValue = "true") public class PyroscopeInitialiser { - @Value("${pyroscope.agent.enabled:false}") - private boolean usePyroscope; - @PostConstruct - public void init() { - if(usePyroscope) { - PyroscopeAgent.start( - Config.build() - ); - } - } + @PostConstruct + public void init() { + PyroscopeAgent.start(Config.build()); + } } diff --git a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/TreeNodePostgresRepository.java b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/TreeNodePostgresRepository.java index 2da99fac2..d633203ce 100644 --- a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/TreeNodePostgresRepository.java +++ b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/TreeNodePostgresRepository.java @@ -34,7 +34,7 @@ public TreeNodePostgresRepository(FetchPageEntityRepository pageEntityRepository @Override public Optional findByFragmentIdentifier(LdesFragmentIdentifier fragmentIdentifier) { return pageEntityRepository - .findTreeNodeByPartialUrl(fragmentIdentifier.asDecodedFragmentId()) + .findTreeNodeProjectionByPartialUrl(fragmentIdentifier.asDecodedFragmentId()) .map(page -> { var versionObjectCreator = versionObjectCreatorMap.get(page.getBucket().getView().getEventStream().getName()); @@ -45,15 +45,15 @@ public Optional findByFragmentIdentifier(LdesFragmentIdentifier fragme treeMemberProjection.getModel(), treeMemberProjection.getVersionOf(), treeMemberProjection.getTimestamp()))) .toList(); - return TreeNodeMapper.fromPageEntity(page, members); + return TreeNodeMapper.fromProjection(page, members); }); } @Override public Optional findTreeNodeWithoutMembers(LdesFragmentIdentifier fragmentIdentifier) { return pageEntityRepository - .findTreeNodeByPartialUrl(fragmentIdentifier.asDecodedFragmentId()) - .map(page -> TreeNodeMapper.fromPageEntity(page, List.of())); + .findTreeNodeProjectionByPartialUrl(fragmentIdentifier.asDecodedFragmentId()) + .map(projection -> TreeNodeMapper.fromProjection(projection, List.of())); } @EventListener diff --git a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/mapper/TreeNodeMapper.java b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/mapper/TreeNodeMapper.java index 6fbd29baa..fe1b29fd2 100644 --- a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/mapper/TreeNodeMapper.java +++ b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/mapper/TreeNodeMapper.java @@ -1,6 +1,6 @@ package be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.mapper; -import be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.entity.FetchPageEntity; +import be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.projection.TreeNodeProjection; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.entities.Member; import be.vlaanderen.informatievlaanderen.ldes.server.fetching.entities.TreeNode; @@ -10,7 +10,7 @@ public class TreeNodeMapper { private TreeNodeMapper() { } - public static TreeNode fromPageEntity(FetchPageEntity page, List members) { + public static TreeNode fromProjection(TreeNodeProjection page, List members) { return new TreeNode( page.getPartialUrl(), page.isImmutable(), @@ -21,4 +21,5 @@ public static TreeNode fromPageEntity(FetchPageEntity page, List members page.getNextUpdateTs() ); } + } diff --git a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/projection/TreeMemberProjection.java b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/projection/TreeMemberProjection.java deleted file mode 100644 index da3be6ce7..000000000 --- a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/projection/TreeMemberProjection.java +++ /dev/null @@ -1,8 +0,0 @@ -package be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.projection; - -import org.apache.jena.rdf.model.Model; - -import java.time.LocalDateTime; - -public record TreeMemberProjection (String subject, Model model, String versionOf, LocalDateTime timestamp) { -} diff --git a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/projection/TreeNodeProjection.java b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/projection/TreeNodeProjection.java new file mode 100644 index 000000000..1b0b11e76 --- /dev/null +++ b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/projection/TreeNodeProjection.java @@ -0,0 +1,17 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.projection; + +import be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.entity.FetchBucketEntity; +import be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.entity.FetchPageRelationEntity; + +import java.time.LocalDateTime; +import java.util.List; + +public interface TreeNodeProjection { + long getId(); + String getPartialUrl(); + boolean isImmutable(); + boolean isView(); + List getRelations(); + FetchBucketEntity getBucket(); + LocalDateTime getNextUpdateTs(); +} diff --git a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/repository/FetchPageEntityRepository.java b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/repository/FetchPageEntityRepository.java index b4a47647c..f86ce250a 100644 --- a/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/repository/FetchPageEntityRepository.java +++ b/ldes-server-infra-postgres/postgres-fetch-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fetch/postgres/repository/FetchPageEntityRepository.java @@ -2,6 +2,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.entity.FetchPageEntity; +import be.vlaanderen.informatievlaanderen.ldes.server.fetch.postgres.projection.TreeNodeProjection; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.transaction.annotation.Transactional; @@ -9,5 +10,5 @@ public interface FetchPageEntityRepository extends JpaRepository { @Transactional(readOnly = true) - Optional findTreeNodeByPartialUrl(String partialUrl); + Optional findTreeNodeProjectionByPartialUrl(String partialUrl); } \ No newline at end of file From ec7228aff6faddfbdaae3ba4e31223f17b863695 Mon Sep 17 00:00:00 2001 From: Jan Robert <15772440+Yalz@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:32:19 +0100 Subject: [PATCH 12/45] fix: lenient version ingest (#1426) --------- Co-authored-by: Yalz --- .../ingestreportvalidator/PathsValidator.java | 108 +++++++++--------- .../src/main/java/module-info.java | 3 +- .../rest/MemberIngestControllerTest.java | 3 +- .../MemberIngestValidatorTest.java | 4 +- 4 files changed, 60 insertions(+), 58 deletions(-) diff --git a/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java index 981301b9d..254db5873 100644 --- a/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java @@ -3,73 +3,73 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import org.apache.jena.datatypes.RDFDatatype; import org.apache.jena.datatypes.xsd.XSDDatatype; -import org.apache.jena.rdf.model.*; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.rdf.model.Statement; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.List; +import static org.apache.jena.rdf.model.ResourceFactory.createProperty; + @Order(2) @Component public class PathsValidator implements IngestReportValidator { - @Override - public void validate(Model model, EventStream eventStream, ShaclReportManager reportManager) { - List memberSubjects = model.listSubjects().filterDrop(RDFNode::isAnon).toList(); - - if (memberSubjects.size() > 1 && !eventStream.isVersionCreationEnabled()) { - memberSubjects.forEach(subject -> reportManager.addEntry(subject, - "Only 1 member is allowed per request on collection with version creation disabled" - ) - ); - } + @Override + public void validate(Model model, EventStream eventStream, ShaclReportManager reportManager) { + List memberSubjects = model.listSubjects() + .filterDrop(RDFNode::isAnon) + .toList(); - validateTimestampPath(memberSubjects, model, eventStream, reportManager); - validateVersionOfPath(memberSubjects, model, eventStream, reportManager); - } + validateTimestampPath(memberSubjects, model, eventStream, reportManager); + validateVersionOfPath(memberSubjects, model, eventStream, reportManager); + } - private void validateTimestampPath(List memberSubjects, Model model, EventStream eventStream, ShaclReportManager reportManager) { - int expectedNumber = eventStream.isVersionCreationEnabled() ? 0 : 1; - List validTypes = List.of(XSDDatatype.XSDdateTime, XSDDatatype.XSDstring); - memberSubjects.forEach(subject -> { - List timestampStatements = getStatementsOfPath(subject, model, eventStream.getTimestampPath()); - if (timestampStatements.size() != expectedNumber) { - reportManager.addEntry(subject, - String.format(String.format("Member must have exactly %s statement%s with timestamp path: %s as predicate.", expectedNumber, expectedNumber == 1 ? "" : "s", eventStream.getTimestampPath())) - ); - } + private void validateTimestampPath(List memberSubjects, Model model, EventStream eventStream, ShaclReportManager reportManager) { + int expectedNumber = eventStream.isVersionCreationEnabled() ? 0 : 1; + List validTypes = List.of(XSDDatatype.XSDdateTime, XSDDatatype.XSDstring); + memberSubjects.forEach(subject -> { + List timestampStatements = getStatementsOfPath(subject, model, eventStream.getTimestampPath()); + if (timestampStatements.size() != expectedNumber) { + reportManager.addEntry(subject, + String.format(String.format("Member must have exactly %s statement%s with timestamp path: %s as predicate.", expectedNumber, expectedNumber == 1 ? "" : "s", eventStream.getTimestampPath())) + ); + } - timestampStatements.forEach(statement -> { - if (!statement.getObject().isLiteral() || !validTypes.contains(statement.getLiteral().getDatatype())) { - reportManager.addEntry(subject, - String.format(String.format("Object of statement with predicate: %s should be a literal either of type %s or %s", eventStream.getTimestampPath(), XSDDatatype.XSDdateTime.getURI(), XSDDatatype.XSDstring.getURI())) - ); - } - }); - }); - } + timestampStatements.forEach(statement -> { + if (!statement.getObject().isLiteral() || !validTypes.contains(statement.getLiteral().getDatatype())) { + reportManager.addEntry(subject, + String.format(String.format("Object of statement with predicate: %s should be a literal either of type %s or %s", eventStream.getTimestampPath(), XSDDatatype.XSDdateTime.getURI(), XSDDatatype.XSDstring.getURI())) + ); + } + }); + }); + } - private void validateVersionOfPath(List memberSubjects, Model model, EventStream eventStream, ShaclReportManager reportManager) { - int expectedNumber = eventStream.isVersionCreationEnabled() ? 0 : 1; - memberSubjects.forEach(subject -> { - List versionOfStatements = getStatementsOfPath(subject, model, eventStream.getVersionOfPath()); - if (versionOfStatements.size() != expectedNumber) { - reportManager.addEntry(subject, - String.format("Member must have exactly %s statement%s with versionOf path: %s as predicate.", expectedNumber, expectedNumber == 1 ? "" : "s", eventStream.getVersionOfPath()) - ); - } + private void validateVersionOfPath(List memberSubjects, Model model, EventStream eventStream, ShaclReportManager reportManager) { + int expectedNumber = eventStream.isVersionCreationEnabled() ? 0 : 1; + memberSubjects.forEach(subject -> { + List versionOfStatements = getStatementsOfPath(subject, model, eventStream.getVersionOfPath()); + if (versionOfStatements.size() != expectedNumber) { + reportManager.addEntry(subject, + String.format("Member must have exactly %s statement%s with versionOf path: %s as predicate.", expectedNumber, expectedNumber == 1 ? "" : "s", eventStream.getVersionOfPath()) + ); + } - versionOfStatements.forEach(statement -> { - if (!statement.getObject().isResource()) { - reportManager.addEntry(subject, - String.format("Object of statement with predicate: %s should be a resource", eventStream.getVersionOfPath()) - ); - } - }); - }); - } + versionOfStatements.forEach(statement -> { + if (!statement.getObject().isResource()) { + reportManager.addEntry(subject, + String.format("Object of statement with predicate: %s should be a resource", eventStream.getVersionOfPath()) + ); + } + }); + }); + } - private List getStatementsOfPath(Resource memberSubject, Model model, String path) { - return model.listStatements(memberSubject, ResourceFactory.createProperty(path), (RDFNode) null).toList(); - } + private List getStatementsOfPath(Resource memberSubject, Model model, String path) { + return model.listStatements(memberSubject, createProperty(path), (RDFNode) null).toList(); + } } diff --git a/ldes-server-ingest/ldes-server-ingest-common/src/main/java/module-info.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/module-info.java index a4bfea651..bcb6ecde0 100644 --- a/ldes-server-ingest/ldes-server-ingest-common/src/main/java/module-info.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/module-info.java @@ -8,7 +8,8 @@ requires org.apache.jena.arq; requires micrometer.core; requires micrometer.observation; - exports be.vlaanderen.informatievlaanderen.ldes.server.ingest.entities; + requires spring.core; + exports be.vlaanderen.informatievlaanderen.ldes.server.ingest.entities; exports be.vlaanderen.informatievlaanderen.ldes.server.ingest.repositories; exports be.vlaanderen.informatievlaanderen.ldes.server.ingest; } \ No newline at end of file diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java index a64531b0c..9f90af6a5 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java @@ -103,7 +103,8 @@ void when_POSTRequestIsPerformedWithMultipleNamedNodes_ThrowException() throws E .content(ldesMemberBytes)) .andExpect(status().isBadRequest()) .andExpect(header().exists("X-App-Version")) - .andExpect(content().string(containsString("Only 1 member is allowed per request on collection with version creation disabled"))); + .andExpect(content().string(containsString("Member must have exactly 1 statement with versionOf path"))) + .andExpect(content().string(containsString("Member must have exactly 1 statement with timestamp path"))); } @Test diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java index fb66db41a..13bf4ce28 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java @@ -109,10 +109,10 @@ public Stream provideArguments(ExtensionContext extensionCo List.of("Member must have exactly 1 statement with timestamp path: " + TIMESTAMP_PATH)), Arguments.of("example-ldes-member-multiple-version-ofs.nq", VERSION, List.of("Member must have exactly 1 statement with versionOf path: " + VERSIONOF_PATH)), - Arguments.of("example-ldes-member-without-version-of.nq", VERSION, - List.of("Member must have exactly 1 statement with versionOf path: " + VERSIONOF_PATH)), Arguments.of("example-ldes-member-wrong-type-version-of.nq", VERSION, List.of("Object of statement with predicate: " + VERSIONOF_PATH + " should be a resource")), + Arguments.of("example-ldes-member-without-version-of.nq", VERSION, + List.of("Member must have exactly 1 statement with versionOf path: " + VERSIONOF_PATH)), Arguments.of("example-ldes-member-wrong-type-timestamp.nq", VERSION, List.of("Object of statement with predicate: " + TIMESTAMP_PATH + " should be a literal either of type " + XSDDatatype.XSDdateTime.getURI() + " or " + XSDDatatype.XSDstring.getURI())), Arguments.of("example-ldes-member-dangling-nodes.nq", VERSION, List.of("Object graphs don't allow blank nodes to occur outside of a named object.")), From a862b4694f2ab98c34f28b9964ce084542105c5b Mon Sep 17 00:00:00 2001 From: Yalz Date: Tue, 26 Nov 2024 10:22:19 +0100 Subject: [PATCH 13/45] Revert "fix: lenient version ingest (#1426)" This reverts commit 072c00e3f4bb9adcb9e547b685201376a750181c. --- .../ingestreportvalidator/PathsValidator.java | 108 +++++++++--------- .../src/main/java/module-info.java | 3 +- .../rest/MemberIngestControllerTest.java | 3 +- .../MemberIngestValidatorTest.java | 4 +- 4 files changed, 58 insertions(+), 60 deletions(-) diff --git a/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java index 254db5873..981301b9d 100644 --- a/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/validators/ingestreportvalidator/PathsValidator.java @@ -3,73 +3,73 @@ import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import org.apache.jena.datatypes.RDFDatatype; import org.apache.jena.datatypes.xsd.XSDDatatype; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.RDFNode; -import org.apache.jena.rdf.model.Resource; -import org.apache.jena.rdf.model.Statement; +import org.apache.jena.rdf.model.*; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.List; -import static org.apache.jena.rdf.model.ResourceFactory.createProperty; - @Order(2) @Component public class PathsValidator implements IngestReportValidator { - @Override - public void validate(Model model, EventStream eventStream, ShaclReportManager reportManager) { - List memberSubjects = model.listSubjects() - .filterDrop(RDFNode::isAnon) - .toList(); + @Override + public void validate(Model model, EventStream eventStream, ShaclReportManager reportManager) { + List memberSubjects = model.listSubjects().filterDrop(RDFNode::isAnon).toList(); + + if (memberSubjects.size() > 1 && !eventStream.isVersionCreationEnabled()) { + memberSubjects.forEach(subject -> reportManager.addEntry(subject, + "Only 1 member is allowed per request on collection with version creation disabled" + ) + ); + } - validateTimestampPath(memberSubjects, model, eventStream, reportManager); - validateVersionOfPath(memberSubjects, model, eventStream, reportManager); - } + validateTimestampPath(memberSubjects, model, eventStream, reportManager); + validateVersionOfPath(memberSubjects, model, eventStream, reportManager); + } - private void validateTimestampPath(List memberSubjects, Model model, EventStream eventStream, ShaclReportManager reportManager) { - int expectedNumber = eventStream.isVersionCreationEnabled() ? 0 : 1; - List validTypes = List.of(XSDDatatype.XSDdateTime, XSDDatatype.XSDstring); - memberSubjects.forEach(subject -> { - List timestampStatements = getStatementsOfPath(subject, model, eventStream.getTimestampPath()); - if (timestampStatements.size() != expectedNumber) { - reportManager.addEntry(subject, - String.format(String.format("Member must have exactly %s statement%s with timestamp path: %s as predicate.", expectedNumber, expectedNumber == 1 ? "" : "s", eventStream.getTimestampPath())) - ); - } + private void validateTimestampPath(List memberSubjects, Model model, EventStream eventStream, ShaclReportManager reportManager) { + int expectedNumber = eventStream.isVersionCreationEnabled() ? 0 : 1; + List validTypes = List.of(XSDDatatype.XSDdateTime, XSDDatatype.XSDstring); + memberSubjects.forEach(subject -> { + List timestampStatements = getStatementsOfPath(subject, model, eventStream.getTimestampPath()); + if (timestampStatements.size() != expectedNumber) { + reportManager.addEntry(subject, + String.format(String.format("Member must have exactly %s statement%s with timestamp path: %s as predicate.", expectedNumber, expectedNumber == 1 ? "" : "s", eventStream.getTimestampPath())) + ); + } - timestampStatements.forEach(statement -> { - if (!statement.getObject().isLiteral() || !validTypes.contains(statement.getLiteral().getDatatype())) { - reportManager.addEntry(subject, - String.format(String.format("Object of statement with predicate: %s should be a literal either of type %s or %s", eventStream.getTimestampPath(), XSDDatatype.XSDdateTime.getURI(), XSDDatatype.XSDstring.getURI())) - ); - } - }); - }); - } + timestampStatements.forEach(statement -> { + if (!statement.getObject().isLiteral() || !validTypes.contains(statement.getLiteral().getDatatype())) { + reportManager.addEntry(subject, + String.format(String.format("Object of statement with predicate: %s should be a literal either of type %s or %s", eventStream.getTimestampPath(), XSDDatatype.XSDdateTime.getURI(), XSDDatatype.XSDstring.getURI())) + ); + } + }); + }); + } - private void validateVersionOfPath(List memberSubjects, Model model, EventStream eventStream, ShaclReportManager reportManager) { - int expectedNumber = eventStream.isVersionCreationEnabled() ? 0 : 1; - memberSubjects.forEach(subject -> { - List versionOfStatements = getStatementsOfPath(subject, model, eventStream.getVersionOfPath()); - if (versionOfStatements.size() != expectedNumber) { - reportManager.addEntry(subject, - String.format("Member must have exactly %s statement%s with versionOf path: %s as predicate.", expectedNumber, expectedNumber == 1 ? "" : "s", eventStream.getVersionOfPath()) - ); - } + private void validateVersionOfPath(List memberSubjects, Model model, EventStream eventStream, ShaclReportManager reportManager) { + int expectedNumber = eventStream.isVersionCreationEnabled() ? 0 : 1; + memberSubjects.forEach(subject -> { + List versionOfStatements = getStatementsOfPath(subject, model, eventStream.getVersionOfPath()); + if (versionOfStatements.size() != expectedNumber) { + reportManager.addEntry(subject, + String.format("Member must have exactly %s statement%s with versionOf path: %s as predicate.", expectedNumber, expectedNumber == 1 ? "" : "s", eventStream.getVersionOfPath()) + ); + } - versionOfStatements.forEach(statement -> { - if (!statement.getObject().isResource()) { - reportManager.addEntry(subject, - String.format("Object of statement with predicate: %s should be a resource", eventStream.getVersionOfPath()) - ); - } - }); - }); - } + versionOfStatements.forEach(statement -> { + if (!statement.getObject().isResource()) { + reportManager.addEntry(subject, + String.format("Object of statement with predicate: %s should be a resource", eventStream.getVersionOfPath()) + ); + } + }); + }); + } - private List getStatementsOfPath(Resource memberSubject, Model model, String path) { - return model.listStatements(memberSubject, createProperty(path), (RDFNode) null).toList(); - } + private List getStatementsOfPath(Resource memberSubject, Model model, String path) { + return model.listStatements(memberSubject, ResourceFactory.createProperty(path), (RDFNode) null).toList(); + } } diff --git a/ldes-server-ingest/ldes-server-ingest-common/src/main/java/module-info.java b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/module-info.java index bcb6ecde0..a4bfea651 100644 --- a/ldes-server-ingest/ldes-server-ingest-common/src/main/java/module-info.java +++ b/ldes-server-ingest/ldes-server-ingest-common/src/main/java/module-info.java @@ -8,8 +8,7 @@ requires org.apache.jena.arq; requires micrometer.core; requires micrometer.observation; - requires spring.core; - exports be.vlaanderen.informatievlaanderen.ldes.server.ingest.entities; + exports be.vlaanderen.informatievlaanderen.ldes.server.ingest.entities; exports be.vlaanderen.informatievlaanderen.ldes.server.ingest.repositories; exports be.vlaanderen.informatievlaanderen.ldes.server.ingest; } \ No newline at end of file diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java index 9f90af6a5..a64531b0c 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/MemberIngestControllerTest.java @@ -103,8 +103,7 @@ void when_POSTRequestIsPerformedWithMultipleNamedNodes_ThrowException() throws E .content(ldesMemberBytes)) .andExpect(status().isBadRequest()) .andExpect(header().exists("X-App-Version")) - .andExpect(content().string(containsString("Member must have exactly 1 statement with versionOf path"))) - .andExpect(content().string(containsString("Member must have exactly 1 statement with timestamp path"))); + .andExpect(content().string(containsString("Only 1 member is allowed per request on collection with version creation disabled"))); } @Test diff --git a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java index 13bf4ce28..fb66db41a 100644 --- a/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java +++ b/ldes-server-ingest/ldes-server-ingest-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/rest/validators/memberingestvalidator/MemberIngestValidatorTest.java @@ -109,10 +109,10 @@ public Stream provideArguments(ExtensionContext extensionCo List.of("Member must have exactly 1 statement with timestamp path: " + TIMESTAMP_PATH)), Arguments.of("example-ldes-member-multiple-version-ofs.nq", VERSION, List.of("Member must have exactly 1 statement with versionOf path: " + VERSIONOF_PATH)), - Arguments.of("example-ldes-member-wrong-type-version-of.nq", VERSION, - List.of("Object of statement with predicate: " + VERSIONOF_PATH + " should be a resource")), Arguments.of("example-ldes-member-without-version-of.nq", VERSION, List.of("Member must have exactly 1 statement with versionOf path: " + VERSIONOF_PATH)), + Arguments.of("example-ldes-member-wrong-type-version-of.nq", VERSION, + List.of("Object of statement with predicate: " + VERSIONOF_PATH + " should be a resource")), Arguments.of("example-ldes-member-wrong-type-timestamp.nq", VERSION, List.of("Object of statement with predicate: " + TIMESTAMP_PATH + " should be a literal either of type " + XSDDatatype.XSDdateTime.getURI() + " or " + XSDDatatype.XSDstring.getURI())), Arguments.of("example-ldes-member-dangling-nodes.nq", VERSION, List.of("Object graphs don't allow blank nodes to occur outside of a named object.")), From 10dc543c5fb3f156808ddcc1b68b120fa5fa56aa Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:19:19 +0100 Subject: [PATCH 14/45] chore: return 404 when updating event source of non existing event stream (#1427) --- .../services/EventSourceService.java | 2 +- .../services/EventSourceServiceImpl.java | 6 +++- .../services/EventStreamServiceImpl.java | 2 +- .../services/EventStreamServiceImplTest.java | 2 +- .../services/EventSourceServiceImplTest.java | 36 +++++++++++++++---- .../AdminEventStreamsRestControllerSteps.java | 8 +++++ .../eventstreamscontroller.feature | 10 ++++++ .../test/resources/retention/event-source.ttl | 9 +++++ 8 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 ldes-server-admin/ldes-server-admin-rest/src/test/resources/retention/event-source.ttl diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceService.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceService.java index bca1d1b94..b78a2cee4 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceService.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceService.java @@ -9,5 +9,5 @@ public interface EventSourceService { Optional getEventSource(String collectionName); - void saveEventSource(String collectionName, List retentionPolicies); + void updateEventSource(String collectionName, List retentionPolicies); } diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceServiceImpl.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceServiceImpl.java index d41d5ce1a..1cbcf7ab6 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceServiceImpl.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventsource/services/EventSourceServiceImpl.java @@ -2,6 +2,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventsource.repository.EventSourceRepository; import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.DeletionPolicyChangedEvent; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventSource; import org.apache.jena.rdf.model.Model; import org.springframework.boot.context.event.ApplicationReadyEvent; @@ -28,7 +29,10 @@ public Optional getEventSource(String collectionName) { } @Override - public void saveEventSource(String collectionName, List retentionPolicies) { + public void updateEventSource(String collectionName, List retentionPolicies) { + if(repository.getEventSource(collectionName).isEmpty()) { + throw new MissingResourceException("eventstream", collectionName); + } repository.saveEventSource(new EventSource(collectionName, retentionPolicies)); eventPublisher.publishEvent(new DeletionPolicyChangedEvent(collectionName, retentionPolicies)); } diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java index 9cf6cbd64..b0a66cdc1 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java @@ -81,7 +81,7 @@ private void checkCollectionDoesNotYetExist(String collectionName) { @Override public void updateEventSource(String collectionName, List eventSourceModel) { - eventSourceService.saveEventSource(collectionName, eventSourceModel); + eventSourceService.updateEventSource(collectionName, eventSourceModel); } @Override diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java index 70680b417..6e2bd2db5 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java @@ -146,7 +146,7 @@ void when_collectionExists_then_updateEventSource() { service.updateEventSource(COLLECTION, List.of()); InOrder inOrder = Mockito.inOrder(eventSourceService, eventPublisher); - inOrder.verify(eventSourceService).saveEventSource(COLLECTION, List.of()); + inOrder.verify(eventSourceService).updateEventSource(COLLECTION, List.of()); } @Nested diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/services/EventSourceServiceImplTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/services/EventSourceServiceImplTest.java index 0e6a3fc24..62904d421 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/services/EventSourceServiceImplTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/services/EventSourceServiceImplTest.java @@ -4,10 +4,10 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventsource.services.EventSourceService; import be.vlaanderen.informatievlaanderen.ldes.server.admin.domain.eventsource.services.EventSourceServiceImpl; import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.DeletionPolicyChangedEvent; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventSource; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -18,6 +18,11 @@ import java.util.List; import java.util.Optional; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.when; + @ExtendWith(MockitoExtension.class) class EventSourceServiceImplTest { private static final String COLLECTION_NAME = "collection"; @@ -40,29 +45,46 @@ void setUp() { @Test void when_SaveEventSource_Then_EventSourceSaved() { - eventSourceService.saveEventSource(COLLECTION_NAME, retentionModels); + when(eventSourceRepository.getEventSource(COLLECTION_NAME)) + .thenReturn(Optional.of(new EventSource(COLLECTION_NAME, List.of()))); + + eventSourceService.updateEventSource(COLLECTION_NAME, retentionModels); - InOrder inOrder = Mockito.inOrder(eventSourceRepository, eventPublisher); + InOrder inOrder = inOrder(eventSourceRepository, eventPublisher); + inOrder.verify(eventSourceRepository).getEventSource(COLLECTION_NAME); inOrder.verify(eventSourceRepository).saveEventSource(eventSourceArgumentCaptor.capture()); inOrder.verify(eventPublisher).publishEvent(ArgumentMatchers.any(DeletionPolicyChangedEvent.class)); inOrder.verifyNoMoreInteractions(); - Assertions.assertThat(eventSourceArgumentCaptor.getValue()) + assertThat(eventSourceArgumentCaptor.getValue()) .hasFieldOrPropertyWithValue("collectionName", COLLECTION_NAME) .hasFieldOrPropertyWithValue("retentionPolicies", retentionModels); } @Test void when_GetEventSource_Then_EventSourceIsRetrieved() { - Mockito.when(eventSourceRepository.getEventSource(COLLECTION_NAME)) + when(eventSourceRepository.getEventSource(COLLECTION_NAME)) .thenReturn(Optional.of(eventSource)); Optional actual = eventSourceService.getEventSource(COLLECTION_NAME); - InOrder inOrder = Mockito.inOrder(eventSourceRepository); + InOrder inOrder = inOrder(eventSourceRepository); inOrder.verify(eventSourceRepository).getEventSource(COLLECTION_NAME); inOrder.verifyNoMoreInteractions(); - Assertions.assertThat(actual.get()) + assertThat(actual) + .get() .hasFieldOrPropertyWithValue("collectionName", COLLECTION_NAME) .hasFieldOrPropertyWithValue("retentionPolicies", retentionModels); } + + @Test + void given_NonExistingEventStream_When_UpdateEventSource_then_ThrowException() { + when(eventSourceRepository.getEventSource(COLLECTION_NAME)) + .thenReturn(Optional.empty()); + + assertThatThrownBy(() -> eventSourceService.updateEventSource(COLLECTION_NAME, retentionModels)) + .isInstanceOf(MissingResourceException.class) + .hasMessage("Resource of type: eventstream with id: %s could not be found.", COLLECTION_NAME); + } + + } \ No newline at end of file diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerSteps.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerSteps.java index bfddaf962..5089f3ba6 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerSteps.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminEventStreamsRestControllerSteps.java @@ -101,6 +101,7 @@ public void aDbContainingOneEventStream() throws URISyntaxException { Model shape = readModelFromFile("shacl/server-shape.ttl"); final EventStreamTO eventStreamTO = new EventStreamTO.Builder().withEventStream(eventStream).withShacl(shape).build(); when(eventStreamRepository.retrieveEventStreamTO(COLLECTION)).thenReturn(Optional.of(eventStreamTO)); + when(eventSourceRepository.getEventSource(COLLECTION)).thenReturn(Optional.of(new EventSource(COLLECTION, List.of()))); eventPublisher.publishEvent(new EventStreamCreatedEvent(eventStream)); } @@ -223,4 +224,11 @@ public void iVerifyTheSavedEventStreamHasNoSkolemizationDomain() { public void iVerifyNoEventStreamHasBeenSavedToTheDb() { verify(eventStreamRepository, never()).saveEventStream(any()); } + + @When("the client posts an event source to that event stream") + public void theClientPostsAnEventSourceToThatEventStream() throws Exception { + resultActions = mockMvc.perform(put("/admin/api/v1/eventstreams/{collection}/eventsource", COLLECTION) + .contentType(Lang.TURTLE.getHeaderString()) + .content(readDataFromFile("retention/event-source.ttl"))); + } } diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/features/eventstreams/eventstreamscontroller.feature b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/features/eventstreams/eventstreamscontroller.feature index 4f7ae23d4..beb086908 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/features/eventstreams/eventstreamscontroller.feature +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/features/eventstreams/eventstreamscontroller.feature @@ -72,3 +72,13 @@ Feature: event streams can be configured at runtime | eventstream/streams/ldes.ttl | 201 | eventstream/streams-with-dcat/ldes-with-dcat.ttl | the saved event stream has no skolemization domain | | eventstream/streams/ldes-with-valid-skol-dom.ttl | 201 | eventstream/streams-with-dcat/ldes-with-dcat.ttl | the saved event stream has a skolemization domain | | eventstream/streams/ldes-with-invalid-skol-dom.ttl | 400 | shacl/invalid-skol-dom-report.ttl | no event stream has been saved to the db | + + Scenario: put an event source to an existing event stream + Given a db containing one event stream + When the client posts an event source to that event stream + Then the client receives HTTP status 200 + + Scenario: put an event source to an existing event stream + Given an empty db + When the client posts an event source to that event stream + Then the client receives HTTP status 404 diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/retention/event-source.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/retention/event-source.ttl new file mode 100644 index 000000000..ea4100a2b --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/retention/event-source.ttl @@ -0,0 +1,9 @@ +@prefix ldes: . +@prefix dcterms: . +@prefix tree: . + +<> a ldes:EventSource ; + ldes:retentionPolicy [ + a ldes:LatestVersionSubset ; + ldes:amount 2 ; + ]. \ No newline at end of file From 2e49eaea827d419556c7041f2f64f5ddff100d5a Mon Sep 17 00:00:00 2001 From: Ranko Orlic Date: Thu, 28 Nov 2024 14:26:43 +0100 Subject: [PATCH 15/45] fix: lock collection row to prevent interleaved sequence numbers in member_id when ingesting members (#1430) Co-authored-by: Jan Robert <15772440+Yalz@users.noreply.github.com> --- .../ldes/server/ingest/postgres/MemberPostgresRepository.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ldes-server-infra-postgres/postgres-ingest-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/postgres/MemberPostgresRepository.java b/ldes-server-infra-postgres/postgres-ingest-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/postgres/MemberPostgresRepository.java index 11d39efa2..8fce3b1f7 100644 --- a/ldes-server-infra-postgres/postgres-ingest-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/postgres/MemberPostgresRepository.java +++ b/ldes-server-infra-postgres/postgres-ingest-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/postgres/MemberPostgresRepository.java @@ -53,6 +53,10 @@ public int insertAll(List members) { }) .toList(); + // Note: that we lock the collection row to ensure no interleaved sequence numbers are assigned to the member_id + // Note: that the lock is released when txn is committed (upon method exit as it is transactional) + jdbcTemplate.queryForObject("SELECT name FROM collections WHERE collection_id = ? FOR UPDATE", String.class, collectionId); + jdbcTemplate.batchUpdate(INSERT_SQL, batchArgs); updateCollectionStats(members.size(), collectionId); From 915c82489713a7480d71952b8bb084f6a3a1caff Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:51:30 +0100 Subject: [PATCH 16/45] fix: wrong view stats update (#1431) * fix: wrong member pagination count in view stats chore: cleanup fragmentation service * fix: broken test * chore: implement PR remarks chore: add extra tests --- ...ce.java => FragmentationJobScheduler.java} | 47 ++++------- .../batch/BucketMetricUpdater.java | 2 +- ...itions.java => BucketStepDefinitions.java} | 2 +- .../batch/FragmentationJobDefintions.java | 28 +++++++ .../fragmentation/batch/OldJobsAbandoner.java | 34 ++++++++ .../src/main/java/module-info.java | 1 + ...ava => FragmentationJobSchedulerTest.java} | 27 +++--- .../batch/OldJobsAbandonerTest.java | 44 ++++++++++ .../services/TimeBasedBucketCreator.java | 2 +- .../batch/PaginationMetricUpdater.java | 43 ++++++++-- .../server/pagination/batch/Paginator.java | 21 +---- .../batch/PaginationMetricUpdaterTest.java | 83 +++++++++++++++++++ .../pagination/batch/PaginatorTest.java | 3 - .../batch/BucketisationItemWriter.java | 2 +- .../postgres/batch/MemberItemReader.java | 2 +- .../PostgresBucketisationIntegrationTest.java | 4 +- 16 files changed, 266 insertions(+), 79 deletions(-) rename ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/{FragmentationService.java => FragmentationJobScheduler.java} (69%) rename ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/{BucketJobDefinitions.java => BucketStepDefinitions.java} (97%) create mode 100644 ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefintions.java create mode 100644 ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandoner.java rename ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/{FragmentationServiceTest.java => FragmentationJobSchedulerTest.java} (77%) create mode 100644 ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandonerTest.java create mode 100644 ldes-server-fragmentation/ldes-server-pagination/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginationMetricUpdaterTest.java diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationService.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobScheduler.java similarity index 69% rename from ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationService.java rename to ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobScheduler.java index e404ecc60..a4350fcba 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationService.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobScheduler.java @@ -3,13 +3,14 @@ import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.entities.UnprocessedView; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.exceptions.FragmentationJobException; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.repository.UnprocessedViewRepository; -import org.springframework.batch.core.*; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.JobParametersInvalidException; import org.springframework.batch.core.explore.JobExplorer; -import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.job.builder.SimpleJobBuilder; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; -import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.JobRestartException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.EnableScheduling; @@ -21,12 +22,11 @@ import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.ServerConfig.FRAGMENTATION_CRON; import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BatchConfiguration.ASYNC_JOB_LAUNCHER; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BucketJobDefinitions.BUCKETISATION_STEP; +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefintions.FRAGMENTATION_JOB; @Service @EnableScheduling -public class FragmentationService { - public static final String FRAGMENTATION_JOB = "fragmentation"; +public class FragmentationJobScheduler { public static final String COLLECTION_NAME = "collectionName"; public static final String VIEW_NAME = "viewName"; public static final String COLLECTION_ID = "collectionId"; @@ -34,29 +34,27 @@ public class FragmentationService { public static final String LDES_SERVER_CREATE_FRAGMENTS_COUNT = "ldes_server_create_fragments_count"; private final JobLauncher jobLauncher; private final JobExplorer jobExplorer; - private final JobRepository jobRepository; - private final Job bucketiseJob; + private final Job fragmentationJob; private final UnprocessedViewRepository unprocessedViewRepository; - public FragmentationService(@Qualifier(ASYNC_JOB_LAUNCHER) JobLauncher jobLauncher, JobRepository jobRepository, JobExplorer jobExplorer, - @Qualifier(BUCKETISATION_STEP) Step bucketiseMembersStep, Step paginationStep, - UnprocessedViewRepository unprocessedViewRepository) { + public FragmentationJobScheduler(@Qualifier(ASYNC_JOB_LAUNCHER) JobLauncher jobLauncher, + JobExplorer jobExplorer, + SimpleJobBuilder fragmentationJobBuilder, + UnprocessedViewRepository unprocessedViewRepository) { this.jobLauncher = jobLauncher; this.jobExplorer = jobExplorer; - this.jobRepository = jobRepository; this.unprocessedViewRepository = unprocessedViewRepository; - this.bucketiseJob = createJob(bucketiseMembersStep, paginationStep); - this.cleanupOldJobs(); + this.fragmentationJob = fragmentationJobBuilder.build(); } @Scheduled(cron = FRAGMENTATION_CRON) - public void scheduledJobLauncher() { + public void scheduleJobs() { unprocessedViewRepository.findAll() .parallelStream() .filter(this::noJobsRunning) .forEach(unprocessedView -> { try { - jobLauncher.run(bucketiseJob, new JobParametersBuilder() + jobLauncher.run(fragmentationJob, new JobParametersBuilder() .addLong(VIEW_ID, (long) unprocessedView.viewId()) .addLong(COLLECTION_ID, (long) unprocessedView.collectionId()) .addString(VIEW_NAME, unprocessedView.viewName()) @@ -84,21 +82,4 @@ private boolean noJobsRunning(UnprocessedView unprocessedView) { return Objects.equals(fromParams, unprocessedView); }); } - - private Job createJob(Step step, Step paginationStep) { - return new JobBuilder(FRAGMENTATION_JOB, jobRepository) - .start(step) - .next(paginationStep) - .build(); - } - - public void cleanupOldJobs() { - jobExplorer.findRunningJobExecutions(FRAGMENTATION_JOB).forEach(this::stopJob); - } - - private void stopJob(JobExecution jobExecution) { - jobExecution.setStatus(BatchStatus.ABANDONED); - jobExecution.setEndTime(LocalDateTime.now()); - jobRepository.update(jobExecution); - } } diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketMetricUpdater.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketMetricUpdater.java index d7c5e598c..fa1709d32 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketMetricUpdater.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketMetricUpdater.java @@ -7,7 +7,7 @@ import org.springframework.batch.core.StepExecutionListener; import org.springframework.stereotype.Component; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationService.COLLECTION_NAME; +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationJobScheduler.COLLECTION_NAME; @Component public class BucketMetricUpdater implements StepExecutionListener { diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketJobDefinitions.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketStepDefinitions.java similarity index 97% rename from ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketJobDefinitions.java rename to ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketStepDefinitions.java index d3f706f92..573070e96 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketJobDefinitions.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/BucketStepDefinitions.java @@ -13,7 +13,7 @@ import org.springframework.transaction.PlatformTransactionManager; @Configuration -public class BucketJobDefinitions { +public class BucketStepDefinitions { public static final String BUCKETISATION_STEP = "bucketisation"; public static final int CHUNK_SIZE = 250; diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefintions.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefintions.java new file mode 100644 index 000000000..6f9ac27f3 --- /dev/null +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefintions.java @@ -0,0 +1,28 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch; + +import org.springframework.batch.core.JobExecutionListener; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.job.builder.SimpleJobBuilder; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BucketStepDefinitions.BUCKETISATION_STEP; + +@Configuration +public class FragmentationJobDefintions { + public static final String FRAGMENTATION_JOB = "fragmentation"; + + @Bean + public SimpleJobBuilder fragmentationJobBuilder(JobRepository jobRepository, + @Qualifier(BUCKETISATION_STEP) Step bucketisationStep, + Step paginationStep, + JobExecutionListener paginationViewStatsUpdater) { + return new JobBuilder(FRAGMENTATION_JOB, jobRepository) + .start(bucketisationStep) + .next(paginationStep) + .listener(paginationViewStatsUpdater); + } +} diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandoner.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandoner.java new file mode 100644 index 000000000..b4f9a91b9 --- /dev/null +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandoner.java @@ -0,0 +1,34 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefintions.FRAGMENTATION_JOB; + +@Component +public class OldJobsAbandoner implements CommandLineRunner { + private final JobRepository jobRepository; + private final JobExplorer jobExplorer; + + public OldJobsAbandoner(JobRepository jobRepository, JobExplorer jobExplorer) { + this.jobRepository = jobRepository; + this.jobExplorer = jobExplorer; + } + + @Override + public void run(String... args) { + jobExplorer.findRunningJobExecutions(FRAGMENTATION_JOB).forEach(this::abandonJob); + } + + private void abandonJob(JobExecution jobExecution) { + jobExecution.setStatus(BatchStatus.ABANDONED); + jobExecution.setEndTime(LocalDateTime.now()); + jobRepository.update(jobExecution); + } +} diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/module-info.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/module-info.java index a9005d06f..49a4c4265 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/module-info.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/module-info.java @@ -12,6 +12,7 @@ requires org.jetbrains.annotations; requires spring.tx; requires spring.core; + requires spring.boot; exports be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.entities; exports be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.repository; exports be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.valueobjects; diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationServiceTest.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobSchedulerTest.java similarity index 77% rename from ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationServiceTest.java rename to ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobSchedulerTest.java index bf70b717b..f2ac95081 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationServiceTest.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobSchedulerTest.java @@ -15,6 +15,8 @@ import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.Step; import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.job.builder.SimpleJobBuilder; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.repository.JobRepository; @@ -22,13 +24,14 @@ import java.util.Objects; import java.util.Set; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationService.*; +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationJobScheduler.*; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -class FragmentationServiceTest { +class FragmentationJobSchedulerTest { private static final String COLLECTION = "collection"; + private static final String FRAGMENTATION_JOB_NAME = "fragmentation"; @Mock private Step bucketStep; @Mock @@ -45,12 +48,16 @@ class FragmentationServiceTest { private UnprocessedViewRepository unprocessedViewRepository; @Captor private ArgumentCaptor captor; - private FragmentationService fragmentationService; + private FragmentationJobScheduler fragmentationJobScheduler; private List unprocessedViews; @BeforeEach void setUp() { - fragmentationService = new FragmentationService(jobLauncher, jobRepository, jobExplorer, bucketStep, paginationStep, unprocessedViewRepository); + final SimpleJobBuilder builder = new JobBuilder(FRAGMENTATION_JOB_NAME, jobRepository) + .start(bucketStep) + .next(paginationStep); + + fragmentationJobScheduler = new FragmentationJobScheduler(jobLauncher, jobExplorer, builder, unprocessedViewRepository); unprocessedViews = List.of( new UnprocessedView(1, COLLECTION, 1, "v1"), new UnprocessedView(1, COLLECTION, 2, "v2") @@ -61,11 +68,11 @@ void setUp() { void when_unprocessedViews_then_triggerJobsForEachView() throws Exception { when(unprocessedViewRepository.findAll()).thenReturn(unprocessedViews); - fragmentationService.scheduledJobLauncher(); + fragmentationJobScheduler.scheduleJobs(); verify(jobLauncher, times(2)).run(any(), captor.capture()); assertThat(captor.getAllValues()) - .map(FragmentationServiceTest::mapParamsToUnprocessedView) + .map(FragmentationJobSchedulerTest::mapParamsToUnprocessedView) .containsExactlyInAnyOrderElementsOf(unprocessedViews); } @@ -73,7 +80,7 @@ void when_unprocessedViews_then_triggerJobsForEachView() throws Exception { void when_noUnprocessedViews_then_triggerNone() { when(unprocessedViewRepository.findAll()).thenReturn(List.of()); - fragmentationService.scheduledJobLauncher(); + fragmentationJobScheduler.scheduleJobs(); verifyNoInteractions(jobLauncher); } @@ -90,13 +97,13 @@ void when_unprocessedViews_then_triggerJobsForEachViewThatIsntRunningAlready() t .addString(COLLECTION_NAME, COLLECTION) .toJobParameters(); when(jobExecution.getJobParameters()).thenReturn(jobParameters); - when(jobExplorer.findRunningJobExecutions(FRAGMENTATION_JOB)).thenReturn(Set.of(jobExecution)); + when(jobExplorer.findRunningJobExecutions("fragmentation")).thenReturn(Set.of(jobExecution)); - fragmentationService.scheduledJobLauncher(); + fragmentationJobScheduler.scheduleJobs(); verify(jobLauncher).run(any(), captor.capture()); assertThat(captor.getValue()) - .extracting(FragmentationServiceTest::mapParamsToUnprocessedView) + .extracting(FragmentationJobSchedulerTest::mapParamsToUnprocessedView) .isEqualTo(new UnprocessedView(1, COLLECTION, 2, "v2")); } diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandonerTest.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandonerTest.java new file mode 100644 index 000000000..44c3f83fb --- /dev/null +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandonerTest.java @@ -0,0 +1,44 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.repository.JobRepository; + +import java.util.Set; + +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefintions.FRAGMENTATION_JOB; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class OldJobsAbandonerTest { + @Mock + private JobExplorer jobExplorer; + @Mock + private JobRepository jobRepository; + @InjectMocks + private OldJobsAbandoner oldJobsAbandoner; + + @Test + void test_Run() { + when(jobExplorer.findRunningJobExecutions(FRAGMENTATION_JOB)).thenReturn(Set.of(new JobExecution(1L))); + + oldJobsAbandoner.run(); + + verify(jobRepository).update(new JobExecution(1L)); + } + + @Test + void given_NoOldJobs_Then_UpdateNothing() { + when(jobExplorer.findRunningJobExecutions(FRAGMENTATION_JOB)).thenReturn(Set.of()); + + oldJobsAbandoner.run(); + + verify(jobExplorer).findRunningJobExecutions(FRAGMENTATION_JOB); + verifyNoInteractions(jobRepository); + } +} \ No newline at end of file diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/services/TimeBasedBucketCreator.java b/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/services/TimeBasedBucketCreator.java index 32a53a177..1d0c690dc 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/services/TimeBasedBucketCreator.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-timebased-hierarchical/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentisers/timebasedhierarchical/services/TimeBasedBucketCreator.java @@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory; import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.ServerConstants.DEFAULT_BUCKET_STRING; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationService.LDES_SERVER_CREATE_FRAGMENTS_COUNT; +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationJobScheduler.LDES_SERVER_CREATE_FRAGMENTS_COUNT; import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.metrics.MetricsConstants.FRAGMENTATION_STRATEGY; import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.metrics.MetricsConstants.VIEW; import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentisers.timebasedhierarchical.HierarchicalTimeBasedFragmentationStrategy.TIMEBASED_FRAGMENTATION_HIERARCHICAL; diff --git a/ldes-server-fragmentation/ldes-server-pagination/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginationMetricUpdater.java b/ldes-server-fragmentation/ldes-server-pagination/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginationMetricUpdater.java index 101c40eb6..79e669c15 100644 --- a/ldes-server-fragmentation/ldes-server-pagination/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginationMetricUpdater.java +++ b/ldes-server-fragmentation/ldes-server-pagination/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginationMetricUpdater.java @@ -1,25 +1,50 @@ package be.vlaanderen.informatievlaanderen.ldes.server.pagination.batch; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.metrics.FragmentationMetricsService; -import org.jetbrains.annotations.NotNull; -import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobExecutionListener; import org.springframework.batch.core.StepExecution; -import org.springframework.batch.core.StepExecutionListener; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationService.COLLECTION_NAME; +import java.util.Objects; + +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BucketStepDefinitions.BUCKETISATION_STEP; @Component -public class PaginationMetricUpdater implements StepExecutionListener { +public class PaginationMetricUpdater implements JobExecutionListener { + private final JdbcTemplate jdbcTemplate; private final FragmentationMetricsService fragmentationMetricsService; - public PaginationMetricUpdater(FragmentationMetricsService fragmentationMetricsService) { + public PaginationMetricUpdater(JdbcTemplate jdbcTemplate, FragmentationMetricsService fragmentationMetricsService) { + this.jdbcTemplate = jdbcTemplate; this.fragmentationMetricsService = fragmentationMetricsService; } @Override - public ExitStatus afterStep(@NotNull StepExecution stepExecution) { - fragmentationMetricsService.updatePaginationCounts(stepExecution.getJobParameters().getString(COLLECTION_NAME)); - return StepExecutionListener.super.afterStep(stepExecution); + public void afterJob(JobExecution jobExecution) { + long viewId = Objects.requireNonNull(jobExecution.getJobParameters().getLong("viewId")); + String collectionName = Objects.requireNonNull(jobExecution.getJobParameters().getString("collectionName")); + + updateViewStats(getBucketisedMemberCount(jobExecution), viewId); + fragmentationMetricsService.updatePaginationCounts(collectionName); + } + + + private long getBucketisedMemberCount(JobExecution jobExecution) { + return jobExecution.getStepExecutions().stream() + .filter(stepExecution -> stepExecution.getStepName().equals(BUCKETISATION_STEP)) + .findFirst() + .map(StepExecution::getWriteCount) + .orElse(0L); + } + + private void updateViewStats(long uniqueMemberCount, long viewId) { + String sql = """ + UPDATE view_stats vs + SET paginated_count = vs.paginated_count + ? + where view_id = ?; + """; + jdbcTemplate.update(sql, uniqueMemberCount, viewId); } } diff --git a/ldes-server-fragmentation/ldes-server-pagination/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/Paginator.java b/ldes-server-fragmentation/ldes-server-pagination/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/Paginator.java index e15d32d9b..6bb418c97 100644 --- a/ldes-server-fragmentation/ldes-server-pagination/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/Paginator.java +++ b/ldes-server-fragmentation/ldes-server-pagination/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/Paginator.java @@ -8,7 +8,6 @@ import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.repeat.RepeatStatus; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import java.util.List; @@ -17,12 +16,10 @@ public class Paginator implements Tasklet { private final PageMemberRepository pageMemberRepository; private final PageRepository pageRepository; - private final JdbcTemplate jdbcTemplate; - public Paginator(PageMemberRepository pageMemberRepository, PageRepository pageRepository, JdbcTemplate jdbcTemplate) { + public Paginator(PageMemberRepository pageMemberRepository, PageRepository pageRepository) { this.pageMemberRepository = pageMemberRepository; this.pageRepository = pageRepository; - this.jdbcTemplate = jdbcTemplate; } @Override @@ -31,6 +28,7 @@ public RepeatStatus execute(StepContribution contribution, ChunkContext chunkCon long bucketId = context.getLong("bucketId"); List members = pageMemberRepository.getUnpaginatedMembersForBucket(bucketId); + chunkContext.getStepContext().getStepExecution().setReadCount(members.size()); if (members.isEmpty()) { return RepeatStatus.FINISHED; @@ -51,8 +49,7 @@ public RepeatStatus execute(StepContribution contribution, ChunkContext chunkCon openPage = fillPageWithMembers(openPage, pageMembers); } - updateViewStats(members.size(), Long.parseLong(chunkContext.getStepContext().getJobParameters().get("viewId").toString())); - + chunkContext.getStepContext().getStepExecution().setWriteCount(members.size()); return RepeatStatus.FINISHED; } @@ -62,19 +59,9 @@ private Page fillPageWithMembers(Page openPage, List pageMembers) { if (openPage.isFull()) { return pageRepository.createNextPage(openPage); - } - else { + } else { return openPage; } } - private void updateViewStats(long uniqueMemberCount, long viewId) { - String sql = """ - update view_stats vs set - paginated_count = vs.paginated_count + ? - where view_id = ?; - """; - - jdbcTemplate.update(sql, uniqueMemberCount, viewId); - } } diff --git a/ldes-server-fragmentation/ldes-server-pagination/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginationMetricUpdaterTest.java b/ldes-server-fragmentation/ldes-server-pagination/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginationMetricUpdaterTest.java new file mode 100644 index 000000000..b232077aa --- /dev/null +++ b/ldes-server-fragmentation/ldes-server-pagination/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginationMetricUpdaterTest.java @@ -0,0 +1,83 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.pagination.batch; + +import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.metrics.FragmentationMetricsService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.StepExecution; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.util.List; + +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BucketStepDefinitions.BUCKETISATION_STEP; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; + +@ExtendWith(MockitoExtension.class) +class PaginationMetricUpdaterTest { + private static final String COLLECTION = "observations"; + private static final long VIEW_ID = 1L; + private final JobParameters jobParams = new JobParametersBuilder() + .addLong("viewId", VIEW_ID) + .addString("collectionName", COLLECTION) + .toJobParameters(); + private final JobExecution jobExecution = new JobExecution(1L, jobParams); + @Mock + private JdbcTemplate jdbcTemplate; + @Mock + private FragmentationMetricsService fragmentationMetricsService; + @InjectMocks + private PaginationMetricUpdater paginationMetricUpdater; + + @Test + void test_AfterJob() { + final long bucketisedMemberCount = 2; + StepExecution stepExecution = new StepExecution(BUCKETISATION_STEP, jobExecution); + stepExecution.setWriteCount(bucketisedMemberCount); + jobExecution.addStepExecutions(List.of(stepExecution)); + + paginationMetricUpdater.afterJob(jobExecution); + + verify(fragmentationMetricsService).updatePaginationCounts(COLLECTION); + verify(jdbcTemplate).update(anyString(), eq(bucketisedMemberCount), eq(VIEW_ID)); + } + + @Test + void given_MissingStep_when_afterJob_then_AddZero() { + StepExecution stepExecution = new StepExecution("fantasy step", jobExecution); + jobExecution.addStepExecutions(List.of(stepExecution)); + + paginationMetricUpdater.afterJob(jobExecution); + + verify(fragmentationMetricsService).updatePaginationCounts(COLLECTION); + verify(jdbcTemplate).update(anyString(), eq(0L), eq(VIEW_ID)); + } + + @Test + void given_MissingViewId_when_afterJob_then_ThrowNullPointerException() { + StepExecution stepExecution = new StepExecution("fantasy step", jobExecution); + jobExecution.addStepExecutions(List.of(stepExecution)); + + assertThatNullPointerException().isThrownBy(() -> paginationMetricUpdater.afterJob(new JobExecution(2L))); + verifyNoInteractions(fragmentationMetricsService, jdbcTemplate); + } + + @Test + void given_MissingCollection_when_afterJob_then_ThrowNullPointerException() { + JobParameters viewIdJobParam = new JobParametersBuilder().addLong("viewId", VIEW_ID).toJobParameters(); + StepExecution stepExecution = new StepExecution("fantasy step", jobExecution); + jobExecution.addStepExecutions(List.of(stepExecution)); + + + assertThatNullPointerException().isThrownBy(() -> paginationMetricUpdater.afterJob(new JobExecution(2L, viewIdJobParam))); + verifyNoInteractions(fragmentationMetricsService, jdbcTemplate); + } +} \ No newline at end of file diff --git a/ldes-server-fragmentation/ldes-server-pagination/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginatorTest.java b/ldes-server-fragmentation/ldes-server-pagination/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginatorTest.java index 2f09d4ae5..aca807955 100644 --- a/ldes-server-fragmentation/ldes-server-pagination/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginatorTest.java +++ b/ldes-server-fragmentation/ldes-server-pagination/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/pagination/batch/PaginatorTest.java @@ -15,7 +15,6 @@ import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.scope.context.StepContext; import org.springframework.batch.item.ExecutionContext; -import org.springframework.jdbc.core.JdbcTemplate; import java.util.List; import java.util.Map; @@ -35,8 +34,6 @@ class PaginatorTest { private PageMemberRepository pageMemberRepository; @Mock private PageRepository pageRepository; - @Mock - private JdbcTemplate jdbcTemplate; @InjectMocks Paginator paginator; @Captor diff --git a/ldes-server-infra-postgres/postgres-fragmentation-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/batch/BucketisationItemWriter.java b/ldes-server-infra-postgres/postgres-fragmentation-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/batch/BucketisationItemWriter.java index 77dd50bce..a94609a7c 100644 --- a/ldes-server-infra-postgres/postgres-fragmentation-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/batch/BucketisationItemWriter.java +++ b/ldes-server-infra-postgres/postgres-fragmentation-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/batch/BucketisationItemWriter.java @@ -62,7 +62,7 @@ private void updateViewStats(long lastMemberId, long uniqueMemberCount) { bucketized_count = vs.bucketized_count + ?, bucketized_last_id = ? where view_id = ?; - """; + """; jdbcTemplate.update(sql, uniqueMemberCount, lastMemberId, viewId); } diff --git a/ldes-server-infra-postgres/postgres-fragmentation-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/batch/MemberItemReader.java b/ldes-server-infra-postgres/postgres-fragmentation-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/batch/MemberItemReader.java index 2b0afd2e5..17a3afc21 100644 --- a/ldes-server-infra-postgres/postgres-fragmentation-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/batch/MemberItemReader.java +++ b/ldes-server-infra-postgres/postgres-fragmentation-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/batch/MemberItemReader.java @@ -15,7 +15,7 @@ import java.util.HashMap; import java.util.Map; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BucketJobDefinitions.CHUNK_SIZE; +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BucketStepDefinitions.CHUNK_SIZE; @Configuration public class MemberItemReader { diff --git a/ldes-server-infra-postgres/postgres-fragmentation-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/PostgresBucketisationIntegrationTest.java b/ldes-server-infra-postgres/postgres-fragmentation-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/PostgresBucketisationIntegrationTest.java index 08406c2ba..c494e6960 100644 --- a/ldes-server-infra-postgres/postgres-fragmentation-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/PostgresBucketisationIntegrationTest.java +++ b/ldes-server-infra-postgres/postgres-fragmentation-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/postgres/PostgresBucketisationIntegrationTest.java @@ -1,7 +1,7 @@ package be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.postgres; import be.vlaanderen.informatievlaanderen.ldes.server.domain.services.FragmentationMetricsRepository; -import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationService; +import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.FragmentationJobScheduler; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.metrics.FragmentationMetricsService; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.postgres.batch.delegates.BucketisedMemberItemWriterConfig; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.postgres.repository.MemberEntityRepository; @@ -25,7 +25,7 @@ import static org.mockito.Mockito.mock; @CucumberContextConfiguration -@EnableAutoConfiguration(exclude = FragmentationService.class) +@EnableAutoConfiguration(exclude = FragmentationJobScheduler.class) @DataJpaTest @AutoConfigureEmbeddedDatabase(refresh = AutoConfigureEmbeddedDatabase.RefreshMode.BEFORE_EACH_TEST_METHOD) @EnableBatchProcessing From 55ead5d8f29228cfbdc19780b303efce8ae491ad Mon Sep 17 00:00:00 2001 From: pj-cegeka <119848850+pj-cegeka@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:09:54 +0100 Subject: [PATCH 17/45] fix/ fix admin view shacl shape (#1433) --- docs/_configuration/view.md | 3 +- .../controllers/AdminViewsRestController.java | 1 + .../src/main/resources/viewShaclShape.ttl | 88 +++++++++++++++++-- .../AdminViewsRestControllerSteps.java | 2 +- .../features/views/viewscontroller.feature | 16 ++-- .../src/test/resources/view/another-view.ttl | 2 +- .../view/view-with-duplicate-retention.ttl | 2 +- .../view/view-with-empty-fragmentation.ttl | 16 ++++ .../view/view-with-empty-retention.ttl | 17 ++++ .../view-with-multiple-fragmentations.ttl | 21 +++++ .../view/view-with-two-diff-retention.ttl | 2 +- .../view-with-wrong-type-fragmentation.ttl | 19 ++++ .../view/view-with-wrong-type-retention.ttl | 19 ++++ .../view/view-without-fragmentation.ttl | 15 ++++ .../resources/view/view-without-retention.ttl | 4 +- .../src/test/resources/view/view.ttl | 2 +- .../src/test/resources/view/view_valid.ttl | 2 +- 17 files changed, 210 insertions(+), 21 deletions(-) create mode 100644 ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-empty-fragmentation.ttl create mode 100644 ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-empty-retention.ttl create mode 100644 ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-multiple-fragmentations.ttl create mode 100644 ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-wrong-type-fragmentation.ttl create mode 100644 ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-wrong-type-retention.ttl create mode 100644 ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-without-fragmentation.ttl diff --git a/docs/_configuration/view.md b/docs/_configuration/view.md index e9f9cd2c6..8ce2a60bb 100644 --- a/docs/_configuration/view.md +++ b/docs/_configuration/view.md @@ -14,7 +14,7 @@ A view config needs to have the following structure: * A `tree:viewDescription` object with its subject referring to the event stream object * a `tree:FragmentationStrategy` object that contains an ordered rdf list of fragmentations. - * a `ldes:retentionPolicy` object that contains a set of retention policies. + * a `ldes:retentionPolicy` object that contains a set of retention policies. When no retention policies are required, this is omitted. * a `tree:pageSize` object that marks how many members should be partitioned per fragment. For more info, visit the [Swagger API documentation.](./admin-api) @@ -44,7 +44,6 @@ visit the [Retention Policies Subsection](./retention-policies). server:view-name tree:viewDescription [ a tree:fragmentationStrategy; tree:fragmentationStrategy () ; - ldes:retentionPolicy [] ; tree:pageSize "10"^^ ; ] . ```` diff --git a/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestController.java b/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestController.java index 45ef80d2c..17b5350fd 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestController.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestController.java @@ -49,6 +49,7 @@ public List getViews(@PathVariable String collectionName) { contentTypeNQuads}) public void createView(@PathVariable String collectionName, @RequestBody @Validated Model view) { + viewValidator.validate(view); viewService.addView(viewConverter.viewFromModel(view, collectionName)); } diff --git a/ldes-server-admin/ldes-server-admin-rest/src/main/resources/viewShaclShape.ttl b/ldes-server-admin/ldes-server-admin-rest/src/main/resources/viewShaclShape.ttl index 40a5fe4bf..2abc201a0 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/main/resources/viewShaclShape.ttl +++ b/ldes-server-admin/ldes-server-admin-rest/src/main/resources/viewShaclShape.ttl @@ -9,26 +9,42 @@ tree:ViewDescription sh:order 1; a sh:NodeShape ; + sh:targetClass tree:ViewDescription; sh:property [ sh:path tree:fragmentationStrategy ; sh:name "List of fragmentations"; sh:description "Ordered list of fragmentations how a member for this view should be processed"; - sh:or (tree:GeospatialFragmentation tree:HierarchicalTimeBasedFragmentation) ; + sh:or (tree:List rdf:nil) ; sh:minCount 1 ; sh:maxCount 1 ; ]; sh:property [ sh:path ldes:retentionPolicy; - sh:targetClass ldes:RetentionPolicy ; sh:name "List of retention policies"; sh:description "Unordered list of retention policies that declare when a member should be removed from the collection"; + sh:or (ldes:TimeBasedRetentionPolicy ldes:VersionBasedRetentionPolicy) ; ]. +tree:List + a sh:PropertyShape ; + sh:property [ + sh:path rdf:first ; + sh:or (tree:GeospatialFragmentation tree:HierarchicalTimeBasedFragmentation tree:ReferenceFragmentation) ; + ]; + sh:property [ + sh:path rdf:rest ; + sh:or (tree:List rdf:nil); +] . + +rdf:nil + a sh:PropertyShape ; + sh:hasValue rdf:nil . + tree:GeospatialFragmentation sh:order 2; a sh:NodeShape; - sh:class tree:GeospatialFragmentation ; sh:targetClass tree:GeospatialFragmentation ; + sh:class tree:GeospatialFragmentation ; sh:property [ sh:name "Max Zoom"; sh:description "Maximal zoom level the fragmentation should go"; @@ -44,11 +60,18 @@ tree:GeospatialFragmentation tree:HierarchicalTimeBasedFragmentation sh:order 2 ; a sh:NodeShape ; - sh:class: tree:HierarchicalTimeBasedFragmentation ; sh:targetClass tree:HierarchicalTimeBasedFragmentation ; - sh:zeroOrOnePath true; + sh:class tree:HierarchicalTimeBasedFragmentation ; sh:property tree:FragmentationPath, tree:MaxGranularity, tree:FragmentSubjectFilter . +tree:ReferenceFragmentation + sh:order 2; + a sh:NodeShape; + sh:targetClass tree:ReferenceFragmentation ; + sh:class tree:ReferenceFragmentation ; + sh:property tree:FragmentationKey ; + sh:property tree:FragmentationPathRef . + tree:MaxGranularity a sh:PropertyShape; sh:name "Max Granularity" ; @@ -81,10 +104,63 @@ tree:MemberLimit tree:FragmentationPath a sh:PropertyShape; sh:name "Fragmentation Path"; - sh:description "Path the fragmentation should use to find the "; + sh:description "Path the fragmentation should use to find the property used for fragmentation"; sh:path tree:fragmentationPath ; sh:nodeKind sh:IRI ; sh:minCount 1 ; sh:maxCount 1 . +tree:FragmentationPathRef + a sh:PropertyShape; + sh:name "Fragmentation Path"; + sh:description "Path the fragmentation should use to find the property used for fragmentation"; + sh:path tree:fragmentationPath ; + sh:nodeKind sh:IRI ; + sh:maxCount 1 . +tree:FragmentationKey + a sh:PropertyShape; + sh:name "Fragmentation Path"; + sh:description "Defines the request parameter that will be used in the uri"; + sh:path tree:fragmentationKey ; + sh:nodeKind sh:IRI ; + sh:maxCount 1 . + +ldes:TimeBasedRetentionPolicy + sh:order 2 ; + a sh:PropertyShape; + sh:name "Timebased Retention Policy"; + sh:description "Retention Policy defining how old members have to be before they are removed from the view."; + sh:targetClass ldes:DurationAgoPolicy ; + sh:class ldes:DurationAgoPolicy ; + sh:zeroOrOnePath true; + sh:property tree:TimebasedRetentionValue . + +ldes:VersionBasedRetentionPolicy + sh:order 2 ; + a sh:PropertyShape; + sh:name "Versionbased Retention Policy"; + sh:description "Retention Policy defining how many version-members of the same state object are retained in the view."; + sh:targetClass ldes:LatestVersionSubset ; + sh:class ldes:LatestVersionSubset ; + sh:zeroOrOnePath true; + sh:property ldes:VersionbaserRetentionAmount . + +tree:TimebasedRetentionValue + a sh:PropertyShape; + sh:name "Value"; + sh:description "The duration during which members will be kept for a certain retention policy."; + sh:path tree:value ; + sh:datatype ; + sh:minCount 1 ; + sh:maxCount 1 . + +ldes:VersionbaserRetentionAmount + a sh:PropertyShape; + sh:name "Amount"; + sh:description "The duration during which members will be kept for a certain retention policy."; + sh:path ldes:amount ; + sh:datatype xsd:integer ; + sh:minInclusive 1 ; + sh:minCount 1 ; + sh:maxCount 1 . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestControllerSteps.java b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestControllerSteps.java index 30534caac..ea99a087c 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestControllerSteps.java +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/rest/controllers/AdminViewsRestControllerSteps.java @@ -76,7 +76,7 @@ public void theEventStreamContainsTwoViews() { view2 = RDFDataMgr.loadModel("view/another-view.ttl"); final FragmentationConfig fragmentationConfig = new FragmentationConfig(); - fragmentationConfig.setName("ExampleFragmentation"); + fragmentationConfig.setName("ReferenceFragmentation"); fragmentationConfig.setConfig(Map.of("property", "ldes:propertyPath")); final Model retention = RDFDataMgr.loadModel("retention/ten-minutes-timebased-policy.ttl"); diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/features/views/viewscontroller.feature b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/features/views/viewscontroller.feature index 3f596335b..7e77df70f 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/features/views/viewscontroller.feature +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/features/views/viewscontroller.feature @@ -5,11 +5,17 @@ Feature: AdminViewsRestController When I POST a view from file "" to "/admin/api/v1/eventstreams/name1/views" Then I obtain an HTTP status Examples: - | fileName | status | - | view/view-without-retention.ttl | 201 | - | view/view.ttl | 201 | - | view/view-with-duplicate-retention.ttl | 400 | - | view/view-with-two-diff-retention.ttl | 201 | + | fileName | status | + | view/view-without-retention.ttl | 201 | + | view/view.ttl | 201 | + | view/view-with-duplicate-retention.ttl | 400 | + | view/view-with-two-diff-retention.ttl | 201 | + | view/view-with-empty-retention.ttl | 400 | + | view/view-with-wrong-type-retention.ttl | 400 | + | view/view-with-wrong-type-fragmentation.ttl | 400 | + | view/view-without-fragmentation.ttl | 400 | + | view/view-with-empty-fragmentation.ttl | 201 | + | view/view-with-multiple-fragmentations.ttl | 201 | Scenario: Add a view to a non-existing event stream Given an LDES server with an event stream diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/another-view.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/another-view.ttl index 228975adc..768604759 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/another-view.ttl +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/another-view.ttl @@ -11,7 +11,7 @@ viewName:description tree:value "PT10M"^^ ; ] ; tree:fragmentationStrategy ([ - a tree:ExampleFragmentation ; + a tree:ReferenceFragmentation ; tree:property "ldes:propertyPath" ]) . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-duplicate-retention.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-duplicate-retention.ttl index 8894981e0..f2e17afaa 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-duplicate-retention.ttl +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-duplicate-retention.ttl @@ -15,7 +15,7 @@ viewName:description tree:value "P1D"^^ ; ] ; tree:fragmentationStrategy ([ - a tree:ExampleFragmentation ; + a tree:ReferenceFragmentation ; tree:property "ldes:propertyPath" ]) . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-empty-fragmentation.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-empty-fragmentation.ttl new file mode 100644 index 000000000..8d0f7dca8 --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-empty-fragmentation.ttl @@ -0,0 +1,16 @@ +@prefix ldes: . +@prefix tree: . +@prefix server: . +@prefix viewName: . + +viewName:description + a tree:ViewDescription ; + tree:pageSize "100"^^; + ldes:retentionPolicy [ + a ldes:DurationAgoPolicy ; + tree:value "PT10M"^^ ; + ] ; + tree:fragmentationStrategy () . + +server:view1 a tree:Node ; + tree:viewDescription . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-empty-retention.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-empty-retention.ttl new file mode 100644 index 000000000..b7bea725d --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-empty-retention.ttl @@ -0,0 +1,17 @@ +@prefix ldes: . +@prefix tree: . +@prefix server: . +@prefix viewName: . + +viewName:description + a tree:ViewDescription ; + tree:pageSize "100"^^; + ldes:retentionPolicy [ + ] ; + tree:fragmentationStrategy ([ + a tree:ReferenceFragmentation ; + tree:property "ldes:propertyPath" + ]) . + +server:view1 a tree:Node ; + tree:viewDescription . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-multiple-fragmentations.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-multiple-fragmentations.ttl new file mode 100644 index 000000000..174372c4e --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-multiple-fragmentations.ttl @@ -0,0 +1,21 @@ +@prefix server: . +@prefix tree: . +@prefix viewName: . + +server:geospatial + a tree:Node ; + tree:viewDescription viewName:description . + +viewName:description + a tree:ViewDescription ; + tree:pageSize "100"^^; + tree:fragmentationStrategy ([ + a tree:GeospatialFragmentation ; + tree:maxZoom 15; + tree:fragmentationPath + ] [ + a tree:HierarchicalTimeBasedFragmentation ; + tree:maxGranularity "day" ; + tree:fragmentationPath ; + ] ) . + diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-two-diff-retention.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-two-diff-retention.ttl index 4c838d557..f11469839 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-two-diff-retention.ttl +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-two-diff-retention.ttl @@ -15,7 +15,7 @@ viewName:description ldes:amount 2 ; ] ; tree:fragmentationStrategy ([ - a tree:ExampleFragmentation ; + a tree:ReferenceFragmentation ; tree:property "ldes:propertyPath" ]) . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-wrong-type-fragmentation.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-wrong-type-fragmentation.ttl new file mode 100644 index 000000000..d61dbcf35 --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-wrong-type-fragmentation.ttl @@ -0,0 +1,19 @@ +@prefix ldes: . +@prefix tree: . +@prefix server: . +@prefix viewName: . + +viewName:description + a tree:ViewDescription ; + tree:pageSize "100"^^; + ldes:retentionPolicy [ + a ldes:DurationAgoPolicy ; + tree:value "PT10M"^^ ; + ] ; + tree:fragmentationStrategy ([ + a tree:WrongType ; + tree:property "ldes:propertyPath" + ]) . + +server:view1 a tree:Node ; + tree:viewDescription . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-wrong-type-retention.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-wrong-type-retention.ttl new file mode 100644 index 000000000..91c42dc19 --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-with-wrong-type-retention.ttl @@ -0,0 +1,19 @@ +@prefix ldes: . +@prefix tree: . +@prefix server: . +@prefix viewName: . + +viewName:description + a tree:ViewDescription ; + tree:pageSize "100"^^; + ldes:retentionPolicy [ + a ldes:WrongType ; + tree:value "PT10M"^^ ; + ] ; + tree:fragmentationStrategy ([ + a tree:ReferenceFragmentation ; + tree:property "ldes:propertyPath" + ]) . + +server:view1 a tree:Node ; + tree:viewDescription . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-without-fragmentation.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-without-fragmentation.ttl new file mode 100644 index 000000000..245ca3b7f --- /dev/null +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-without-fragmentation.ttl @@ -0,0 +1,15 @@ +@prefix ldes: . +@prefix tree: . +@prefix server: . +@prefix viewName: . + +viewName:description + a tree:ViewDescription ; + tree:pageSize "100"^^; + ldes:retentionPolicy [ + a ldes:DurationAgoPolicy ; + tree:value "PT10M"^^ ; + ] . + +server:view1 a tree:Node ; + tree:viewDescription . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-without-retention.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-without-retention.ttl index 3a9305f15..f6ff392df 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-without-retention.ttl +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view-without-retention.ttl @@ -7,8 +7,8 @@ viewName:description a tree:ViewDescription ; tree:pageSize "100"^^; tree:fragmentationStrategy ([ - a tree:ExampleFragmentation ; - tree:property "ldes:propertyPath" + a tree:ReferenceFragmentation ; + tree:property "ldes:propertyPath" ; ]) . server:view1 a tree:Node ; diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view.ttl index c21345af3..ad7614627 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view.ttl +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view.ttl @@ -11,7 +11,7 @@ viewName:description tree:value "PT10M"^^ ; ] ; tree:fragmentationStrategy ([ - a tree:ExampleFragmentation ; + a tree:ReferenceFragmentation ; tree:property "ldes:propertyPath" ]) . diff --git a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view_valid.ttl b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view_valid.ttl index 21e369805..e90ee6ece 100644 --- a/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view_valid.ttl +++ b/ldes-server-admin/ldes-server-admin-rest/src/test/resources/view/view_valid.ttl @@ -16,7 +16,7 @@ viewName:description a dcat:DataService , tree:ViewDescription ; tree:pageSize "100"^^; tree:fragmentationStrategy - ([ a tree:ExampleFragmentation ; + ([ a tree:ReferenceFragmentation ; tree:pageSize "100" ; tree:property "example/property" ]) ; From 2e64abb6bfeea7ff9235aad66218d176214e113b Mon Sep 17 00:00:00 2001 From: Jan Robert <15772440+Yalz@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:25:26 +0100 Subject: [PATCH 18/45] chore: dcat catalog repository: remove unreachable logic (#1435) * chore: remove unreachable logic * chore: remove unreachable logic * chore: make flaky test fail less --------- Co-authored-by: Yalz --- .../dcatserver/DcatCatalogPostgresRepository.java | 10 ++++------ .../DcatServerPostgresRepositoryTest.java | 13 ++----------- .../ldes/server/FragmentationSteps.java | 2 +- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/dcatserver/DcatCatalogPostgresRepository.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/dcatserver/DcatCatalogPostgresRepository.java index 97c7876b5..6ff52b95b 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/dcatserver/DcatCatalogPostgresRepository.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/dcatserver/DcatCatalogPostgresRepository.java @@ -43,11 +43,9 @@ public void deleteServerDcat(String id) { @Override public Optional findSingleDcatServer() { - List servers = repository.findAll().stream().map(converter::toDcatServer).toList(); - if (servers.size() > 1) { - throw new IllegalStateException("Multiple dcatServers found. There should be 0 or 1 record of this."); - } - - return servers.isEmpty() ? Optional.empty() : Optional.of(servers.get(0)); + return repository.findAll() + .stream() + .map(converter::toDcatServer) + .findFirst(); } } diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/dcatserver/DcatServerPostgresRepositoryTest.java b/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/dcatserver/DcatServerPostgresRepositoryTest.java index b30181ee2..4bfe0ec71 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/dcatserver/DcatServerPostgresRepositoryTest.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/dcatserver/DcatServerPostgresRepositoryTest.java @@ -15,7 +15,8 @@ import java.util.List; import java.util.Optional; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -96,16 +97,6 @@ void when_DbContainsElement_then_DeleteIt() { @Nested class FindSingleDcatServer { - @Test - void should_ThrowException_when_MoreThanOneResultFound() { - List entities = List.of( - new DcatCatalogEntity("id1", ""), - new DcatCatalogEntity("id2", "")); - when(dcatCatalogEntityRepository.findAll()).thenReturn(entities); - - assertThrows(IllegalStateException.class, () -> dcatServerRepository.findSingleDcatServer()); - } - @Test void should_ReturnEmpty_when_NoResultsFound() { List entities = List.of(); diff --git a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/FragmentationSteps.java b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/FragmentationSteps.java index 1b0528c9c..8eb2e9b39 100644 --- a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/FragmentationSteps.java +++ b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/FragmentationSteps.java @@ -60,7 +60,7 @@ private void fetchFragment(String path) throws Exception { @And("I fetch the next fragment through the first {string}") public void iFetchTheNextFragmentThroughTheFirst(String relation) { - await().atMost(60, TimeUnit.SECONDS) + await().atMost(90, TimeUnit.SECONDS) .untilAsserted(() -> { fetchFragment(currentPath); assertNotNull(currentFragment); From 6a86af75ea5fad005f32b55b14c7dda55479a64a Mon Sep 17 00:00:00 2001 From: Jonas Bulcke <127748878+jobulcke@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:25:45 +0100 Subject: [PATCH 19/45] feat: keep launching jobs until all work is done (#1436) * feat: use while loop to check if there is still fragmentation work to do * feat: fire event when there is fragmentation work to do * chore: extend tests --- .../FragmentationJobScheduler.java | 64 +++++++++-------- ....java => FragmentationJobDefinitions.java} | 8 ++- .../batch/FragmentationReadinessListener.java | 25 +++++++ .../fragmentation/batch/OldJobsAbandoner.java | 2 +- .../ContinueFragmentationTriggerEvent.java | 18 +++++ .../FragmentationJobSchedulerTest.java | 27 +++++-- .../FragmentationReadinessListenerTest.java | 70 +++++++++++++++++++ .../batch/OldJobsAbandonerTest.java | 2 +- 8 files changed, 173 insertions(+), 43 deletions(-) rename ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/{FragmentationJobDefintions.java => FragmentationJobDefinitions.java} (81%) create mode 100644 ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationReadinessListener.java create mode 100644 ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/valueobjects/ContinueFragmentationTriggerEvent.java create mode 100644 ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationReadinessListenerTest.java diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobScheduler.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobScheduler.java index a4350fcba..1fe639025 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobScheduler.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobScheduler.java @@ -3,16 +3,13 @@ import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.entities.UnprocessedView; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.exceptions.FragmentationJobException; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.repository.UnprocessedViewRepository; -import org.springframework.batch.core.Job; -import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.batch.core.JobParametersInvalidException; +import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.valueobjects.ContinueFragmentationTriggerEvent; +import org.springframework.batch.core.*; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.job.builder.SimpleJobBuilder; import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; -import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; -import org.springframework.batch.core.repository.JobRestartException; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -22,7 +19,7 @@ import static be.vlaanderen.informatievlaanderen.ldes.server.domain.constants.ServerConfig.FRAGMENTATION_CRON; import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BatchConfiguration.ASYNC_JOB_LAUNCHER; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefintions.FRAGMENTATION_JOB; +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefinitions.FRAGMENTATION_JOB; @Service @EnableScheduling @@ -52,34 +49,39 @@ public void scheduleJobs() { unprocessedViewRepository.findAll() .parallelStream() .filter(this::noJobsRunning) - .forEach(unprocessedView -> { - try { - jobLauncher.run(fragmentationJob, new JobParametersBuilder() - .addLong(VIEW_ID, (long) unprocessedView.viewId()) - .addLong(COLLECTION_ID, (long) unprocessedView.collectionId()) - .addString(VIEW_NAME, unprocessedView.viewName()) - .addString(COLLECTION_NAME, unprocessedView.collectionName()) - .addLocalDateTime("triggered", LocalDateTime.now()) - .toJobParameters()); - } catch (JobInstanceAlreadyCompleteException | JobExecutionAlreadyRunningException | - JobParametersInvalidException | JobRestartException e) { - throw new FragmentationJobException(e); - } - }); + .map(unprocessedView -> new JobParametersBuilder() + .addLong(VIEW_ID, (long) unprocessedView.viewId()) + .addLong(COLLECTION_ID, (long) unprocessedView.collectionId()) + .addString(VIEW_NAME, unprocessedView.viewName()) + .addString(COLLECTION_NAME, unprocessedView.collectionName()) + .addLocalDateTime("triggered", LocalDateTime.now()) + .toJobParameters()) + .forEach(this::launchSingleFragmentationJob); + } + + @EventListener + public void handleContinueFragmentationTriggerEvent(ContinueFragmentationTriggerEvent event) { + launchSingleFragmentationJob(event.getNewlyTriggeredJobParameters()); } private boolean noJobsRunning(UnprocessedView unprocessedView) { return jobExplorer.findRunningJobExecutions(FRAGMENTATION_JOB) .stream() - .noneMatch(jobExecution -> { - var params = jobExecution.getJobParameters(); - final UnprocessedView fromParams = new UnprocessedView( - Objects.requireNonNull(params.getLong(COLLECTION_ID)).intValue(), - params.getString(COLLECTION_NAME), - Objects.requireNonNull(params.getLong(VIEW_ID)).intValue(), - params.getString(VIEW_NAME) - ); - return Objects.equals(fromParams, unprocessedView); - }); + .map(JobExecution::getJobParameters) + .map(params -> new UnprocessedView( + Objects.requireNonNull(params.getLong(COLLECTION_ID)).intValue(), + params.getString(COLLECTION_NAME), + Objects.requireNonNull(params.getLong(VIEW_ID)).intValue(), + params.getString(VIEW_NAME) + )) + .noneMatch(unprocessedViewFromParams -> Objects.equals(unprocessedView, unprocessedViewFromParams)); + } + + private void launchSingleFragmentationJob(JobParameters jobParams) { + try { + jobLauncher.run(fragmentationJob, jobParams); + } catch (JobExecutionException e) { + throw new FragmentationJobException(e); + } } } diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefintions.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefinitions.java similarity index 81% rename from ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefintions.java rename to ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefinitions.java index 6f9ac27f3..2436d1d1f 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefintions.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationJobDefinitions.java @@ -12,17 +12,19 @@ import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.BucketStepDefinitions.BUCKETISATION_STEP; @Configuration -public class FragmentationJobDefintions { +public class FragmentationJobDefinitions { public static final String FRAGMENTATION_JOB = "fragmentation"; @Bean public SimpleJobBuilder fragmentationJobBuilder(JobRepository jobRepository, @Qualifier(BUCKETISATION_STEP) Step bucketisationStep, Step paginationStep, - JobExecutionListener paginationViewStatsUpdater) { + JobExecutionListener paginationMetricUpdater, + JobExecutionListener fragmentationReadinessListener) { return new JobBuilder(FRAGMENTATION_JOB, jobRepository) .start(bucketisationStep) .next(paginationStep) - .listener(paginationViewStatsUpdater); + .listener(paginationMetricUpdater) + .listener(fragmentationReadinessListener); } } diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationReadinessListener.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationReadinessListener.java new file mode 100644 index 000000000..6bb70ffa1 --- /dev/null +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationReadinessListener.java @@ -0,0 +1,25 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch; + +import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.valueobjects.ContinueFragmentationTriggerEvent; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobExecutionListener; +import org.springframework.batch.core.StepExecution; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +@Component +public class FragmentationReadinessListener implements JobExecutionListener { + private final ApplicationEventPublisher applicationEventPublisher; + + public FragmentationReadinessListener(ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } + + @Override + public void afterJob(JobExecution jobExecution) { + final boolean hasWorkAvailable = jobExecution.getStepExecutions().stream().findFirst().map(StepExecution::getReadCount).map(readCount -> readCount > 0).orElse(true); + if (hasWorkAvailable && !jobExecution.isRunning()) { + applicationEventPublisher.publishEvent(new ContinueFragmentationTriggerEvent(jobExecution.getJobParameters())); + } + } +} diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandoner.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandoner.java index b4f9a91b9..c723c6e55 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandoner.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandoner.java @@ -9,7 +9,7 @@ import java.time.LocalDateTime; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefintions.FRAGMENTATION_JOB; +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefinitions.FRAGMENTATION_JOB; @Component public class OldJobsAbandoner implements CommandLineRunner { diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/valueobjects/ContinueFragmentationTriggerEvent.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/valueobjects/ContinueFragmentationTriggerEvent.java new file mode 100644 index 000000000..b3a05c97e --- /dev/null +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/valueobjects/ContinueFragmentationTriggerEvent.java @@ -0,0 +1,18 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.valueobjects; + +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; + +import java.time.LocalDateTime; + +public class ContinueFragmentationTriggerEvent { + final JobParameters originalJobParameters; + + public ContinueFragmentationTriggerEvent(JobParameters originalJobParameters) { + this.originalJobParameters = originalJobParameters; + } + + public JobParameters getNewlyTriggeredJobParameters() { + return new JobParametersBuilder(originalJobParameters).addLocalDateTime("triggered", LocalDateTime.now()).toJobParameters(); + } +} diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobSchedulerTest.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobSchedulerTest.java index f2ac95081..3f0e90e41 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobSchedulerTest.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/FragmentationJobSchedulerTest.java @@ -1,8 +1,8 @@ package be.vlaanderen.informatievlaanderen.ldes.server.fragmentation; -import be.vlaanderen.informatievlaanderen.ldes.server.domain.services.MemberMetricsRepository; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.entities.UnprocessedView; import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.repository.UnprocessedViewRepository; +import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.valueobjects.ContinueFragmentationTriggerEvent; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -10,10 +10,7 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.JobParametersBuilder; -import org.springframework.batch.core.Step; +import org.springframework.batch.core.*; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.job.builder.JobBuilder; import org.springframework.batch.core.job.builder.SimpleJobBuilder; @@ -37,8 +34,6 @@ class FragmentationJobSchedulerTest { @Mock private Step paginationStep; @Mock - private MemberMetricsRepository memberMetricsRepository; - @Mock private JobLauncher jobLauncher; @Mock private JobExplorer jobExplorer; @@ -107,6 +102,24 @@ void when_unprocessedViews_then_triggerJobsForEachViewThatIsntRunningAlready() t .isEqualTo(new UnprocessedView(1, COLLECTION, 2, "v2")); } + @Test + void test_HandleContinueFragmentationTriggerEvent() throws JobExecutionException { + JobParameters jobParameters = new JobParametersBuilder() + .addLong(VIEW_ID, 1L) + .addLong(COLLECTION_ID, 1L) + .addString(VIEW_NAME, "v1") + .addString(COLLECTION_NAME, COLLECTION) + .toJobParameters(); + ContinueFragmentationTriggerEvent event = new ContinueFragmentationTriggerEvent(jobParameters); + + fragmentationJobScheduler.handleContinueFragmentationTriggerEvent(event); + + verify(jobLauncher).run(any(), captor.capture()); + assertThat(captor.getValue()) + .extracting(FragmentationJobSchedulerTest::mapParamsToUnprocessedView) + .isEqualTo(new UnprocessedView(1, COLLECTION, 1, "v1")); + } + private static UnprocessedView mapParamsToUnprocessedView(JobParameters params) { return new UnprocessedView( Objects.requireNonNull(params.getLong(COLLECTION_ID)).intValue(), diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationReadinessListenerTest.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationReadinessListenerTest.java new file mode 100644 index 000000000..217c9605d --- /dev/null +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/FragmentationReadinessListenerTest.java @@ -0,0 +1,70 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch; + +import be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.valueobjects.ContinueFragmentationTriggerEvent; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.StepExecution; +import org.springframework.context.ApplicationEventPublisher; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class FragmentationReadinessListenerTest { + @Mock + private ApplicationEventPublisher applicationEventPublisher; + @Mock + private JobExecution jobExecution; + @Mock + private StepExecution stepExecution; + @InjectMocks + private FragmentationReadinessListener fragmentationReadinessListener; + + @BeforeEach + void setUp() { + when(jobExecution.getStepExecutions()).thenReturn(List.of(stepExecution)); + } + + @Test + void when_AfterJob_then_PublishEvent() { + final JobParameters jobParameters = new JobParametersBuilder().addLong("viewId", 2L).toJobParameters(); + when(stepExecution.getReadCount()).thenReturn(2L); + when(jobExecution.isRunning()).thenReturn(false); + when(jobExecution.getJobParameters()).thenReturn(jobParameters); + + fragmentationReadinessListener.afterJob(jobExecution); + + verify(applicationEventPublisher).publishEvent(assertArg((ContinueFragmentationTriggerEvent event) -> assertThat(event) + .usingRecursiveComparison() + .isEqualTo(new ContinueFragmentationTriggerEvent(jobParameters)) + )); + } + + @Test + void when_StepDidNotReadAnything_then_DoNothing() { + when(stepExecution.getReadCount()).thenReturn(0L); + + fragmentationReadinessListener.afterJob(jobExecution); + + verifyNoInteractions(applicationEventPublisher); + } + + @Test + void when_JobIsRunning_then_DoNothing() { + when(stepExecution.getReadCount()).thenReturn(2L); + when(jobExecution.isRunning()).thenReturn(true); + + fragmentationReadinessListener.afterJob(jobExecution); + + verifyNoInteractions(applicationEventPublisher); + } +} \ No newline at end of file diff --git a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandonerTest.java b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandonerTest.java index 44c3f83fb..afedb58db 100644 --- a/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandonerTest.java +++ b/ldes-server-fragmentation/ldes-server-fragmentation-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/fragmentation/batch/OldJobsAbandonerTest.java @@ -11,7 +11,7 @@ import java.util.Set; -import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefintions.FRAGMENTATION_JOB; +import static be.vlaanderen.informatievlaanderen.ldes.server.fragmentation.batch.FragmentationJobDefinitions.FRAGMENTATION_JOB; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) From 8a60a327b23e7456ca2c6c4c40395c2d49c8d1c2 Mon Sep 17 00:00:00 2001 From: Jan Robert <15772440+Yalz@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:04:23 +0100 Subject: [PATCH 20/45] chore: delete kafka source in db when listener is removed (#1439) * chore: delete kafka source in db when listener is removed * chore: delete kafka source in db when listener is removed * chore: delete kafka source in db when listener is removed --------- Co-authored-by: Yalz --- .../eventstream/services/EventStreamServiceImpl.java | 5 +++++ .../domain/kafkasource/KafkaSourceRepository.java | 2 ++ .../services/EventStreamServiceImplTest.java | 7 +++++++ .../domain/events/admin/KafkaSourceDeletedEvent.java | 4 ++++ .../kafkasource/KafkaSourcePostgresRepository.java | 5 +++++ .../repository/KafkaSourceEntityRepository.java | 3 ++- .../kafka/controller/KafkaConsumerController.java | 12 +++++++++++- .../controller/KafkaConsumerControllerTest.java | 10 +++++++++- 8 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/events/admin/KafkaSourceDeletedEvent.java diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java index b0a66cdc1..ed2f7eb94 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImpl.java @@ -116,6 +116,11 @@ public void initEventStream() { .forEach(eventPublisher::publishEvent); } + @EventListener(KafkaSourceDeletedEvent.class) + public void handleKafkaSourceDeleted(KafkaSourceDeletedEvent event) { + kafkaSourceRepository.deleteWithTopic(event.topic()); + } + private void publishEventStreamTOCreatedEvents(EventStreamTO eventStreamTO) { eventPublisher.publishEvent(new EventStreamCreatedEvent(eventStreamTO.extractEventStreamProperties())); eventStreamTO.getViews().stream().map(ViewAddedEvent::new).forEach(eventPublisher::publishEvent); diff --git a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/kafkasource/KafkaSourceRepository.java b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/kafkasource/KafkaSourceRepository.java index 213d21deb..eb9e4a648 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/kafkasource/KafkaSourceRepository.java +++ b/ldes-server-admin/ldes-server-admin-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/kafkasource/KafkaSourceRepository.java @@ -7,4 +7,6 @@ public interface KafkaSourceRepository { void save(KafkaSourceProperties kafkaSource, Integer eventStreamId); List getAll(); + + void deleteWithTopic(String topic); } diff --git a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java index 6e2bd2db5..d7a65345b 100644 --- a/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java +++ b/ldes-server-admin/ldes-server-admin-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/domain/eventstream/services/EventStreamServiceImplTest.java @@ -12,6 +12,7 @@ import be.vlaanderen.informatievlaanderen.ldes.server.admin.spi.EventStreamTO; import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.EventStreamClosedEvent; import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.EventStreamDeletedEvent; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.KafkaSourceDeletedEvent; import be.vlaanderen.informatievlaanderen.ldes.server.domain.exceptions.MissingResourceException; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.EventStream; import be.vlaanderen.informatievlaanderen.ldes.server.domain.model.VersionCreationProperties; @@ -263,6 +264,12 @@ void when_closeEventStream_andEventStreamDoesNotExist_thenExceptionIsThrown() { Mockito.verify(eventPublisher, Mockito.never()).publishEvent(new EventStreamClosedEvent(COLLECTION)); } + @Test + void when_deleteKafkaSource_then_deleteKafkaSource() { + ((EventStreamServiceImpl) service).handleKafkaSourceDeleted(new KafkaSourceDeletedEvent(COLLECTION)); + Mockito.verify(kafkaSourceRepository).deleteWithTopic(COLLECTION); + } + private Model readModelFromFile(String fileName) throws URISyntaxException { ClassLoader classLoader = getClass().getClassLoader(); String uri = Objects.requireNonNull(classLoader.getResource(fileName)).toURI() diff --git a/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/events/admin/KafkaSourceDeletedEvent.java b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/events/admin/KafkaSourceDeletedEvent.java new file mode 100644 index 000000000..08af2724d --- /dev/null +++ b/ldes-server-domain/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/domain/events/admin/KafkaSourceDeletedEvent.java @@ -0,0 +1,4 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin; + +public record KafkaSourceDeletedEvent (String topic) { +} diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/KafkaSourcePostgresRepository.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/KafkaSourcePostgresRepository.java index 01622a36f..413790987 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/KafkaSourcePostgresRepository.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/KafkaSourcePostgresRepository.java @@ -30,4 +30,9 @@ public List getAll() { kafkaSourceEntity.getMimeType())) .toList(); } + + @Override + public void deleteWithTopic(String topic) { + repository.deleteByTopic(topic); + } } diff --git a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/repository/KafkaSourceEntityRepository.java b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/repository/KafkaSourceEntityRepository.java index d6b0b0815..607e29957 100644 --- a/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/repository/KafkaSourceEntityRepository.java +++ b/ldes-server-infra-postgres/postgres-admin-repository/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/admin/postgres/kafkasource/repository/KafkaSourceEntityRepository.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Repository; @Repository -public interface KafkaSourceEntityRepository extends JpaRepository { +public interface KafkaSourceEntityRepository extends JpaRepository { + void deleteByTopic(String topic); } diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerController.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerController.java index 8fa17dbdc..8522006bf 100644 --- a/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerController.java +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerController.java @@ -1,15 +1,18 @@ package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.controller; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.KafkaSourceDeletedEvent; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.KafkaListenerContainerManager; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.exception.KafkaConsumerException; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerAssignment; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerRequest; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerResponse; import org.apache.kafka.common.TopicPartition; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.kafka.listener.MessageListenerContainer; import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -17,9 +20,11 @@ @RequestMapping(path = "/consumers") public class KafkaConsumerController { private final KafkaListenerContainerManager kafkaListenerContainerManager; + private final ApplicationEventPublisher eventPublisher; - public KafkaConsumerController(KafkaListenerContainerManager kafkaListenerContainerManager) { + public KafkaConsumerController(KafkaListenerContainerManager kafkaListenerContainerManager, ApplicationEventPublisher eventPublisher) { this.kafkaListenerContainerManager = kafkaListenerContainerManager; + this.eventPublisher = eventPublisher; } @PostMapping @@ -94,6 +99,11 @@ public void delete(@PathVariable String listenerId) { MessageListenerContainer listenerContainer = getListenerContainer(listenerId); listenerContainer.stop(); kafkaListenerContainerManager.unregisterListener(listenerId); + Objects.requireNonNull(listenerContainer.getAssignedPartitions()) + .stream() + .map(TopicPartition::topic) + .map(KafkaSourceDeletedEvent::new) + .forEach(eventPublisher::publishEvent); } private MessageListenerContainer getListenerContainer(String listenerId) { diff --git a/ldes-server-ingest/ldes-server-ingest-kafka/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerControllerTest.java b/ldes-server-ingest/ldes-server-ingest-kafka/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerControllerTest.java index 1e5cbfdf8..fbbb50bf0 100644 --- a/ldes-server-ingest/ldes-server-ingest-kafka/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerControllerTest.java +++ b/ldes-server-ingest/ldes-server-ingest-kafka/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/ingest/kafka/controller/KafkaConsumerControllerTest.java @@ -1,10 +1,13 @@ package be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.controller; +import be.vlaanderen.informatievlaanderen.ldes.server.domain.events.admin.KafkaSourceDeletedEvent; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.KafkaListenerContainerManager; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerRequest; import be.vlaanderen.informatievlaanderen.ldes.server.ingest.kafka.model.KafkaConsumerResponse; +import org.apache.kafka.common.TopicPartition; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.kafka.listener.MessageListenerContainer; import java.util.Collections; @@ -20,11 +23,13 @@ class KafkaConsumerControllerTest { private KafkaListenerContainerManager kafkaListenerContainerManager; private KafkaConsumerController kafkaConsumerController; + private ApplicationEventPublisher eventPublisher; @BeforeEach void setUp() { kafkaListenerContainerManager = mock(KafkaListenerContainerManager.class); - kafkaConsumerController = new KafkaConsumerController(kafkaListenerContainerManager); + eventPublisher = mock(ApplicationEventPublisher.class); + kafkaConsumerController = new KafkaConsumerController(kafkaListenerContainerManager, eventPublisher); } @Test @@ -93,8 +98,11 @@ void stop() { void delete() { MessageListenerContainer container = mock(MessageListenerContainer.class); when(kafkaListenerContainerManager.getContainer(anyString())).thenReturn(Optional.of(container)); + when(container.getAssignedPartitions()).thenReturn(List.of(new TopicPartition("topic", 0))); kafkaConsumerController.delete("listenerId"); verify(container, times(1)).stop(); verify(kafkaListenerContainerManager, times(1)).unregisterListener("listenerId"); + verify(eventPublisher, times(1)).publishEvent(new KafkaSourceDeletedEvent("topic")); + } } \ No newline at end of file From c58e66cf0bce4596fcc33beaa9ce88cffca0ad5a Mon Sep 17 00:00:00 2001 From: Jonas Bulcke Date: Tue, 3 Dec 2024 16:06:34 +0100 Subject: [PATCH 21/45] feat: delete obsolete rows from spring batch db tables --- .../maintenance/batch/MaintenanceFlows.java | 4 +- .../tablecleanup/CompletedJobExecution.java | 4 + .../CompletedJobExecutionsConfig.java | 117 ++++++++++++++++++ .../src/main/java/module-info.java | 2 + 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 ldes-server-maintenance/ldes-server-retention/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/retention/batch/tablecleanup/CompletedJobExecution.java create mode 100644 ldes-server-maintenance/ldes-server-retention/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/retention/batch/tablecleanup/CompletedJobExecutionsConfig.java diff --git a/ldes-server-maintenance/ldes-server-maintenance-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/maintenance/batch/MaintenanceFlows.java b/ldes-server-maintenance/ldes-server-maintenance-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/maintenance/batch/MaintenanceFlows.java index dbdfcbcf7..b3b6e4cd9 100644 --- a/ldes-server-maintenance/ldes-server-maintenance-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/maintenance/batch/MaintenanceFlows.java +++ b/ldes-server-maintenance/ldes-server-maintenance-common/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/maintenance/batch/MaintenanceFlows.java @@ -19,10 +19,12 @@ public class MaintenanceFlows { @Bean public FlowJobBuilder maintenanceJobBuilder(JobRepository jobRepository, Flow viewRetentionFlow, - Flow eventSourceRetentionFlow) { + Flow eventSourceRetentionFlow, + Step completedJobExecutionsStep) { return new JobBuilder(MAINTENANCE_JOB, jobRepository) .start(viewRetentionFlow) .next(eventSourceRetentionFlow) + .next(completedJobExecutionsStep) .end(); } diff --git a/ldes-server-maintenance/ldes-server-retention/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/retention/batch/tablecleanup/CompletedJobExecution.java b/ldes-server-maintenance/ldes-server-retention/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/retention/batch/tablecleanup/CompletedJobExecution.java new file mode 100644 index 000000000..f1a7ab526 --- /dev/null +++ b/ldes-server-maintenance/ldes-server-retention/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/retention/batch/tablecleanup/CompletedJobExecution.java @@ -0,0 +1,4 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.retention.batch.tablecleanup; + +public record CompletedJobExecution(long jobExecutionId, long jobInstanceId) { +} diff --git a/ldes-server-maintenance/ldes-server-retention/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/retention/batch/tablecleanup/CompletedJobExecutionsConfig.java b/ldes-server-maintenance/ldes-server-retention/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/retention/batch/tablecleanup/CompletedJobExecutionsConfig.java new file mode 100644 index 000000000..c40ee337b --- /dev/null +++ b/ldes-server-maintenance/ldes-server-retention/src/main/java/be/vlaanderen/informatievlaanderen/ldes/server/retention/batch/tablecleanup/CompletedJobExecutionsConfig.java @@ -0,0 +1,117 @@ +package be.vlaanderen.informatievlaanderen.ldes.server.retention.batch.tablecleanup; + +import org.springframework.batch.core.Step; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder; +import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder; +import org.springframework.batch.item.support.CompositeItemWriter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.transaction.PlatformTransactionManager; + +import javax.sql.DataSource; +import java.util.List; +import java.util.Map; + +import static org.springframework.batch.item.database.Order.ASCENDING; + +@Configuration +public class CompletedJobExecutionsConfig { + + @Bean + public Step completedJobExecutionsStep(JobRepository jobRepository, + PlatformTransactionManager platformTransactionManager, + ItemReader completedJobExecutionsReader, + ItemWriter batchTableDeleter) { + return new StepBuilder("completedJobExecutionsStep", jobRepository) + .chunk(100, platformTransactionManager) + .reader(completedJobExecutionsReader) + .writer(batchTableDeleter) + .build(); + } + + @Bean + public ItemReader completedJobExecutionsReader(DataSource dataSource) { + return new JdbcPagingItemReaderBuilder() + .name("completedJobExecutionsReader") + .selectClause("JOB_EXECUTION_ID, JOB_INSTANCE_ID") + .fromClause("BATCH_JOB_EXECUTION") + .whereClause("EXIT_CODE = 'COMPLETED'") + .sortKeys(Map.of("JOB_EXECUTION_ID", ASCENDING)) + .pageSize(250) + .maxItemCount(1000) + .dataSource(dataSource) + .rowMapper((rs, rowNum) -> new CompletedJobExecution(rs.getLong("JOB_EXECUTION_ID"), rs.getLong("JOB_INSTANCE_ID"))) + .build(); + } + + @Bean + public ItemWriter batchTableDeleter(List> delegates) { + return new CompositeItemWriter<>(delegates); + } + + @Bean + @Order(1) + public ItemWriter batchStepExecutionContextDeleter(DataSource dataSource) { + return new JdbcBatchItemWriterBuilder() + .dataSource(dataSource) + .sql("DELETE FROM BATCH_STEP_EXECUTION_CONTEXT WHERE STEP_EXECUTION_ID IN (SELECT STEP_EXECUTION_ID FROM BATCH_STEP_EXECUTION WHERE JOB_EXECUTION_ID = ?)") + .itemPreparedStatementSetter((jobExecution, ps) -> ps.setLong(1, jobExecution.jobExecutionId())) + .build(); + } + + @Bean + @Order(2) + public ItemWriter batchStepExecutionDeleter(DataSource dataSource) { + return new JdbcBatchItemWriterBuilder() + .dataSource(dataSource) + .sql("DELETE FROM BATCH_STEP_EXECUTION WHERE JOB_EXECUTION_ID = ?") + .itemPreparedStatementSetter((jobExecution, ps) -> ps.setLong(1, jobExecution.jobExecutionId())) + .build(); + } + + @Bean + @Order(3) + public ItemWriter batchJobExecutionContextDeleter(DataSource dataSource) { + return new JdbcBatchItemWriterBuilder() + .dataSource(dataSource) + .sql("DELETE FROM BATCH_JOB_EXECUTION_CONTEXT WHERE JOB_EXECUTION_ID = ?") + .itemPreparedStatementSetter((jobExecution, ps) -> ps.setLong(1, jobExecution.jobExecutionId())) + .build(); + } + + @Bean + @Order(4) + public ItemWriter batchJobExecutionParamsDeleter(DataSource dataSource) { + return new JdbcBatchItemWriterBuilder() + .dataSource(dataSource) + .sql("DELETE FROM BATCH_JOB_EXECUTION_PARAMS WHERE JOB_EXECUTION_ID = ?") + .itemPreparedStatementSetter((jobExecution, ps) -> ps.setLong(1, jobExecution.jobExecutionId())) + .build(); + } + + @Bean + @Order(5) + public ItemWriter batchJobExecutionDeleter(DataSource dataSource) { + return new JdbcBatchItemWriterBuilder() + .dataSource(dataSource) + .sql("DELETE FROM BATCH_JOB_EXECUTION WHERE JOB_EXECUTION_ID = ?") + .itemPreparedStatementSetter((jobExecution, ps) -> ps.setLong(1, jobExecution.jobExecutionId())) + .build(); + } + + @Bean + @Order(6) + public ItemWriter batchJobInstanceDeleter(DataSource dataSource) { + return new JdbcBatchItemWriterBuilder() + .dataSource(dataSource) + .sql("DELETE FROM BATCH_JOB_INSTANCE WHERE JOB_INSTANCE_ID = ?") + .itemPreparedStatementSetter((jobExecution, ps) -> ps.setLong(1, jobExecution.jobInstanceId())) + .build(); + } + +} diff --git a/ldes-server-maintenance/ldes-server-retention/src/main/java/module-info.java b/ldes-server-maintenance/ldes-server-retention/src/main/java/module-info.java index 635cf440a..1d445f994 100644 --- a/ldes-server-maintenance/ldes-server-retention/src/main/java/module-info.java +++ b/ldes-server-maintenance/ldes-server-retention/src/main/java/module-info.java @@ -9,4 +9,6 @@ requires ldes.server.maintenance.common; requires spring.tx; requires spring.core; + requires spring.jdbc; + requires java.sql; } \ No newline at end of file From 87147b8e014ee089b632f2e2157c61ff896c29ad Mon Sep 17 00:00:00 2001 From: Jonas Bulcke Date: Tue, 3 Dec 2024 16:29:51 +0100 Subject: [PATCH 22/45] fix: broken test --- .../batch/MaintenanceJobDefinitionTest.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ldes-server-maintenance/ldes-server-maintenance-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/maintenance/batch/MaintenanceJobDefinitionTest.java b/ldes-server-maintenance/ldes-server-maintenance-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/maintenance/batch/MaintenanceJobDefinitionTest.java index 8516a5b26..7e77e32e9 100644 --- a/ldes-server-maintenance/ldes-server-maintenance-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/maintenance/batch/MaintenanceJobDefinitionTest.java +++ b/ldes-server-maintenance/ldes-server-maintenance-common/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/maintenance/batch/MaintenanceJobDefinitionTest.java @@ -47,6 +47,8 @@ class MaintenanceJobDefinitionTest { private Step deletionStep; @SpyBean(name = "eventSourceRetentionStep") private Step eventSourceRetentionStep; + @SpyBean(name = "completedJobExecutionsStep") + private Step completedJobExecutionsStep; @MockBean(name = "viewRetentionExecutionDecider") private JobExecutionDecider viewRetentionExecutionDecider; @@ -96,17 +98,19 @@ void given_NothingShouldBeSkipped_when_Execute_then_VerifyAllStepsInteraction() void given_AllShouldBeSkipped_when_Execute_then_VerifyNoStepsInteraction() throws Exception { when(viewRetentionExecutionDecider.decide(any(), any())).thenReturn(new FlowExecutionStatus("SKIP")); when(eventSourceRetentionExecutionDecider.decide(any(), any())).thenReturn(new FlowExecutionStatus("SKIP")); + doNothing().when(viewRetentionStep).execute(any()); final JobParameters jobParameters = new JobParametersBuilder() .addLocalDateTime("triggered", LocalDateTime.now()) .toJobParameters(); final JobExecution result = jobLauncherTestUtils.launchJob(jobParameters); - assertThat(result.getExitStatus().getExitCode()).isEqualTo(ExitStatus.NOOP.getExitCode()); + assertThat(result.getExitStatus().getExitCode()).isEqualTo(ExitStatus.COMPLETED.getExitCode()); verify(viewRetentionStep, never()).execute(any()); verify(compactionStep, never()).execute(any()); verify(deletionStep, never()).execute(any()); verify(eventSourceRetentionStep, never()).execute(any()); + verify(completedJobExecutionsStep).execute(any()); } @Test @@ -143,18 +147,27 @@ public Step compactionStep(JobRepository jobRepository, PlatformTransactionManag .tasklet(tasklet, transactionManager) .build(); } + @Bean(name = "deletionStep") public Step deletionStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) { return new StepBuilder("deletionStep", jobRepository) .tasklet(tasklet, transactionManager) .build(); } + @Bean(name = "eventSourceRetentionStep") public Step eventSourceRetentionStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) { return new StepBuilder("eventSourceRetentionStep", jobRepository) .tasklet(tasklet, transactionManager) .build(); } + + @Bean(name = "completedJobExecutionsStep") + public Step completedJobExecutionsStep(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) { + return new StepBuilder("completedJobExecutionsStep", jobRepository) + .tasklet(tasklet, platformTransactionManager) + .build(); + } } From 779788835b3413ddb9101d79154f2d9a496742cf Mon Sep 17 00:00:00 2001 From: Jonas Bulcke Date: Wed, 4 Dec 2024 15:28:28 +0100 Subject: [PATCH 23/45] chore: additional step added to ITs --- .../ldes/server/LdesServerSteps.java | 38 ++++++++++++++----- .../features/maintenance/retention.feature | 6 +++ .../batch/MaintenanceServiceTest.java | 15 +------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerSteps.java b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerSteps.java index 0ec36d412..e94381fcd 100644 --- a/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerSteps.java +++ b/ldes-server-integration-test/src/test/java/be/vlaanderen/informatievlaanderen/ldes/server/LdesServerSteps.java @@ -15,10 +15,13 @@ import org.apache.jena.rdf.model.Resource; import org.apache.jena.riot.*; import org.apache.jena.vocabulary.RDF; +import org.assertj.core.api.InstanceOfAssertFactories; import org.awaitility.Awaitility; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobInstance; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.launch.NoSuchJobException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; @@ -262,7 +265,7 @@ public void firstFragmentOfViewContainsMembers(String view, String collection, l Model fragmentPage = fetchFragment(fragmentUrl); return fragmentPage.listObjectsOfProperty(createProperty("https://w3id.org/tree#member")) - .toList().size() == expectedMemberCount; + .toList().size() == expectedMemberCount; }); } @@ -270,9 +273,9 @@ public void firstFragmentOfViewContainsMembers(String view, String collection, l public void theLDESContainsMembers(String collection, int expectedMemberCount) { await().atMost(60, SECONDS) .until(() -> jdbcTemplate - .queryForObject("SELECT COUNT(*) FROM members m JOIN collections c ON m.collection_id = c.collection_id WHERE c.name = ?", - Integer.class, collection) - == expectedMemberCount); + .queryForObject("SELECT COUNT(*) FROM members m JOIN collections c ON m.collection_id = c.collection_id WHERE c.name = ?", + Integer.class, collection) + == expectedMemberCount); } @After @@ -367,10 +370,27 @@ public void theResponseFromRequestingTheUrlDoesContainAJsonFile(String message, @And("the background processes did not fail") public void theBackgroundProcessesDidNotFail() { - JobInstance lastJobInstance = Objects.requireNonNull(jobExplorer.getLastJobInstance(MAINTENANCE_JOB)); - JobExecution lastJobExecution = Objects.requireNonNull(jobExplorer.getLastJobExecution(lastJobInstance)); - boolean hasFailedExecutions = lastJobExecution.getStepExecutions().stream() - .anyMatch(stepExecution -> stepExecution.getStatus().equals(BatchStatus.FAILED)); - assertThat(hasFailedExecutions).isFalse(); + assertThat(jobExplorer.getLastJobInstance(MAINTENANCE_JOB)) + .isNotNull() + .extracting(jobExplorer::getLastJobExecution) + .isNotNull() + .extracting(JobExecution::getStepExecutions, InstanceOfAssertFactories.list(StepExecution.class)) + .map(StepExecution::getStatus) + .doesNotContain(BatchStatus.FAILED); + } + + @And("the batch tables has been cleaned") + public void theBatchTablesHasBeenCleaned() throws NoSuchJobException { + final JobInstance lastJobInstance = jobExplorer.getLastJobInstance(MAINTENANCE_JOB); + assertThat(lastJobInstance).isNotNull(); + await() + .untilAsserted(() -> assertThat(jobExplorer.getLastJobExecution(lastJobInstance)) + .isNotNull() + .extracting(JobExecution::isRunning, InstanceOfAssertFactories.BOOLEAN) + .isFalse()); + assertThat(jobExplorer.getJobInstanceCount(MAINTENANCE_JOB)).isEqualTo(1); + assertThat(jobExplorer.getJobNames()) + .doesNotContain("fragmentation") + .hasSize(1); } } diff --git a/ldes-server-integration-test/src/test/resources/features/maintenance/retention.feature b/ldes-server-integration-test/src/test/resources/features/maintenance/retention.feature index 304468c3f..2ce9f8e17 100644 --- a/ldes-server-integration-test/src/test/resources/features/maintenance/retention.feature +++ b/ldes-server-integration-test/src/test/resources/features/maintenance/retention.feature @@ -8,6 +8,7 @@ Feature: LDES Server Retention # Since all added members' timestamp values equal to their ingestion date, they should be removed after 15 seconds Then the first fragment of the "paged" view in collection contains 0 members And the background processes did not fail + And the batch tables has been cleaned Examples: | eventStreamDescriptionFile | template | collection | ingestedMemberCount | | "data/input/eventstreams/retention/mobility-hindrances_timebased.ttl" | "data/input/members/mob-hind.template.ttl" | "mobility-hindrances" | 30 | @@ -19,6 +20,7 @@ Feature: LDES Server Retention When I ingest 30 members of template