From 4f239e055d15a6307967561c7154031ac0a2ec02 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Tue, 24 Dec 2024 15:15:40 -0700 Subject: [PATCH 01/25] Mark repartion classes for removal --- docker-compose.yml | 148 +++++++++--------- .../RepartitionStreamsAlgorithm.java | 2 + .../monitor/models/bsm/BsmRsuIdKey.java | 2 + .../topologies/RepartitionTopology.java | 2 + 4 files changed, 80 insertions(+), 74 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 97734383..25fc900d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,75 +1,75 @@ -include: - - docker-compose-ode.yml +#include: +# - docker-compose-ode.yml services: - conflictmonitor-build: - profiles: - - all - - cm_full - - cm_base - - cm_build - build: - context: . - dockerfile: Dockerfile - args: - MAVEN_GITHUB_TOKEN: ${MAVEN_GITHUB_TOKEN:?error} - MAVEN_GITHUB_ORG: ${MAVEN_GITHUB_ORG:?error} - image: jpo-conflictmonitor:latest - restart: ${RESTART_POLICY} - ports: - - "8082:8082" - environment: - DOCKER_HOST_IP: ${DOCKER_HOST_IP:?error} - KAFKA_BOOTSTRAP_SERVERS: ${KAFKA_BOOTSTRAP_SERVERS:?error} - CONNECT_URL: ${CONNECT_URL:?error} - spring.kafka.bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:?error} - healthcheck: - test: ["CMD", "java", "-version"] - interval: 10s - timeout: 10s - retries: 20 - logging: - options: - max-size: "10m" - max-file: "5" - deploy: - resources: - limits: - memory: 3G - depends_on: - kafka: - condition: service_healthy - required: false - - conflictmonitor-release: - profiles: - - cm_release - image: usdotjpoode/jpo-conflictmonitor:latest - restart: ${RESTART_POLICY} - ports: - - "8082:8082" - environment: - DOCKER_HOST_IP: ${DOCKER_HOST_IP:?error} - KAFKA_BOOTSTRAP_SERVERS: ${KAFKA_BOOTSTRAP_SERVERS:?error} - CONNECT_URL: ${CONNECT_URL:?error} - spring.kafka.bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:?error} - healthcheck: - test: ["CMD", "java", "-version"] - interval: 10s - timeout: 10s - retries: 20 - logging: - options: - max-size: "10m" - max-file: "5" - deploy: - resources: - limits: - memory: 3G - depends_on: - kafka: - condition: service_healthy - required: false +# conflictmonitor-build: +# profiles: +# - all +# - cm_full +# - cm_base +# - cm_build +# build: +# context: . +# dockerfile: Dockerfile +# args: +# MAVEN_GITHUB_TOKEN: ${MAVEN_GITHUB_TOKEN:?error} +# MAVEN_GITHUB_ORG: ${MAVEN_GITHUB_ORG:?error} +# image: jpo-conflictmonitor:latest +# restart: ${RESTART_POLICY} +# ports: +# - "8082:8082" +# environment: +# DOCKER_HOST_IP: ${DOCKER_HOST_IP:?error} +# KAFKA_BOOTSTRAP_SERVERS: ${KAFKA_BOOTSTRAP_SERVERS:?error} +# CONNECT_URL: ${CONNECT_URL:?error} +# spring.kafka.bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:?error} +# healthcheck: +# test: ["CMD", "java", "-version"] +# interval: 10s +# timeout: 10s +# retries: 20 +# logging: +# options: +# max-size: "10m" +# max-file: "5" +# deploy: +# resources: +# limits: +# memory: 3G +# depends_on: +# kafka: +# condition: service_healthy +# required: false +# +# conflictmonitor-release: +# profiles: +# - cm_release +# image: usdotjpoode/jpo-conflictmonitor:latest +# restart: ${RESTART_POLICY} +# ports: +# - "8082:8082" +# environment: +# DOCKER_HOST_IP: ${DOCKER_HOST_IP:?error} +# KAFKA_BOOTSTRAP_SERVERS: ${KAFKA_BOOTSTRAP_SERVERS:?error} +# CONNECT_URL: ${CONNECT_URL:?error} +# spring.kafka.bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:?error} +# healthcheck: +# test: ["CMD", "java", "-version"] +# interval: 10s +# timeout: 10s +# retries: 20 +# logging: +# options: +# max-size: "10m" +# max-file: "5" +# deploy: +# resources: +# limits: +# memory: 3G +# depends_on: +# kafka: +# condition: service_healthy +# required: false deduplicator: profiles: @@ -102,7 +102,7 @@ services: resources: limits: memory: 3G - depends_on: - kafka: - condition: service_healthy - required: false +# depends_on: +# kafka: +# condition: service_healthy +# required: false diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionStreamsAlgorithm.java index 5b093432..4fb0336c 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionStreamsAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionStreamsAlgorithm.java @@ -3,5 +3,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; +// TODO remove +@Deprecated(forRemoval = true) public interface RepartitionStreamsAlgorithm extends RepartitionAlgorithm, StreamsTopology {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmRsuIdKey.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmRsuIdKey.java index f6f7d3b4..fb1f6a9c 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmRsuIdKey.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmRsuIdKey.java @@ -9,6 +9,8 @@ import us.dot.its.jpo.geojsonconverter.DateJsonMapper; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIdKey; +// TODO Remove, use geojsonconverter RsuLogKey instead +@Deprecated(forRemoval = true) @EqualsAndHashCode @Getter @Setter diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/RepartitionTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/RepartitionTopology.java index 11cb7fd7..57290903 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/RepartitionTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/RepartitionTopology.java @@ -22,6 +22,8 @@ import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionConstants.DEFAULT_REPARTITION_ALGORITHM; +// TODO Remove this, don't need to repartition when using ProcessedBsm +@Deprecated(forRemoval = true) @Component(DEFAULT_REPARTITION_ALGORITHM) public class RepartitionTopology extends BaseStreamsTopology From 30796787e3925be0e238c0443fdb61963f4f56d4 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Tue, 24 Dec 2024 15:29:55 -0700 Subject: [PATCH 02/25] Mark classes to update --- .../its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java | 1 + .../conflictmonitor/monitor/processors/BsmEventProcessor.java | 1 + .../processors/BsmMessageCountProgressionProcessor.java | 1 + .../conflictmonitor/monitor/topologies/BsmEventTopology.java | 1 + .../monitor/topologies/BsmMessageCountProgressionTopology.java | 1 + .../monitor/topologies/IntersectionEventTopology.java | 3 ++- 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java index 3031e02e..b1caa050 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java @@ -10,6 +10,7 @@ import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; import us.dot.its.jpo.ode.model.OdeBsmData; +// TODO Use ProcessedBsm @Getter @Setter @EqualsAndHashCode diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java index e5972263..aa918a03 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java @@ -37,6 +37,7 @@ import java.util.*; import java.util.stream.Collectors; +// TODO Receive ProcessedBsm public class BsmEventProcessor extends ContextualProcessor { diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java index 6c9b1037..3a45b7f9 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java @@ -23,6 +23,7 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +// TODO Receive ProcessedBsm @Slf4j public class BsmMessageCountProgressionProcessor extends ContextualProcessor, String, BsmMessageCountProgressionEvent> { diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopology.java index a046f1e6..3707dcbe 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopology.java @@ -30,6 +30,7 @@ import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_event.BsmEventConstants.DEFAULT_BSM_EVENT_ALGORITHM; +// TODO Receive ProcessedBsm @Component(DEFAULT_BSM_EVENT_ALGORITHM) public class BsmEventTopology extends BaseStreamsTopology diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java index 2f019d79..13d545b2 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java @@ -22,6 +22,7 @@ import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_message_count_progression.BsmMessageCountProgressionConstants.DEFAULT_BSM_MESSAGE_COUNT_PROGRESSION_ALGORITHM; +// TODO Receive ProcessedBsm @Component(DEFAULT_BSM_MESSAGE_COUNT_PROGRESSION_ALGORITHM) @Slf4j public class BsmMessageCountProgressionTopology diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java index 16c7ceec..0d08b87e 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java @@ -52,6 +52,7 @@ import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.intersection_event.IntersectionEventConstants.*; +// TODO Use ProcessedBsm @Component(DEFAULT_INTERSECTION_EVENT_ALGORITHM) public class IntersectionEventTopology extends BaseStreamsTopology @@ -230,7 +231,7 @@ public void setStopLineStopParameters(StopLineStopParameters stopsParams) { - + // TODO Use ProcessedBsm private static BsmAggregator getBsmsByTimeVehicle(ReadOnlyWindowStore bsmWindowStore, Instant start, Instant end, BsmIntersectionIdKey key){ logger.info("getBsmsByTimeVehicle: Start: {}, End: {}, key: {}", start, end, key); From c33d495b5f5815577aac92f179b3e4feff04e658 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Tue, 24 Dec 2024 15:36:19 -0700 Subject: [PATCH 03/25] Remove repartition topology --- .../monitor/MonitorServiceController.java | 21 ----- .../repartition/RepartitionAlgorithm.java | 13 --- .../RepartitionAlgorithmFactory.java | 5 -- .../repartition/RepartitionAlgorithms.java | 16 ---- .../repartition/RepartitionConstants.java | 8 -- .../repartition/RepartitionParameters.java | 35 -------- .../RepartitionStreamsAlgorithm.java | 9 --- .../topologies/RepartitionTopology.java | 80 ------------------- .../src/main/resources/application.yaml | 12 +-- 9 files changed, 6 insertions(+), 193 deletions(-) delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithm.java delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithmFactory.java delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithms.java delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionConstants.java delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionParameters.java delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionStreamsAlgorithm.java delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/RepartitionTopology.java diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/MonitorServiceController.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/MonitorServiceController.java index eb542653..a617e731 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/MonitorServiceController.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/MonitorServiceController.java @@ -43,9 +43,6 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.notification.NotificationAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.notification.NotificationAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.notification.NotificationParameters; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionAlgorithm; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionAlgorithmFactory; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event_state_progression.EventStateProgressionAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_passage.StopLinePassageAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_passage.StopLinePassageAlgorithmFactory; @@ -129,24 +126,6 @@ public MonitorServiceController(final ConflictMonitorProperties conflictMonitorP configTopology.start(); - final String repartition = "repartition"; - final RepartitionAlgorithmFactory repartitionAlgoFactory = conflictMonitorProps.getRepartitionAlgorithmFactory(); - final String repAlgo = conflictMonitorProps.getRepartitionAlgorithm(); - final RepartitionAlgorithm repartitionAlgo = repartitionAlgoFactory.getAlgorithm(repAlgo); - final RepartitionParameters repartitionParams = conflictMonitorProps.getRepartitionAlgorithmParameters(); - configTopology.registerConfigListeners(repartitionParams); - if (repartitionAlgo instanceof StreamsTopology) { - final var streamsAlgo = (StreamsTopology)repartitionAlgo; - streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(repartition)); - streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, repartition, stateChangeTopic, healthTopic)); - streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, repartition, healthTopic)); - algoMap.put(repartition, streamsAlgo); - } - repartitionAlgo.setParameters(repartitionParams); - Runtime.getRuntime().addShutdownHook(new Thread(repartitionAlgo::stop)); - repartitionAlgo.start(); - - final String notification = "notification"; final NotificationAlgorithmFactory notificationAlgoFactory = conflictMonitorProps.getNotificationAlgorithmFactory(); final String notAlgo = conflictMonitorProps.getNotificationAlgorithm(); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithm.java deleted file mode 100644 index f22c5571..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithm.java +++ /dev/null @@ -1,13 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition; - -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.Algorithm; - -public interface RepartitionAlgorithm extends Algorithm{ - -} - - - - - - diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithmFactory.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithmFactory.java deleted file mode 100644 index c13aaa94..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithmFactory.java +++ /dev/null @@ -1,5 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition; - -public interface RepartitionAlgorithmFactory { - RepartitionAlgorithm getAlgorithm(String algorithmName); -} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithms.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithms.java deleted file mode 100644 index ae521f66..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionAlgorithms.java +++ /dev/null @@ -1,16 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.config.ServiceLocatorFactoryBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class RepartitionAlgorithms { - @Bean - public FactoryBean repartitionServiceLocatorFactoryBean() { - var factoryBean = new ServiceLocatorFactoryBean(); - factoryBean.setServiceLocatorInterface(RepartitionAlgorithmFactory.class); - return factoryBean; - } -} \ No newline at end of file diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionConstants.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionConstants.java deleted file mode 100644 index 50703690..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionConstants.java +++ /dev/null @@ -1,8 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition; - -public final class RepartitionConstants { - public static final String DEFAULT_REPARTITION_ALGORITHM = "defaultRepartitionAlgorithm"; - public static final String DEBUG_REPARTITION_ALGORITHM = "debugRepartitionAlgorithm"; -} - - diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionParameters.java deleted file mode 100644 index 0197ed34..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionParameters.java +++ /dev/null @@ -1,35 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; - -import lombok.Data; -import lombok.Generated; -import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigData; -import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigDataClass; -import static us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType.*; - -@Data -@Generated -@Component -@ConfigurationProperties(prefix = "repartition") -@ConfigDataClass -public class RepartitionParameters { - - // Whether to log diagnostic information for debugging - @ConfigData(key = "repartition.debug", - description = "Whether to log diagnostic information for debugging", - updateType = DEFAULT) - boolean debug; - - @ConfigData(key = "repartition.bsmInputTopicName", - description = "The name of the topic to read BSMs from", - updateType = READ_ONLY) - String bsmInputTopicName; - - @ConfigData(key = "repartition.bsmRepartitionOutputTopicName", - description = "The name of the topic to write repartitioned BSMs to", - updateType = READ_ONLY) - String bsmRepartitionOutputTopicName; - -} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionStreamsAlgorithm.java deleted file mode 100644 index 4fb0336c..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/repartition/RepartitionStreamsAlgorithm.java +++ /dev/null @@ -1,9 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition; - - -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; - -// TODO remove -@Deprecated(forRemoval = true) -public interface RepartitionStreamsAlgorithm - extends RepartitionAlgorithm, StreamsTopology {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/RepartitionTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/RepartitionTopology.java deleted file mode 100644 index 57290903..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/RepartitionTopology.java +++ /dev/null @@ -1,80 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.topologies; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.kstream.Consumed; -import org.apache.kafka.streams.kstream.KStream; -import org.apache.kafka.streams.kstream.Produced; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.BaseStreamsTopology; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionParameters; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionStreamsAlgorithm; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; -import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; -import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; -import us.dot.its.jpo.geojsonconverter.partitioner.RsuIdPartitioner; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.model.OdeBsmMetadata; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; - -import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionConstants.DEFAULT_REPARTITION_ALGORITHM; - -// TODO Remove this, don't need to repartition when using ProcessedBsm -@Deprecated(forRemoval = true) -@Component(DEFAULT_REPARTITION_ALGORITHM) -public class RepartitionTopology - extends BaseStreamsTopology - implements RepartitionStreamsAlgorithm { - - private static final Logger logger = LoggerFactory.getLogger(RepartitionTopology.class); - - - - @Override - protected Logger getLogger() { - return logger; - } - - - - @Override - public Topology buildTopology() { - - StreamsBuilder builder = new StreamsBuilder(); - - KStream bsmRepartitionStream = - builder.stream( - parameters.getBsmInputTopicName(), - Consumed.with( - Serdes.String(), - JsonSerdes.OdeBsm()) - ); - - - KStream bsmRekeyedStream = bsmRepartitionStream.selectKey((key, value)->{ - String ip = BsmUtils.getRsuIp(value); - String bsmId = BsmUtils.getVehicleId(value); - return new BsmRsuIdKey(ip, bsmId); - }); - - - bsmRekeyedStream.to( - parameters.getBsmRepartitionOutputTopicName(), - Produced.with( - JsonSerdes.BsmRsuIdKey(), - JsonSerdes.OdeBsm(), - new RsuIdPartitioner() - ) - ); - - - - return builder.build(); - - } - - -} diff --git a/jpo-conflictmonitor/src/main/resources/application.yaml b/jpo-conflictmonitor/src/main/resources/application.yaml index e90f8095..ba06cb41 100644 --- a/jpo-conflictmonitor/src/main/resources/application.yaml +++ b/jpo-conflictmonitor/src/main/resources/application.yaml @@ -267,12 +267,12 @@ map.validation: -# BSM Repartition -repartition: - algorithm: defaultRepartitionAlgorithm - debug: false - bsmInputTopicName: topic.OdeBsmJson - bsmRepartitionOutputTopicName: topic.CmBsmJsonRepartition +## BSM Repartition +#repartition: +# algorithm: defaultRepartitionAlgorithm +# debug: false +# bsmInputTopicName: topic.OdeBsmJson +# bsmRepartitionOutputTopicName: topic.CmBsmJsonRepartition notification: algorithm: defaultNotificationAlgorithm From d45b67c843f54973be2812d59be388eaed4ffb2f Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Thu, 26 Dec 2024 15:13:12 -0700 Subject: [PATCH 04/25] Converting BsmEventProcessor, BsmEvent, BsmTimestampExtractor --- .../monitor/models/bsm/BsmEvent.java | 26 ++-- .../models/bsm/BsmIntersectionIdKey.java | 1 + .../models/bsm/BsmTimestampExtractor.java | 61 ++++---- .../monitor/processors/BsmEventProcessor.java | 132 +++++++++--------- .../BsmMessageCountProgressionProcessor.java | 2 +- .../monitor/topologies/BsmEventTopology.java | 28 ++-- .../BsmMessageCountProgressionTopology.java | 2 +- .../monitor/utils/BsmUtils.java | 54 +++++++ .../src/main/resources/application.yaml | 2 +- 9 files changed, 176 insertions(+), 132 deletions(-) diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java index b1caa050..a2146de4 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmEvent.java @@ -1,24 +1,21 @@ package us.dot.its.jpo.conflictmonitor.monitor.models.bsm; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.EqualsAndHashCode; +import lombok.Generated; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; -import lombok.*; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; -import us.dot.its.jpo.ode.model.OdeBsmData; - -// TODO Use ProcessedBsm @Getter @Setter @EqualsAndHashCode @ToString @Generated public class BsmEvent { - private OdeBsmData startingBsm; - private OdeBsmData endingBsm; + private ProcessedBsm startingBsm; + private ProcessedBsm endingBsm; private Long startingBsmTimestamp; private Long endingBsmTimestamp; private String wktPath; @@ -28,16 +25,17 @@ public class BsmEvent { /** * Timestamp to use with wall clock punctuator + * TODO Remove/use TopologyTestDriver support */ private long wallClockTimestamp; public BsmEvent() {} - public BsmEvent(OdeBsmData startingBsm){ + public BsmEvent(ProcessedBsm startingBsm){ this.startingBsm = startingBsm; } - public BsmEvent(OdeBsmData startingBsm, OdeBsmData endingBsm){ + public BsmEvent(ProcessedBsm startingBsm, ProcessedBsm endingBsm){ this.startingBsm = startingBsm; this.endingBsm = endingBsm; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmIntersectionIdKey.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmIntersectionIdKey.java index bfd14b59..285d9bce 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmIntersectionIdKey.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmIntersectionIdKey.java @@ -15,6 +15,7 @@ public class BsmIntersectionIdKey extends RsuIntersectionKey { String bsmId; + // TODO Add log file public BsmIntersectionIdKey() {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmTimestampExtractor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmTimestampExtractor.java index b8964377..a118a42a 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmTimestampExtractor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmTimestampExtractor.java @@ -1,51 +1,54 @@ package us.dot.its.jpo.conflictmonitor.monitor.models.bsm; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalUnit; - +import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.streams.processor.TimestampExtractor; +import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; + -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +@Slf4j public class BsmTimestampExtractor implements TimestampExtractor { - private static final Logger logger = LoggerFactory.getLogger(BsmTimestampExtractor.class); @Override public long extract(ConsumerRecord record, long partitionTime) { - OdeBsmData bsm = (OdeBsmData) record.value(); - if(bsm != null){ - return getBsmTimestamp(bsm); + if (record.value() instanceof ProcessedBsm processedBsm) { + return getBsmTimestamp(processedBsm); } - return partitionTime; } - public static long getBsmTimestamp(OdeBsmData bsm){ + public static long getBsmTimestamp(ProcessedBsm bsm){ try{ - ZonedDateTime time = ZonedDateTime.parse(bsm.getMetadata().getOdeReceivedAt(), DateTimeFormatter.ISO_ZONED_DATE_TIME); - int secmark = ((J2735Bsm)bsm.getPayload().getData()).getCoreData().getSecMark(); - int second = (int)secmark / 1000; - int nanosecond = (secmark % 1000) * 1000000; - - ZonedDateTime refTime = ZonedDateTime.of(time.getYear(), time.getMonthValue(), time.getDayOfMonth(), time.getHour(), time.getMinute(), second, nanosecond, time.getZone()); - - // If the secondmark is close to the rollover point of the minute and the ODE received at time is at the beginning of the minute. Subtract a minute. - if(secmark > 50000 && time.getSecond() < 10){ - refTime = refTime.minus(1, ChronoUnit.MINUTES); - } - + ZonedDateTime time = ZonedDateTime.parse(bsm.getOdeReceivedAt(), DateTimeFormatter.ISO_ZONED_DATE_TIME); + BsmProperties properties = BsmUtils.getProperties(bsm).orElseThrow(); + final int secMark = properties.getSecMark(); + final ZonedDateTime refTime = getRefTime(secMark, time); return refTime.toInstant().toEpochMilli(); } catch (Exception e){ - logger.error("Timestamp Parsing Failed", e); + log.error("Timestamp Parsing Failed", e); return -1; } } + + private static ZonedDateTime getRefTime(int secMark, ZonedDateTime time) { + final int second = secMark / 1000; + final int nanosecond = (secMark % 1000) * 1000000; + + ZonedDateTime refTime = ZonedDateTime.of(time.getYear(), time.getMonthValue(), time.getDayOfMonth(), + time.getHour(), time.getMinute(), second, nanosecond, time.getZone()); + + // If the secondmark is close to the rollover point of the minute and the ODE received at time is at the + // beginning of the minute, subtract a minute. + if(secMark > 50000 && time.getSecond() < 10){ + refTime = refTime.minusMinutes(1); + } + return refTime; + } + } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java index aa918a03..432c4060 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java @@ -26,7 +26,11 @@ import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; import us.dot.its.jpo.conflictmonitor.monitor.utils.CoordinateConversion; import us.dot.its.jpo.conflictmonitor.monitor.utils.MathTransformPair; -import us.dot.its.jpo.ode.model.OdeBsmData; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmFeature; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; + import us.dot.its.jpo.ode.model.OdeBsmMetadata; import us.dot.its.jpo.ode.model.OdeBsmPayload; import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; @@ -37,10 +41,12 @@ import java.util.*; import java.util.stream.Collectors; -// TODO Receive ProcessedBsm -public class BsmEventProcessor extends ContextualProcessor { - - +public class BsmEventProcessor + extends ContextualProcessor< + RsuLogKey, + ProcessedBsm, + BsmIntersectionIdKey, + Object> { private static final Logger logger = LoggerFactory.getLogger(BsmEventProcessor.class); private final String fStoreName = "bsm-event-state-store"; @@ -89,9 +95,9 @@ public void close() { } @Override - public void process(Record inputRecord) { - BsmRsuIdKey key = inputRecord.key(); - OdeBsmData value = inputRecord.value(); + public void process(Record> inputRecord) { + RsuLogKey key = inputRecord.key(); + ProcessedBsm value = inputRecord.value(); long timestamp = inputRecord.timestamp(); if(!validateBSM(value)){ @@ -200,7 +206,13 @@ public void process(Record inputRecord) { } } - private void extendEvent(BsmIntersectionIdKey eventKey, BsmEvent event, Coordinate newCoord, OdeBsmData value, long timestamp) throws ParseException{ + private void extendEvent( + BsmIntersectionIdKey eventKey, + BsmEvent event, + Coordinate newCoord, + ProcessedBsm value, + long timestamp) throws ParseException{ + String wktPath = addPointToPath(event.getWktPath(), newCoord, simplifyPath, simplifyPathToleranceMeters); event.setWktPath(wktPath); @@ -223,7 +235,10 @@ private void extendEvent(BsmIntersectionIdKey eventKey, BsmEvent event, Coordina stateStore.put(eventKey, ValueAndTimestamp.make(event, timestamp)); } - private void newEvents(OdeBsmData value, BsmRsuIdKey key, List mapsContainingNewBsm, long timestamp) throws ParseException { + private void newEvents( + ProcessedBsm value, + RsuLogKey key, + List mapsContainingNewBsm, long timestamp) throws ParseException { if (mapsContainingNewBsm.isEmpty()) { // Not in any map. // Only create one. @@ -235,7 +250,10 @@ private void newEvents(OdeBsmData value, BsmRsuIdKey key, List m } } - private void newEvent(OdeBsmData value, BsmRsuIdKey key, long timestamp, MapBoundingBox map) throws ParseException { + private void newEvent( + ProcessedBsm value, + RsuLogKey key, long timestamp, + MapBoundingBox map) throws ParseException { BsmEvent event = getNewEvent(value, timestamp, true); event.setWktMapBoundingBox(map.getBoundingPolygonWkt()); event.setIntersectionID(map.getIntersectionId()); @@ -243,7 +261,7 @@ private void newEvent(OdeBsmData value, BsmRsuIdKey key, long timestamp, MapBoun stateStore.put(eventKey, ValueAndTimestamp.make(event, timestamp)); } - private void newEvent(OdeBsmData value, BsmRsuIdKey key, long timestamp) throws ParseException { + private void newEvent(ProcessedBsm value, RsuLogKey key, long timestamp) throws ParseException { BsmEvent event = getNewEvent(value, timestamp, false); var eventKey = new BsmIntersectionIdKey(key.getBsmId(), key.getRsuId(), 0); stateStore.put(eventKey, ValueAndTimestamp.make(event, timestamp)); @@ -251,7 +269,8 @@ private void newEvent(OdeBsmData value, BsmRsuIdKey key, long timestamp) throws - private BsmEvent getNewEvent(OdeBsmData value, long timestamp, boolean inMapBoundingBox) throws ParseException { + private BsmEvent getNewEvent(ProcessedBsm value, long timestamp, boolean inMapBoundingBox) + throws ParseException { BsmEvent event = new BsmEvent(value); CoordinateXY newCoord = BsmUtils.getPosition(value); String wktPath = addPointToPath(event.getWktPath(), newCoord, simplifyPath, simplifyPathToleranceMeters); @@ -288,102 +307,79 @@ private void punctuate(long timestamp) { } } - public static boolean validateBSM(OdeBsmData bsm){ + public static boolean validateBSM(ProcessedBsm bsm){ if (bsm == null) { logger.error("Null BSM"); return false; } - if (bsm.getPayload() == null) { - logger.error("BSM missing payload {}", bsm); - return false; - } - - if (!(bsm.getPayload() instanceof OdeBsmPayload)) { - logger.error("BSM payload is wrong type {}", bsm); - return false; - } - - if (bsm.getMetadata() == null) { - logger.error("BSM missing metadata {}", bsm); - return false; - } - - if (!(bsm.getMetadata() instanceof OdeBsmMetadata)) { - logger.error("BSM metadata is wrong type {}", bsm); - return false; - } - - if (bsm.getPayload().getData() == null) { - logger.error("BSM payload.data missing {}", bsm); + if (bsm.getFeatures() == null) { + logger.error("BSM missing features {}", bsm); return false; } - if (!(bsm.getPayload().getData() instanceof J2735Bsm)) { - logger.error("BSM payload.data is wrong type {}", bsm); + BsmFeature[] features = bsm.getFeatures(); + if (features.length == 0) { + logger.error("BSM features.length = 0 {}", bsm); return false; } - - - J2735BsmCoreData core = ((J2735Bsm)bsm.getPayload().getData()).getCoreData(); - if (core == null) { - logger.error("BSM coreData missing {}", bsm); + if (features.length > 1) { + logger.error("ProcessedBsm has more than one point, {}", bsm); return false; } - OdeBsmMetadata metadata = (OdeBsmMetadata)bsm.getMetadata(); + BsmFeature feature = features[0]; - if (core.getPosition() == null) { - logger.error("BSM position missing {}", bsm); - return false; - } - if(core.getPosition().getLongitude() == null){ - logger.error("BSM longitude missing {}", bsm); + if (feature.getGeometry() instanceof us.dot.its.jpo.geojsonconverter.pojos.geojson.Point pointGeom) { + double[] coords = pointGeom.getCoordinates(); + if (coords == null) { + logger.error("BSM coordinates missing {}", bsm); + return false; + } + if (coords.length < 2) { + logger.error("BSM coords array too small. {}", bsm); + return false; + } + } else { + logger.error("ProcessedBsm geometry is not us.dot.its.jpo.geojsonconverter.pojos.geojson.Point, {}", + feature.getGeometry()); return false; } - if(core.getPosition().getLatitude() == null){ - logger.error("BSM latitude missing {}", bsm); - return false; - } + BsmProperties props = feature.getProperties(); - if(core.getId() == null){ + if(props.getId() == null){ logger.error("BSM id missing {}", bsm); return false; } - if(core.getSecMark() == null){ + if(props.getSecMark() == null){ logger.error("BSM secMark missing {}", bsm); return false; } - if(core.getSpeed() == null){ + if(props.getSpeed() == null){ logger.error("BSM speed missing {}", bsm); return false; } - if(core.getHeading() == null){ + if(props.getHeading() == null){ logger.error("BSM heading missing {}", bsm); return false; } - if(metadata.getBsmSource() == null){ - logger.error("BSM source missing {}", bsm); - return false; - } - - if(metadata.getOriginIp() == null){ - logger.error("BSM originIp missing {}", bsm); + if(bsm.getLogName() == null && bsm.getOriginIp() == null){ + logger.error("BSM source (log name or origin IP) missing {}", bsm); return false; } - if (metadata.getRecordGeneratedAt() == null){ - logger.error("BSM recordGeneratedAt missing {}", bsm); + if (bsm.getTimeStamp() == null){ + logger.error("BSM timestamp missing {}", bsm); return false; } - if (metadata.getOdeReceivedAt() == null) { + if (bsm.getOdeReceivedAt() == null) { logger.error("BSM odeReceivedAt missing {}", bsm); return false; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java index 3a45b7f9..f67f8a87 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java @@ -23,7 +23,7 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -// TODO Receive ProcessedBsm +// TODO Use RsuLogKey @Slf4j public class BsmMessageCountProgressionProcessor extends ContextualProcessor, String, BsmMessageCountProgressionEvent> { diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopology.java index 3707dcbe..ba174335 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopology.java @@ -16,21 +16,21 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmIntersectionIdKey; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmTimestampExtractor; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapIndex; import us.dot.its.jpo.conflictmonitor.monitor.processors.BsmEventProcessor; import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; import us.dot.its.jpo.geojsonconverter.partitioner.IntersectionIdPartitioner; -import us.dot.its.jpo.geojsonconverter.partitioner.IntersectionKey; -import us.dot.its.jpo.geojsonconverter.partitioner.RsuIdPartitioner; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; +import us.dot.its.jpo.geojsonconverter.serialization.deserializers.ProcessedBsmDeserializer; import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; -import us.dot.its.jpo.ode.model.OdeBsmData; import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_event.BsmEventConstants.DEFAULT_BSM_EVENT_ALGORITHM; -// TODO Receive ProcessedBsm + @Component(DEFAULT_BSM_EVENT_ALGORITHM) public class BsmEventTopology extends BaseStreamsTopology @@ -50,21 +50,13 @@ public Topology buildTopology() { Topology bsmEventBuilder = new Topology(); - - - - - bsmEventBuilder.addSource(Topology.AutoOffsetReset.LATEST, BSM_SOURCE, new BsmTimestampExtractor(), - new JsonDeserializer<>(BsmRsuIdKey.class), - new JsonDeserializer<>(OdeBsmData.class), + new JsonDeserializer<>(RsuLogKey.class), + new ProcessedBsmDeserializer<>(Point.class), parameters.getInputTopic()); - - - bsmEventBuilder.addProcessor(BSM_PROCESSOR, () -> { var processor = new BsmEventProcessor(); @@ -81,8 +73,8 @@ public Topology buildTopology() { PARTITIONED_BSM_SINK, parameters.getBsmIntersectionOutputTopic(), new JsonSerializer(), - new JsonSerializer(), - new IntersectionIdPartitioner(), + new JsonSerializer>(), + new IntersectionIdPartitioner>(), BSM_PROCESSOR); // Output BSM Events @@ -119,7 +111,7 @@ protected Logger getLogger() { } - + // TODO Remove this and refactor tests to use Wall Clock time @Setter @Getter public PunctuationType punctuationType = PunctuationType.WALL_CLOCK_TIME; diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java index 13d545b2..a5f25593 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java @@ -22,7 +22,7 @@ import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_message_count_progression.BsmMessageCountProgressionConstants.DEFAULT_BSM_MESSAGE_COUNT_PROGRESSION_ALGORITHM; -// TODO Receive ProcessedBsm +// TODO Use RsuLogKey @Component(DEFAULT_BSM_MESSAGE_COUNT_PROGRESSION_ALGORITHM) @Slf4j public class BsmMessageCountProgressionTopology diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java index 78a579d8..71e9e558 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java @@ -2,6 +2,10 @@ import lombok.extern.slf4j.Slf4j; import org.locationtech.jts.geom.CoordinateXY; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmFeature; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.ode.model.OdeBsmData; import us.dot.its.jpo.ode.model.OdeBsmMetadata; import us.dot.its.jpo.ode.model.OdeBsmPayload; @@ -15,6 +19,56 @@ @Slf4j public class BsmUtils { + + + + public static CoordinateXY getPosition(ProcessedBsm processedBsm) { + CoordinateXY position = new CoordinateXY(); + Optional optionalPoint = getGeometry(processedBsm); + if (optionalPoint.isEmpty()) return position; + Point point = optionalPoint.get(); + double[] coordinates = point.getCoordinates(); + if (coordinates == null || coordinates.length < 2) return position; + position.setX(coordinates[0]); + position.setY(coordinates[1]); + return position; + } + + public static Optional> getFeature(ProcessedBsm processedBsm) { + if (processedBsm == null) return Optional.empty(); + if (processedBsm.getFeatures() == null || processedBsm.getFeatures().length < 1) return Optional.empty(); + return Optional.of(processedBsm.getFeatures()[0]); + } + + /** + * Get geometry + * @param processedBsm The ProcessedBsm + * @return The Point geometry, or empty if geometry is not a geojson Point. + */ + public static Optional getGeometry(ProcessedBsm processedBsm) { + Optional> optionalFeature = getFeature(processedBsm); + if (optionalFeature.isEmpty()) return Optional.empty(); + BsmFeature feature = optionalFeature.get(); + Object geom = feature.getGeometry(); + if (geom == null) return Optional.empty(); + if (geom instanceof Point point) { + return Optional.of(point); + } else { + return Optional.empty(); + } + } + + public static Optional getProperties(ProcessedBsm processedBsm) { + Optional> optFeature = getFeature(processedBsm); + if (optFeature.isEmpty()) return Optional.empty(); + BsmFeature feature = optFeature.get(); + BsmProperties properties = feature.getProperties(); + if (properties == null) return Optional.empty(); + return Optional.of(properties); + } + + + public static CoordinateXY getPosition(OdeBsmData bsm) { CoordinateXY position = new CoordinateXY(); Optional optionalCoreData = getCoreData(bsm); diff --git a/jpo-conflictmonitor/src/main/resources/application.yaml b/jpo-conflictmonitor/src/main/resources/application.yaml index ba06cb41..93d5fafd 100644 --- a/jpo-conflictmonitor/src/main/resources/application.yaml +++ b/jpo-conflictmonitor/src/main/resources/application.yaml @@ -393,7 +393,7 @@ intersection.reference.alignment.notification: # BSM Events bsm.event: algorithm: defaultBsmEventAlgorithm - inputTopic: topic.CmBsmJsonRepartition + inputTopic: topic.ProcessedBsm outputTopic: topic.CmBsmEvents bsmIntersectionOutputTopic: topic.CmBsmIntersection stateStoreName: bsm-event-state-store From 7385b7f365af6c2bcd95ffd84757e90e5c96ebe7 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Thu, 26 Dec 2024 16:11:51 -0700 Subject: [PATCH 05/25] Use ProcessedBsm in analytics classes --- .../IntersectionEventStreamsAlgorithm.java | 7 +-- .../MessageIngestStreamsAlgorithm.java | 5 +- .../ConnectionOfTravelAnalytics.java | 1 + .../LaneDirectionOfTravelAnalytics.java | 15 ++++-- .../analytics/StopLinePassageAnalytics.java | 35 ++++++++----- .../analytics/StopLineStopAnalytics.java | 12 ++--- .../Intersection/LineVehicleIntersection.java | 9 ++-- .../models/Intersection/VehiclePath.java | 42 +++++++-------- .../monitor/models/bsm/BsmAggregator.java | 20 ++++---- .../monitor/models/bsm/BsmRsuIdKey.java | 51 ------------------- .../topologies/IntersectionEventTopology.java | 17 ++++--- .../topologies/MessageIngestTopology.java | 1 + .../monitor/utils/BsmUtils.java | 26 ++++++++++ 13 files changed, 117 insertions(+), 124 deletions(-) delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmRsuIdKey.java diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/intersection_event/IntersectionEventStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/intersection_event/IntersectionEventStreamsAlgorithm.java index 0359c59f..6288751b 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/intersection_event/IntersectionEventStreamsAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/intersection_event/IntersectionEventStreamsAlgorithm.java @@ -5,17 +5,18 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmIntersectionIdKey; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; + public interface IntersectionEventStreamsAlgorithm extends IntersectionEventAlgorithm, StreamsTopology { - ReadOnlyWindowStore getBsmWindowStore(); + ReadOnlyWindowStore> getBsmWindowStore(); ReadOnlyWindowStore getSpatWindowStore(); ReadOnlyKeyValueStore> getMapStore(); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/message_ingest/MessageIngestStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/message_ingest/MessageIngestStreamsAlgorithm.java index 3fac74dd..ddc53ced 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/message_ingest/MessageIngestStreamsAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/message_ingest/MessageIngestStreamsAlgorithm.java @@ -8,14 +8,15 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmIntersectionIdKey; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; public interface MessageIngestStreamsAlgorithm extends MessageIngestAlgorithm { - ReadOnlyWindowStore getBsmWindowStore(KafkaStreams streams); + ReadOnlyWindowStore> getBsmWindowStore(KafkaStreams streams); ReadOnlyWindowStore getSpatWindowStore(KafkaStreams streams); ReadOnlyKeyValueStore> getMapStore(KafkaStreams streams); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/ConnectionOfTravelAnalytics.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/ConnectionOfTravelAnalytics.java index 2f0e25aa..819dc389 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/ConnectionOfTravelAnalytics.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/ConnectionOfTravelAnalytics.java @@ -11,6 +11,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmTimestampExtractor; import us.dot.its.jpo.conflictmonitor.monitor.models.events.ConnectionOfTravelEvent; +// TODO Use Processed BSM @Component(DEFAULT_CONNECTION_OF_TRAVEL_ALGORITHM) public class ConnectionOfTravelAnalytics implements ConnectionOfTravelAlgorithm{ diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/LaneDirectionOfTravelAnalytics.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/LaneDirectionOfTravelAnalytics.java index 4e9920d0..58780911 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/LaneDirectionOfTravelAnalytics.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/LaneDirectionOfTravelAnalytics.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Optional; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.LineString; @@ -18,10 +19,10 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.Intersection.VehiclePath; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmTimestampExtractor; import us.dot.its.jpo.conflictmonitor.monitor.models.events.LaneDirectionOfTravelEvent; +import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; import us.dot.its.jpo.conflictmonitor.monitor.utils.CoordinateConversion; import us.dot.its.jpo.conflictmonitor.monitor.utils.MathFunctions; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; @Component(DEFAULT_LANE_DIRECTION_OF_TRAVEL_ALGORITHM) public class LaneDirectionOfTravelAnalytics implements LaneDirectionOfTravelAlgorithm{ @@ -102,12 +103,16 @@ protected ArrayList getLaneDirectionEvents(VehiclePa if(bsmIndecies.size() > this.parameters.getMinimumPointsPerSegment()){ for(Integer index : bsmIndecies){ - OdeBsmData bsm = path.getBsms().getBsms().get(index); + ProcessedBsm bsm = path.getBsms().getBsms().get(index); Point pathPoint = path.getPathPoints().getPointN(index); double distance = pathPoint.distance(segment.getCenterLine()); - - headings.add(((J2735Bsm)bsm.getPayload().getData()).getCoreData().getHeading().doubleValue()); + Optional optHeading = BsmUtils.getHeading(bsm); + if (optHeading.isPresent()) { + headings.add(optHeading.get()); + } else { + headings.add(null); + } offsetDistances.add(distance); times.add(BsmTimestampExtractor.getBsmTimestamp(bsm)); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/StopLinePassageAnalytics.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/StopLinePassageAnalytics.java index 2d9c503c..cffd9053 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/StopLinePassageAnalytics.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/StopLinePassageAnalytics.java @@ -2,6 +2,7 @@ import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_passage.StopLinePassageConstants.*; +import org.locationtech.jts.geom.CoordinateXY; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -15,13 +16,17 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.events.StopLinePassageEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatAggregator; import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.spat.MovementState; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; import us.dot.its.jpo.ode.plugin.j2735.J2735MovementPhaseState; +import java.util.Optional; import java.util.Set; + @Component(DEFAULT_SIGNAL_STATE_VEHICLE_CROSSES_ALGORITHM) public class StopLinePassageAnalytics implements StopLinePassageAlgorithm { @@ -41,7 +46,7 @@ public StopLinePassageEvent getStopLinePassageEvent(StopLinePassageParameters pa } - OdeBsmData bsm = path.getIngressBsm(); + ProcessedBsm bsm = path.getIngressBsm(); long bsmTime = BsmTimestampExtractor.getBsmTimestamp(bsm); @@ -91,7 +96,8 @@ public StopLinePassageEvent getStopLinePassageEvent(StopLinePassageParameters pa J2735MovementPhaseState signalState = getSignalGroupState(matchingSpat, signalGroup); - var optCoreData = BsmUtils.getCoreData(bsm); + Optional optProperties = BsmUtils.getProperties(bsm); + CoordinateXY position = BsmUtils.getPosition(bsm); StopLinePassageEvent event = new StopLinePassageEvent(); event.setTimestamp(bsmTime); @@ -105,18 +111,19 @@ public StopLinePassageEvent getStopLinePassageEvent(StopLinePassageParameters pa if (egressLane != null) { event.setEgressLane(egressLane.getId()); } - if (optCoreData.isPresent()) { - var coreData = optCoreData.get(); - event.setVehicleID(coreData.getId()); - if (coreData.getPosition() != null) { - event.setLongitude(coreData.getPosition().getLongitude().doubleValue()); - event.setLatitude(coreData.getPosition().getLatitude().doubleValue()); - } - if (coreData.getHeading() != null) { - event.setHeading(coreData.getHeading().doubleValue()); + + event.setLongitude(position.getX()); + event.setLatitude(position.getY()); + + if (optProperties.isPresent()) { + BsmProperties properties = optProperties.get(); + event.setVehicleID(properties.getId()); + + if (properties.getHeading() != null) { + event.setHeading(properties.getHeading().doubleValue()); } - if (coreData.getSpeed() != null) { - event.setSpeed(coreData.getSpeed().doubleValue()); + if (properties.getSpeed() != null) { + event.setSpeed(properties.getSpeed().doubleValue()); } } event.setSignalGroup(signalGroup); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/StopLineStopAnalytics.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/StopLineStopAnalytics.java index ff8fa3e9..655a5683 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/StopLineStopAnalytics.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/StopLineStopAnalytics.java @@ -18,15 +18,15 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatAggregator; import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; import us.dot.its.jpo.conflictmonitor.monitor.utils.SpatUtils; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; import us.dot.its.jpo.ode.plugin.j2735.J2735MovementPhaseState; import java.util.List; import java.util.Optional; import java.util.Set; - @Component(DEFAULT_SIGNAL_STATE_VEHICLE_STOPS_ALGORITHM) public class StopLineStopAnalytics implements StopLineStopAlgorithm { @@ -46,14 +46,14 @@ public StopLineStopEvent getStopLineStopEvent(StopLineStopParameters parameters, } // Find stop events within the stopping search distance along the ingress lane. - List bsmList = path.findBsmsInIngressLane(ingressLane, parameters.getUpstreamSearchDistance()); - List stoppedBsmList = path.filterStoppedBsms(bsmList, parameters.getStopSpeedThreshold()); + List> bsmList = path.findBsmsInIngressLane(ingressLane, parameters.getUpstreamSearchDistance()); + List> stoppedBsmList = path.filterStoppedBsms(bsmList, parameters.getStopSpeedThreshold()); if (stoppedBsmList.size() < 2) { logger.info("Fewer than 2 stopped BSMs found for path {}, can't generate StopLineStop event", path); return null; } - OdeBsmData firstStoppedBsm = stoppedBsmList.get(0); - OdeBsmData lastStoppedBsm = stoppedBsmList.get(stoppedBsmList.size() - 1); + ProcessedBsm firstStoppedBsm = stoppedBsmList.getFirst(); + ProcessedBsm lastStoppedBsm = stoppedBsmList.getLast(); long firstTimestamp = BsmTimestampExtractor.getBsmTimestamp(firstStoppedBsm); logger.info("First stopped BSM timestamp {}", firstTimestamp); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/LineVehicleIntersection.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/LineVehicleIntersection.java index 53a69c08..013e280d 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/LineVehicleIntersection.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/LineVehicleIntersection.java @@ -2,8 +2,9 @@ import lombok.Getter; import lombok.Setter; -import us.dot.its.jpo.ode.model.OdeBsmData; -import java.util.List; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; + @Getter @Setter @@ -14,10 +15,10 @@ public class LineVehicleIntersection { /** * The BSM nearest to the stop/start point */ - private OdeBsmData bsm; + private ProcessedBsm bsm; - public LineVehicleIntersection(Lane lane, OdeBsmData bsm) { + public LineVehicleIntersection(Lane lane, ProcessedBsm bsm) { this.lane = lane; this.bsm = bsm; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/VehiclePath.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/VehiclePath.java index 89587144..fcb4ec18 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/VehiclePath.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/VehiclePath.java @@ -10,8 +10,6 @@ import org.locationtech.jts.geom.impl.PackedCoordinateSequence; import org.locationtech.jts.io.WKTWriter; import org.locationtech.jts.linearref.LengthIndexedLine; -import org.locationtech.jts.linearref.LinearLocation; -import org.locationtech.jts.linearref.LocationIndexedLine; import org.locationtech.jts.operation.buffer.BufferOp; import org.locationtech.jts.operation.buffer.BufferParameters; import org.slf4j.Logger; @@ -20,9 +18,8 @@ import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; import us.dot.its.jpo.conflictmonitor.monitor.utils.CircleMath; import us.dot.its.jpo.conflictmonitor.monitor.utils.CoordinateConversion; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; -import us.dot.its.jpo.ode.plugin.j2735.OdePosition3D; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; + @Getter @Setter @@ -37,8 +34,8 @@ public class VehiclePath { private Lane ingressLane; private Lane egressLane; - private OdeBsmData ingressBsm; - private OdeBsmData egressBsm; + private ProcessedBsm ingressBsm; + private ProcessedBsm egressBsm; private double minDistanceFeet; private double headingToleranceDegrees; @@ -63,12 +60,13 @@ public void buildVehiclePath(){ Coordinate[] vehicleCoords = new Coordinate[bsms.getBsms().size()]; int index =0; - for(OdeBsmData bsm : bsms.getBsms()){ + for(ProcessedBsm bsm : bsms.getBsms()){ - OdePosition3D position = ((J2735Bsm)bsm.getPayload().getData()).getCoreData().getPosition(); + CoordinateXY coords = BsmUtils.getPosition(bsm); + double[] shiftedPosition = CoordinateConversion.longLatToOffsetCM( - position.getLongitude().doubleValue(), - position.getLatitude().doubleValue(), + coords.getX(), + coords.getY(), referencePoint.getX(), referencePoint.getY() ); @@ -117,14 +115,14 @@ public LineVehicleIntersection findLineVehicleIntersection( final double minDistanceCM = CoordinateConversion.feetToCM(minDistanceFeet); double minDistance = Double.MAX_VALUE; - OdeBsmData matchingBsm = null; + ProcessedBsm matchingBsm = null; IntersectionLine bestLine = null; for(IntersectionLine line : lines){ if(this.pathPoints.isWithinDistance(line.getStopLinePoint(), minDistanceCM)){ int index =0; - for(OdeBsmData bsm : this.bsms.getBsms()){ + for(ProcessedBsm bsm : this.bsms.getBsms()){ Point p = this.pathPoints.getPointN(index); var optionalHeading = BsmUtils.getHeading(bsm); if (optionalHeading.isEmpty()) { @@ -160,7 +158,8 @@ public LineVehicleIntersection findLineVehicleIntersection( * @param upstreamSearchDistanceFeet - The upstream distance along the lane to search * @return List */ - public List findBsmsInIngressLane(Lane lane, final double upstreamSearchDistanceFeet) { + public List> + findBsmsInIngressLane(Lane lane, final double upstreamSearchDistanceFeet) { final double upstreamSearchDistanceCm = CoordinateConversion.feetToCM(upstreamSearchDistanceFeet); final double laneWidthCm = lane.getLaneWidthCm(); final double halfLaneWidthCm = laneWidthCm / 2.0; @@ -175,13 +174,11 @@ public List findBsmsInIngressLane(Lane lane, final double upstreamSe Geometry buffer = BufferOp.bufferOp(upstreamLine, halfLaneWidthCm, bufferParams); // Find the BSMs that are within the buffer - List bsmsInLane = new ArrayList<>(); + List> bsmsInLane = new ArrayList<>(); int index = 0; - for (OdeBsmData bsm : this.bsms.getBsms()) { + for (ProcessedBsm bsm : this.bsms.getBsms()) { Point p = this.pathPoints.getPointN(index); - - if (buffer.contains(p)) { bsmsInLane.add(bsm); } @@ -201,12 +198,15 @@ public List findBsmsInIngressLane(Lane lane, final double upstreamSe * @param stopSpeedThresholdMPH * @return */ - public List filterStoppedBsms(final List bsmList, final double stopSpeedThresholdMPH) { + public List> + filterStoppedBsms( + final List> bsmList, + final double stopSpeedThresholdMPH) { List stoppedBsmIndices = new ArrayList<>(); // Find indexes of all BSMs below the stop speed threshold for (int i = 0; i < bsmList.size(); i++) { - OdeBsmData bsm = bsmList.get(i); + ProcessedBsm bsm = bsmList.get(i); Optional optionalSpeed = BsmUtils.getSpeedMPH(bsm); if (optionalSpeed.isEmpty()) { @@ -220,7 +220,7 @@ public List filterStoppedBsms(final List bsmList, final } } - List filteredBsmList = new ArrayList<>(); + List> filteredBsmList = new ArrayList<>(); // Must be at least 2 BSMs to find stop and start timestamps if (stoppedBsmIndices.isEmpty() || stoppedBsmIndices.size() < 2) { diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmAggregator.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmAggregator.java index 1169f155..2b85ac1b 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmAggregator.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmAggregator.java @@ -1,7 +1,7 @@ package us.dot.its.jpo.conflictmonitor.monitor.models.bsm; import java.util.ArrayList; -import java.util.Collections; + import java.util.Comparator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -9,18 +9,18 @@ import lombok.Getter; import lombok.Setter; import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import us.dot.its.jpo.ode.model.OdeBsmData; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; public class BsmAggregator { - @Getter @Setter - private ArrayList bsms = new ArrayList(); + private ArrayList> bsms = new ArrayList<>(); - private Comparator bsmComparator = new Comparator() { + private Comparator> bsmComparator = new Comparator<>() { @Override - public int compare(OdeBsmData bsm1, OdeBsmData bsm2) { + public int compare(ProcessedBsm bsm1, ProcessedBsm bsm2) { long t1 = BsmTimestampExtractor.getBsmTimestamp(bsm1); long t2 = BsmTimestampExtractor.getBsmTimestamp(bsm2); if (t2 < t1) { @@ -34,21 +34,21 @@ public int compare(OdeBsmData bsm1, OdeBsmData bsm2) { }; - public BsmAggregator add(OdeBsmData newBsm) { + public BsmAggregator add(ProcessedBsm newBsm) { bsms.add(newBsm); return this; } public void sort(){ - Collections.sort(this.bsms, bsmComparator); + this.bsms.sort(bsmComparator); } - public BsmAggregator addWithoutDeletion(OdeBsmData newBsm){ + public BsmAggregator addWithoutDeletion(ProcessedBsm newBsm){ bsms.add(newBsm); return this; } - public BsmAggregator subtract(OdeBsmData newBsm){ + public BsmAggregator subtract(ProcessedBsm newBsm){ return this; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmRsuIdKey.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmRsuIdKey.java deleted file mode 100644 index fb1f6a9c..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmRsuIdKey.java +++ /dev/null @@ -1,51 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.bsm; - -import com.fasterxml.jackson.core.JsonProcessingException; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import us.dot.its.jpo.geojsonconverter.partitioner.RsuIdKey; - -// TODO Remove, use geojsonconverter RsuLogKey instead -@Deprecated(forRemoval = true) -@EqualsAndHashCode -@Getter -@Setter -public class BsmRsuIdKey implements RsuIdKey { - - private static final Logger logger = LoggerFactory.getLogger(BsmRsuIdKey.class); - - private String rsuId; - private String bsmId; - - public BsmRsuIdKey() {} - - public BsmRsuIdKey(String rsuId, String bsmId){ - this.rsuId = rsuId; - this.bsmId = bsmId; - } - - @Override - public String getRsuId() { - return this.rsuId; - } - - @Override - public String toString() { - var mapper = DateJsonMapper.getInstance(); - String json = ""; - try { - json = mapper.writeValueAsString(this); - } catch (JsonProcessingException e) { - logger.error("Error writing BsmIntersectionKey as JSON string", e); - } - return json; - } - - - - -} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java index 0d08b87e..6000f92a 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java @@ -46,13 +46,14 @@ import us.dot.its.jpo.geojsonconverter.partitioner.RsuIdPartitioner; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; + import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.intersection_event.IntersectionEventConstants.*; -// TODO Use ProcessedBsm + @Component(DEFAULT_INTERSECTION_EVENT_ALGORITHM) public class IntersectionEventTopology extends BaseStreamsTopology @@ -168,7 +169,7 @@ public StopLineStopParameters getStopLineStopParameters() { } @Override - public ReadOnlyWindowStore getBsmWindowStore() { + public ReadOnlyWindowStore> getBsmWindowStore() { return ((MessageIngestStreamsAlgorithm)messageIngestAlgorithm).getBsmWindowStore(streams); } @@ -232,7 +233,7 @@ public void setStopLineStopParameters(StopLineStopParameters stopsParams) { // TODO Use ProcessedBsm - private static BsmAggregator getBsmsByTimeVehicle(ReadOnlyWindowStore bsmWindowStore, + private static BsmAggregator getBsmsByTimeVehicle(ReadOnlyWindowStore> bsmWindowStore, Instant start, Instant end, BsmIntersectionIdKey key){ logger.info("getBsmsByTimeVehicle: Start: {}, End: {}, key: {}", start, end, key); final String rsuId = key.getRsuId(); @@ -246,19 +247,19 @@ private static BsmAggregator getBsmsByTimeVehicle(ReadOnlyWindowStore, OdeBsmData> bsmRange = bsmWindowStore.fetchAll(timeFrom, timeTo); + KeyValueIterator, ProcessedBsm> bsmRange = bsmWindowStore.fetchAll(timeFrom, timeTo); BsmAggregator agg = new BsmAggregator(); while(bsmRange.hasNext()){ - KeyValue, OdeBsmData> next = bsmRange.next(); + KeyValue, ProcessedBsm> next = bsmRange.next(); Windowed storedWindowedKey = next.key; BsmIntersectionIdKey storedKey = storedWindowedKey.key(); String storedVehicleId = storedKey.getBsmId(); String storedRsuId = storedKey.getRsuId(); int storedIntersectionId = storedKey.getIntersectionId(); int storedRegion = storedKey.getRegion(); - OdeBsmData storedBsm = next.value; + ProcessedBsm storedBsm = next.value; long ts = BsmTimestampExtractor.getBsmTimestamp(next.value); // Filter by timestamp and Vehicle ID. diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java index 65abab0a..1f8209f9 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java @@ -43,6 +43,7 @@ import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.message_ingest.MessageIngestConstants.DEFAULT_MESSAGE_INGEST_ALGORITHM; +// TODO Use ProcessedBsm @Component(DEFAULT_MESSAGE_INGEST_ALGORITHM) public class MessageIngestTopology extends BaseStreamsBuilder diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java index 71e9e558..932a2ee7 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java @@ -90,6 +90,15 @@ public static Optional getHeading(OdeBsmData bsm) { return Optional.of(vehicleHeading); } + public static Optional getHeading(ProcessedBsm processedBsm) { + Optional optProps = getProperties(processedBsm); + if (optProps.isEmpty()) return Optional.empty(); + BsmProperties coreData = optProps.get(); + if (coreData.getHeading() == null) return Optional.empty(); + double vehicleHeading = coreData.getHeading().doubleValue(); + return Optional.of(vehicleHeading); + } + public static Optional getJ2735Bsm(OdeBsmData bsm) { if (bsm == null) return Optional.empty(); if (bsm.getPayload() == null) return Optional.empty(); @@ -117,6 +126,16 @@ public static Optional getSpeedMPH(OdeBsmData bsm) { return Optional.of(speedMPH); } + public static Optional getSpeedMPH(ProcessedBsm processedBsm) { + Optional optProps = getProperties(processedBsm); + if (optProps.isEmpty()) return Optional.empty(); + BsmProperties props = optProps.get(); + if (props.getSpeed() == null) return Optional.empty(); + double speedMetersPerSecond = props.getSpeed().doubleValue(); + double speedMPH = speedMetersPerSecond * 2.23694; // convert m/s to mph + return Optional.of(speedMPH); + } + public static String getVehicleId(OdeBsmData bsm) { Optional optionalCoreData = getCoreData(bsm); if (optionalCoreData.isEmpty()) return ""; @@ -124,6 +143,13 @@ public static String getVehicleId(OdeBsmData bsm) { return coreData.getId(); } + public static String getVehicleId(ProcessedBsm processedBsm) { + Optional optProps = getProperties(processedBsm); + if (optProps.isEmpty()) return ""; + BsmProperties props = optProps.get(); + return props.getId(); + } + public static String getRsuIp(OdeBsmData bsm) { String ip = ""; if (bsm.getMetadata() != null && bsm.getMetadata() instanceof OdeBsmMetadata) { From 59edf25961b43574c51d7b6d6aa03ec9374eba2c Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Thu, 26 Dec 2024 18:41:19 -0700 Subject: [PATCH 06/25] Fix ConflictMonitorProperties --- .../ConflictMonitorProperties.java | 69 +++++++------------ ...ssageCountProgressionAlgorithmFactory.java | 1 + 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/ConflictMonitorProperties.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/ConflictMonitorProperties.java index b1370c13..2e95a03f 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/ConflictMonitorProperties.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/ConflictMonitorProperties.java @@ -59,8 +59,6 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.notification.NotificationParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.message_ingest.MessageIngestAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.message_ingest.MessageIngestParameters; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionAlgorithmFactory; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_message_count_progression.MapMessageCountProgressionAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_message_count_progression.MapMessageCountProgressionParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_message_count_progression.SpatMessageCountProgressionAlgorithmFactory; @@ -167,10 +165,6 @@ public class ConflictMonitorProperties implements EnvironmentAware { private String connectionOfTravelAssessmentAlgorithm; private ConnectionOfTravelAssessmentParameters connectionOfTravelAssessmentAlgorithmParameters; - private RepartitionAlgorithmFactory repartitionAlgorithmFactory; - private String repartitionAlgorithm; - private RepartitionParameters repartitionAlgorithmParameters; - private MapMessageCountProgressionAlgorithmFactory mapMessageCountProgressionAlgorithmFactory; private String mapMessageCountProgressionAlgorithm; private MapMessageCountProgressionParameters mapMessageCountProgressionAlgorithmParameters; @@ -216,6 +210,7 @@ public class ConflictMonitorProperties implements EnvironmentAware { private MessageIngestAlgorithmFactory messageIngestAlgorithmFactory; private MessageIngestParameters messageIngestParameters; + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setIntersectionEventAlgorithmFactory(IntersectionEventAlgorithmFactory intersectionEventAlgorithmFactory) { this.intersectionEventAlgorithmFactory = intersectionEventAlgorithmFactory; @@ -238,11 +233,13 @@ public void setSpatValidationParameters(SpatValidationParameters spatBroadcastRa this.spatValidationParameters = spatBroadcastRateParameters; } + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setMapValidationAlgorithmFactory(MapValidationAlgorithmFactory factory) { this.mapValidationAlgorithmFactory = factory; } + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setSpatValidationAlgorithmFactory(SpatValidationStreamsAlgorithmFactory factory) { this.spatValidationAlgorithmFactory = factory; @@ -265,7 +262,7 @@ public void setMapTimestampDeltaParameters(MapTimestampDeltaParameters mapTimest this.mapTimestampDeltaAlgorithm = mapTimestampDeltaParameters.getAlgorithm(); } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setMapTimestampDeltaAlgorithmFactory(MapTimestampDeltaAlgorithmFactory factory) { this.mapTimestampDeltaAlgorithmFactory = factory; @@ -278,6 +275,7 @@ public void setSpatTimestampDeltaParameters(SpatTimestampDeltaParameters spatTim this.spatTimestampDeltaAlgorithm = spatTimestampDeltaParameters.getAlgorithm(); } + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setSpatTimestampDeltaAlgorithmFactory(SpatTimestampDeltaAlgorithmFactory factory) { this.spatTimestampDeltaAlgorithmFactory = factory; @@ -285,7 +283,7 @@ public void setSpatTimestampDeltaAlgorithmFactory(SpatTimestampDeltaAlgorithmFac - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setLaneDirectionOfTravelAlgorithmFactory( LaneDirectionOfTravelAlgorithmFactory laneDirectionOfTravelAlgorithmFactory) { @@ -307,7 +305,7 @@ public void setLaneDirectionOfTravelParameters(LaneDirectionOfTravelParameters l } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setConnectionOfTravelAlgorithmFactory( ConnectionOfTravelAlgorithmFactory connectionOfTravelAlgorithmFactory) { @@ -329,7 +327,7 @@ public void setConnectionOfTravelParameters(ConnectionOfTravelParameters connect } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setSignalStateVehicleCrossesAlgorithmFactory( StopLinePassageAlgorithmFactory signalStateVehicleCrossesAlgorithmFactory) { @@ -352,7 +350,7 @@ public void setSignalStateVehicleCrossesParameters( } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setSignalStateVehicleStopsAlgorithmFactory( StopLineStopAlgorithmFactory signalStateVehicleStopsAlgorithmFactory) { @@ -374,7 +372,7 @@ public void setSignalStateVehicleStopsParameters(StopLineStopParameters signalSt } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setMapSpatMessageAssessmentAlgorithmFactory( MapSpatMessageAssessmentAlgorithmFactory mapSpatMessageAssessmentAlgorithmFactory) { @@ -396,7 +394,7 @@ public void setMapSpatMessageAssessmentParameters( - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setSpatTimeChangeDetailsAlgorithmFactory( SpatTimeChangeDetailsAlgorithmFactory spatTimeChangeDetailsAlgorithmFactory) { @@ -424,6 +422,7 @@ public void setSpatTimeChangeDetailsParameters(SpatTimeChangeDetailsParameters s this.spatTimeChangeDetailsParameters = spatTimeChangeDetailsParameters; } + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setSpatTransitionAlgorithmFactory(EventStateProgressionAlgorithmFactory spatTransitionAlgorithmFactory) { this.spatTransitionAlgorithmFactory = spatTransitionAlgorithmFactory; @@ -439,7 +438,7 @@ public void setSpatTransitionParameters(EventStateProgressionParameters spatTran this.spatTransitionParameters = spatTransitionParameters; } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setMapTimeChangeDetailsAlgorithmFactory( MapTimeChangeDetailsAlgorithmFactory mapTimeChangeDetailsAlgorithmFactory) { @@ -462,7 +461,7 @@ public void setMapTimeChangeDetailsParameters(MapTimeChangeDetailsParameters map - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setSignalStateEventAssessmentAlgorithmFactory( StopLinePassageAssessmentAlgorithmFactory signalStateEventAssessmentAlgorithmFactory) { @@ -484,6 +483,7 @@ public void setSignalStateEventAssessmentAlgorithmParameters( this.signalStateEventAssessmentAlgorithmParameters = signalStateEventAssessmentAlgorithmParameters; } + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setStopLineStopAssessmentAlgorithmFactory( StopLineStopAssessmentAlgorithmFactory stopLineStopAssessmentAlgorithmFactory) { @@ -506,7 +506,7 @@ public void setStopLineStopAssessmentAlgorithmParameters( } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setLaneDirectionOfTravelAssessmentAlgorithmFactory( LaneDirectionOfTravelAssessmentAlgorithmFactory laneDirectionfOfTravelAssessmentAlgorithmFactory) { @@ -529,7 +529,7 @@ public void setLaneDirectionOfTravelAssessmentAlgorithmParameters( } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setConnectionOfTravelAssessmentAlgorithmFactory( ConnectionOfTravelAssessmentAlgorithmFactory connectionOfTravelAssessmentAlgorithmFactory) { @@ -551,28 +551,7 @@ public void setConnectionOfTravelAssessmentAlgorithmParameters( this.connectionOfTravelAssessmentAlgorithmParameters = connectionOfTravelAssessmentAlgorithmParameters; } - - - @Autowired - public void setRepartitionAlgorithmFactory(RepartitionAlgorithmFactory repartitionAlgorithmFactory) { - this.repartitionAlgorithmFactory = repartitionAlgorithmFactory; - } - - - - @Value("${repartition.algorithm}") - public void setRepartitionAlgorithm(String repartitionAlgorithm) { - this.repartitionAlgorithm = repartitionAlgorithm; - } - - - - @Autowired - public void setRepartitionAlgorithmParameters(RepartitionParameters repartitionAlgorithmParameters) { - this.repartitionAlgorithmParameters = repartitionAlgorithmParameters; - } - - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setMapMessageCountProgressionAlgorithmFactory(MapMessageCountProgressionAlgorithmFactory mapMessageCountProgressionAlgorithmFactory) { this.mapMessageCountProgressionAlgorithmFactory = mapMessageCountProgressionAlgorithmFactory; @@ -589,7 +568,7 @@ public void setMapMessageCountProgressionAlgorithmParameters(MapMessageCountProg } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setSpatMessageCountProgressionAlgorithmFactory(SpatMessageCountProgressionAlgorithmFactory spatMessageCountProgressionAlgorithmFactory) { this.spatMessageCountProgressionAlgorithmFactory = spatMessageCountProgressionAlgorithmFactory; @@ -605,7 +584,7 @@ public void setSpatMessageCountProgressionAlgorithmParameters(SpatMessageCountPr this.spatMessageCountProgressionAlgorithmParameters = spatMessageCountProgressionAlgorithmParameters; } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setBsmMessageCountProgressionAlgorithmFactory(BsmMessageCountProgressionAlgorithmFactory bsmMessageCountProgressionAlgorithmFactory) { this.bsmMessageCountProgressionAlgorithmFactory = bsmMessageCountProgressionAlgorithmFactory; @@ -626,9 +605,9 @@ public NotificationAlgorithmFactory getNotificationAlgorithmFactory() { return notificationAlgorithmFactory; } - - + + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setNotificationAlgorithmFactory(NotificationAlgorithmFactory notificationAlgorithmFactory) { this.notificationAlgorithmFactory = notificationAlgorithmFactory; @@ -658,6 +637,7 @@ public void setEventParameters(EventParameters eventParameters) { this.eventAlgorithm = eventParameters.getAlgorithm(); } + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setEventAlgorithmFactory(EventAlgorithmFactory factory) { this.eventAlgorithmFactory = factory; @@ -667,7 +647,7 @@ public Boolean getConfluentCloudStatus() { return confluentCloudEnabled; } - + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setBsmEventAlgorithmFactory(BsmEventAlgorithmFactory bsmEventAlgorithmFactory) { this.bsmEventAlgorithmFactory = bsmEventAlgorithmFactory; @@ -678,6 +658,7 @@ public void setBsmEventParameters(BsmEventParameters bsmEventParameters) { this.bsmEventParameters = bsmEventParameters; } + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") @Autowired public void setMessageIngestAlgorithmFactory(MessageIngestAlgorithmFactory messageIngestAlgorithmFactory) { this.messageIngestAlgorithmFactory = messageIngestAlgorithmFactory; diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_message_count_progression/MapMessageCountProgressionAlgorithmFactory.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_message_count_progression/MapMessageCountProgressionAlgorithmFactory.java index be263ce1..45791129 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_message_count_progression/MapMessageCountProgressionAlgorithmFactory.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_message_count_progression/MapMessageCountProgressionAlgorithmFactory.java @@ -1,5 +1,6 @@ package us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_message_count_progression; + public interface MapMessageCountProgressionAlgorithmFactory { MapMessageCountProgressionAlgorithm getAlgorithm(String algorithmName); } From 56e39cdceef35a84ddae628e3c9bb7ac62f07644 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Thu, 26 Dec 2024 19:02:43 -0700 Subject: [PATCH 07/25] Fixing tests --- .../monitor/AppHealthMonitor.java | 16 ++++++------ .../monitor/serialization/JsonSerdes.java | 9 ------- .../topologies/MessageIngestTopology.java | 4 ++- .../monitor/MonitorServiceControllerTest.java | 16 +++--------- .../topologies/BsmEventTopologyTest.java | 26 ++++++++++++------- 5 files changed, 30 insertions(+), 41 deletions(-) diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/AppHealthMonitor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/AppHealthMonitor.java index 2af701b1..a46e5c0d 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/AppHealthMonitor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/AppHealthMonitor.java @@ -27,7 +27,6 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -49,9 +48,10 @@ import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; import javax.ws.rs.Produces; @@ -360,22 +360,22 @@ private void addLinks(Map map, String... paths) { Instant startTime = key.window().startTime(); Instant endTime = key.window().endTime(); BsmIntersectionIdKey theKey= key.key(); - OdeBsmData value = kvp.value; + ProcessedBsm value = kvp.value; // Integer intersectionId = value.(); String vehicleId = BsmUtils.getVehicleId(value); - TreeMap> bsms = null; + TreeMap>> bsms = null; if (intersectionMap.containsKey(vehicleId)) { bsms = intersectionMap.get(vehicleId); } else { - bsms = new TreeMap>(); + bsms = new TreeMap<>(); intersectionMap.put(vehicleId, bsms); } String window = String.format("%s / %s", formatter.format(startTime.atZone(ZoneOffset.UTC)), formatter.format(endTime.atZone(ZoneOffset.UTC))); - TreeMap bsmList = null; + TreeMap> bsmList = null; if (bsms.containsKey(window)) { bsmList = bsms.get(window); } else { - bsmList = new TreeMap(); + bsmList = new TreeMap<>(); bsms.put(window, bsmList); } bsmList.put(theKey.toString(), value); @@ -458,7 +458,7 @@ private String baseUrl() { } public class IntersectionSpatMap extends TreeMap>> {} - public class IntersectionBsm extends TreeMap>> {} + public class IntersectionBsm extends TreeMap>>> {} public record TopologyInfoLinks(String detailsUrl, String simpleGraphUrl) {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/JsonSerdes.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/JsonSerdes.java index 80bf307f..0f3a0784 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/JsonSerdes.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/JsonSerdes.java @@ -17,7 +17,6 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmAggregator; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmIntersectionIdKey; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; import us.dot.its.jpo.conflictmonitor.monitor.models.config.DefaultConfig; import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfig; import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfigKey; @@ -239,14 +238,6 @@ public static Serde ConnectionOfTravelAggregator() new JsonDeserializer<>(ConnectionOfTravelAggregator.class)); } - public static Serde BsmRsuIdKey() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(BsmRsuIdKey.class)); - } - - - public static Serde BsmIntersectionIdKey() { return Serdes.serdeFrom( new JsonSerializer(), diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java index 1f8209f9..e4e8d51a 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java @@ -35,6 +35,8 @@ import us.dot.its.jpo.geojsonconverter.partitioner.IntersectionIdPartitioner; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; import us.dot.its.jpo.ode.model.OdeBsmData; @@ -236,7 +238,7 @@ protected Logger getLogger() { @Override - public ReadOnlyWindowStore getBsmWindowStore(KafkaStreams streams) { + public ReadOnlyWindowStore> getBsmWindowStore(KafkaStreams streams) { return streams.store(StoreQueryParameters.fromNameAndType( parameters.getBsmStoreName(), QueryableStoreTypes.windowStore())); } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/MonitorServiceControllerTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/MonitorServiceControllerTest.java index 8a81b1a3..5ecff11c 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/MonitorServiceControllerTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/MonitorServiceControllerTest.java @@ -44,9 +44,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.notification.NotificationAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.notification.NotificationParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.notification.NotificationStreamsAlgorithm; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionAlgorithmFactory; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionParameters; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.repartition.RepartitionStreamsAlgorithm; + import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event_state_progression.EventStateProgressionAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event_state_progression.EventStateProgressionParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event_state_progression.EventStateProgressionStreamsAlgorithm; @@ -106,9 +104,7 @@ public class MonitorServiceControllerTest { ConfigInitializer configInitializer; - @Mock RepartitionAlgorithmFactory repartitionAlgorithmFactory; - @Mock RepartitionStreamsAlgorithm repartitionAlgorithm; - RepartitionParameters repartitionParameters = new RepartitionParameters(); + @Mock NotificationAlgorithmFactory notificationAlgorithmFactory; @Mock NotificationStreamsAlgorithm notificationAlgorithm; @@ -216,12 +212,7 @@ public class MonitorServiceControllerTest { public void testConstructor() { final String defaultAlgo = "default"; - - when(conflictMonitorProperties.getRepartitionAlgorithmFactory()).thenReturn(repartitionAlgorithmFactory); - when(conflictMonitorProperties.getRepartitionAlgorithm()).thenReturn(defaultAlgo); - when(repartitionAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(repartitionAlgorithm); - when(conflictMonitorProperties.getRepartitionAlgorithmParameters()).thenReturn(repartitionParameters); - + when(conflictMonitorProperties.getNotificationAlgorithmFactory()).thenReturn(notificationAlgorithmFactory); when(conflictMonitorProperties.getNotificationAlgorithm()).thenReturn(defaultAlgo); when(notificationAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(notificationAlgorithm); @@ -347,7 +338,6 @@ public void testConstructor() { assertThat(monitorServiceController, notNullValue()); // Check all algorithms were started - verify(repartitionAlgorithm, times(1)).start(); verify(mapValidationAlgorithm, times(1)).start(); verify(spatValidationAlgorithm, times(1)).start(); verify(spatTimeChangeDetailsAlgorithm, times(1)).start(); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java index 131a2699..6cc06e41 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java @@ -11,12 +11,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_event.BsmEventParameters; +import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmIntersectionIdKey; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; + import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmTimestampExtractor; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapIndex; import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; import us.dot.its.jpo.conflictmonitor.testutils.TopologyTestUtils; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; +import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; +import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; import us.dot.its.jpo.ode.model.OdeBsmData; import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; @@ -60,25 +66,25 @@ public void testBsmEventTopology() { Topology topology = bsmEventTopology.buildTopology(); try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig)) { - + var inputTopic = driver.createInputTopic(inputTopicName, - JsonSerdes.BsmRsuIdKey().serializer(), - JsonSerdes.OdeBsm().serializer()); + new JsonSerializer(), + new JsonSerializer>()); var outputTopic = driver.createOutputTopic(outputTopicName, - JsonSerdes.BsmIntersectionIdKey().deserializer(), - JsonSerdes.BsmEvent().deserializer() - ); - + new JsonDeserializer<>(BsmIntersectionIdKey.class), + new JsonDeserializer<>(BsmEvent.class)); final Instant startTime = Instant.ofEpochMilli(1674356320000L); final int periodMillis = 100; final int totalTimeSeconds = 1; List instants = TopologyTestUtils.getInstantsExclusive(startTime, periodMillis, totalTimeSeconds); - final BsmRsuIdKey id1 = new BsmRsuIdKey(rsuId, "BSMID1"); + final RsuLogKey id1 = new RsuLogKey(); + id1.setRsuId(rsuId); + id1.setBsmId("BSMID1"); for (var currentInstant : instants) { logger.info("Send BSM at {}", currentInstant); - OdeBsmData bsm = bsmAtInstant(currentInstant, id1.getBsmId()); + ProcessedBsm bsm = bsmAtInstant(currentInstant, id1.getBsmId()); inputTopic.pipeInput(id1, bsm, currentInstant); } From 04fa8493dd26abd1c2be3853ea8bb592cda51c21 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Fri, 27 Dec 2024 00:18:37 -0700 Subject: [PATCH 08/25] Update unit tests --- .../ConflictMonitorPropertiesTest.java | 3 - .../models/intersection/VehiclePathTest.java | 8 +- .../BsmEventProcessor_validateBSMTest.java | 88 ++++----------- .../topologies/BsmEventTopologyTest.java | 18 ++- .../IntersectionEventTopologyTest.java | 46 +++++--- .../topologies/MessageIngestTopologyTest.java | 104 ++++++++++++++---- .../testutils/BsmTestUtils.java | 40 ++++++- 7 files changed, 187 insertions(+), 120 deletions(-) diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/ConflictMonitorPropertiesTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/ConflictMonitorPropertiesTest.java index fb8da46f..866b68a2 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/ConflictMonitorPropertiesTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/ConflictMonitorPropertiesTest.java @@ -130,9 +130,6 @@ public void testGetProperties() { assertThat(properties.getConnectionOfTravelAssessmentAlgorithmFactory(), notNullValue()); assertThat(properties.getConnectionOfTravelAssessmentAlgorithm(), notNullValue()); assertThat(properties.getConnectionOfTravelAssessmentAlgorithmParameters(), notNullValue()); - assertThat(properties.getRepartitionAlgorithmFactory(), notNullValue()); - assertThat(properties.getRepartitionAlgorithm(), notNullValue()); - assertThat(properties.getRepartitionAlgorithmParameters(), notNullValue()); assertThat(properties.getIntersectionEventAlgorithmFactory(), notNullValue()); assertThat(properties.getIntersectionEventAlgorithm(), notNullValue()); assertThat(properties.getKafkaStateChangeEventTopic(), notNullValue()); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/models/intersection/VehiclePathTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/models/intersection/VehiclePathTest.java index ad6fc35d..9a475506 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/models/intersection/VehiclePathTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/models/intersection/VehiclePathTest.java @@ -1,10 +1,8 @@ package us.dot.its.jpo.conflictmonitor.monitor.models.intersection; import org.junit.Test; -import org.locationtech.jts.geom.CoordinateSequence; import org.locationtech.jts.geom.CoordinateXY; import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.Point; import us.dot.its.jpo.conflictmonitor.monitor.models.Intersection.Intersection; import us.dot.its.jpo.conflictmonitor.monitor.models.Intersection.IntersectionLine; import us.dot.its.jpo.conflictmonitor.monitor.models.Intersection.VehiclePath; @@ -12,9 +10,7 @@ import us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils; import java.time.Instant; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; public class VehiclePathTest { @@ -69,8 +65,8 @@ public void testBuildVehiclePath() { private BsmAggregator getBsms() { - final var startBsm = BsmTestUtils.bsmWithPosition(Instant.ofEpochMilli(startMillis), bsmId, startLon, startLat, elevation); - final var endBsm = BsmTestUtils.bsmWithPosition(Instant.ofEpochMilli(endMillis), bsmId, endLon, endLat, elevation); + final var startBsm = BsmTestUtils.processedBsmWithPosition(Instant.ofEpochMilli(startMillis), bsmId, startLon, startLat, elevation); + final var endBsm = BsmTestUtils.processedBsmWithPosition(Instant.ofEpochMilli(endMillis), bsmId, endLon, endLat, elevation); var bsmAggregator = new BsmAggregator(); bsmAggregator.add(startBsm); bsmAggregator.add(endBsm); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java index 853a5257..390d0d63 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java @@ -1,21 +1,20 @@ package us.dot.its.jpo.conflictmonitor.monitor.processors; -import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.ode.model.*; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; -import us.dot.its.jpo.ode.plugin.j2735.J2735BsmCoreData; -import us.dot.its.jpo.ode.plugin.j2735.OdePosition3D; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils.validBsm; +import static us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils.validProcessedBsm; /** * Unit tests for {@link BsmEventProcessor#validateBSM} @@ -26,15 +25,15 @@ public class BsmEventProcessor_validateBSMTest { @Test public void testValidateBSM() { var processor = new BsmEventProcessor(); - var actual = processor.validateBSM(bsm); + var actual = BsmEventProcessor.validateBSM(bsm); assertThat(description, actual, equalTo(expected)); } private final String description; - private final OdeBsmData bsm; + private final ProcessedBsm bsm; private final boolean expected; - public BsmEventProcessor_validateBSMTest(String description, OdeBsmData bsm, boolean expected) { + public BsmEventProcessor_validateBSMTest(String description, ProcessedBsm bsm, boolean expected) { this.description = description; this.bsm = bsm; this.expected = expected; @@ -47,84 +46,43 @@ public static Collection getParams() { bsms.add(new Object[] {"null BSM", null, false}); - final var emptyBsm = new OdeBsmData(); + final var emptyBsm = new ProcessedBsm(null); bsms.add(new Object[] {"empty BSM", emptyBsm, false}); - final var emptyPayload = new OdeBsmPayload(); - final var emptyMetadata = new OdeBsmMetadata(); - - final var bsmWithInvalidPayload = new OdeBsmData(); - bsmWithInvalidPayload.setPayload(new OdeMsgPayload()); - bsmWithInvalidPayload.setMetadata(emptyMetadata); - bsms.add(new Object[] {"BSM with invalid payload class", bsmWithInvalidPayload, false}); - - final var bsmWithInvalidMetadata = new OdeBsmData(); - bsmWithInvalidMetadata.setPayload(emptyPayload); - bsmWithInvalidMetadata.setMetadata(new OdeMsgMetadata()); - bsms.add(new Object[] {"BSM with invalid metadata class", bsmWithInvalidMetadata, false}); - - final var bsmWithInvalidData = new OdeBsmData(); - final var invalidPayload = new OdeBsmPayload(); - invalidPayload.setData(new OdeObject()); - bsmWithInvalidData.setPayload(invalidPayload); - bsmWithInvalidData.setMetadata(emptyMetadata); - bsms.add(new Object[] {"BSM with invalid data class", bsmWithInvalidData, false}); final OdeBsmData validBsm = validBsm(); bsms.add(new Object[] {"Valid BSM", validBsm, true}); - final var bsmWithNullId = validBsm(); - ((J2735Bsm)bsmWithNullId.getPayload().getData()).getCoreData().setId(null); + final var bsmWithNullId = validProcessedBsm(); + bsmWithNullId.getFeatures()[0].getProperties().setId(null); bsms.add(new Object[] {"BSM with null id", bsmWithNullId, false}); - final var bsmWithNullSecMark = validBsm(); - ((J2735Bsm)bsmWithNullSecMark.getPayload().getData()).getCoreData().setSecMark(null); + final var bsmWithNullSecMark = validProcessedBsm(); + bsmWithNullSecMark.getFeatures()[0].getProperties().setSecMark(null); bsms.add(new Object[] {"BSM with null secMark", bsmWithNullSecMark, false}); - final var bsmWithNullSpeed = validBsm(); - ((J2735Bsm)bsmWithNullSpeed.getPayload().getData()).getCoreData().setSpeed(null); + final var bsmWithNullSpeed = validProcessedBsm(); + bsmWithNullSpeed.getFeatures()[0].getProperties().setSpeed(null); bsms.add(new Object[] {"BSM with null speed", bsmWithNullSpeed, false}); - final var bsmWithNullHeading = validBsm(); - ((J2735Bsm)bsmWithNullHeading.getPayload().getData()).getCoreData().setHeading(null); + final var bsmWithNullHeading = validProcessedBsm(); + bsmWithNullHeading.getFeatures()[0].getProperties().setHeading(null); bsms.add(new Object[] {"BSM with null heading", bsmWithNullHeading, false}); - final var bsmWithNullSource = validBsm(); - ((OdeBsmMetadata)bsmWithNullSource.getMetadata()).setBsmSource(null); + final var bsmWithNullSource = validProcessedBsm(); + bsmWithNullSource.setOriginIp(null); + bsmWithNullSource.setLogName(null); bsms.add(new Object[] {"BSM with null source", bsmWithNullSource, false}); - final var bsmWithNullOriginIp = validBsm(); - ((OdeBsmMetadata)bsmWithNullOriginIp.getMetadata()).setOriginIp(null); - bsms.add(new Object[] {"BSM with null originIp", bsmWithNullOriginIp, false}); - final var bsmWithNullRecordGeneratedAt = validBsm(); - bsmWithNullRecordGeneratedAt.getMetadata().setRecordGeneratedAt(null); + final var bsmWithNullRecordGeneratedAt = validProcessedBsm(); + bsmWithNullRecordGeneratedAt.setTimeStamp(null); bsms.add(new Object[] {"BSM with null recordGeneratedAt", bsmWithNullRecordGeneratedAt, false}); - final var bsmWithNullOdeReceivedAt = validBsm(); - bsmWithNullOdeReceivedAt.getMetadata().setOdeReceivedAt(null); + final var bsmWithNullOdeReceivedAt = validProcessedBsm(); + bsmWithNullOdeReceivedAt.setOdeReceivedAt(null); bsms.add(new Object[] {"BSM with null odeReceivedAt", bsmWithNullOdeReceivedAt, false}); - final var bsmWithNullLatitude = validBsm(); - ((J2735Bsm)bsmWithNullLatitude.getPayload().getData()).getCoreData().getPosition().setLatitude(null); - bsms.add(new Object[] {"BSM with null latitude", bsmWithNullLatitude, false}); - - final var bsmWithNullLongitude = validBsm(); - ((J2735Bsm)bsmWithNullLongitude.getPayload().getData()).getCoreData().getPosition().setLongitude(null); - bsms.add(new Object[] {"BSM with null longitude", bsmWithNullLongitude, false}); - - final var bsmWithNullMetadata = validBsm(); - bsmWithNullMetadata.setMetadata(null); - bsms.add(new Object[] {"BSM with null metadata", bsmWithNullMetadata, false}); - - final var bsmWithNullPayloadData = validBsm(); - bsmWithNullPayloadData.getPayload().setData(null); - bsms.add(new Object[] {"BSM with null payload data", bsmWithNullPayloadData, false}); - - final var bsmWithNullCoreData = validBsm(); - ((J2735Bsm)bsmWithNullCoreData.getPayload().getData()).setCoreData(null); - bsms.add(new Object[] {"BSM with null core data", bsmWithNullCoreData, false}); - return bsms; } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java index 6cc06e41..eb4d3d08 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java @@ -19,6 +19,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; import us.dot.its.jpo.conflictmonitor.testutils.TopologyTestUtils; import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; +import us.dot.its.jpo.geojsonconverter.pojos.ProcessedValidationMessage; import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; @@ -32,6 +33,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils.bsmAtInstant; +import static us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils.processedBsmAtInstant; public class BsmEventTopologyTest { @@ -84,24 +86,28 @@ public void testBsmEventTopology() { id1.setBsmId("BSMID1"); for (var currentInstant : instants) { logger.info("Send BSM at {}", currentInstant); - ProcessedBsm bsm = bsmAtInstant(currentInstant, id1.getBsmId()); + ProcessedBsm bsm = processedBsmAtInstant(currentInstant, id1.getBsmId()); inputTopic.pipeInput(id1, bsm, currentInstant); } // Simulate a long enough period of no BSMs followed by a different BSM ID to advance stream time final Instant newBsm = startTime.plusSeconds(15); - final BsmRsuIdKey id2 = new BsmRsuIdKey(rsuId, "BSMID2"); - OdeBsmData gapBsm = bsmAtInstant(newBsm, id2.getBsmId()); + final RsuLogKey id2 = new RsuLogKey(); + id2.setRsuId(rsuId); + id2.setBsmId("BSMID2"); + ProcessedBsm gapBsm = processedBsmAtInstant(newBsm, id2.getBsmId()); inputTopic.pipeInput(id2, gapBsm, newBsm); // Include an invalid BSM for validation coverage - OdeBsmData invalidBsm = bsmAtInstant(startTime, id2.getBsmId()); - ((J2735Bsm)invalidBsm.getPayload().getData()).getCoreData().setPosition(null); + ProcessedBsm invalidBsm = processedBsmAtInstant(startTime, id2.getBsmId()); + var validationMessage = new ProcessedValidationMessage(); + validationMessage.setMessage("Invalid BSM"); + invalidBsm.setValidationMessages(List.of(validationMessage)); inputTopic.pipeInput(id2, invalidBsm, startTime); // Include a BSM with an earlier timestamp than the previous BSM for validation coverage final Instant oldTime = startTime.minusSeconds(100); - OdeBsmData oldBsm = bsmAtInstant(oldTime, id2.getBsmId()); + ProcessedBsm oldBsm = processedBsmAtInstant(oldTime, id2.getBsmId()); inputTopic.pipeInput(id2, oldBsm, oldTime); var output = outputTopic.readKeyValuesToList(); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopologyTest.java index 7a3bd12f..c58ccb92 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopologyTest.java @@ -1,6 +1,6 @@ package us.dot.its.jpo.conflictmonitor.monitor.topologies; -import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.streams.KafkaStreams; import org.apache.kafka.streams.KeyValue; import org.apache.kafka.streams.Topology; @@ -25,22 +25,26 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_stop.StopLineStopAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_stop.StopLineStopParameters; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmEvent; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; -import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; + +import us.dot.its.jpo.conflictmonitor.monitor.models.events.ConnectionOfTravelEvent; import us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils; import us.dot.its.jpo.conflictmonitor.testutils.SpatTestUtils; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; +import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; +import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; + import java.time.Instant; import java.util.Properties; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.notNullValue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -56,8 +60,8 @@ public class IntersectionEventTopologyTest { Properties streamsProperties = new Properties(); - @Mock ReadOnlyWindowStore bsmWindowStore; - @Mock KeyValueIterator, OdeBsmData> bsmWindowStoreIterator; + @Mock ReadOnlyWindowStore> bsmWindowStore; + @Mock KeyValueIterator, ProcessedBsm> bsmWindowStoreIterator; @Mock ReadOnlyWindowStore spatWindowStore; @Mock KeyValueIterator, ProcessedSpat> spatWindowStoreIterator; @Mock ReadOnlyKeyValueStore> mapStore; @@ -78,7 +82,12 @@ public class IntersectionEventTopologyTest { final long startMillis = 1682615309868L; final long endMillis = 1682615347488L; - final BsmRsuIdKey bsmId = new BsmRsuIdKey("127.0.0.1", "A0A0A0"); + final RsuLogKey bsmId = new RsuLogKey(); + + public IntersectionEventTopologyTest() { + bsmId.setRsuId("127.0.0.1"); + bsmId.setBsmId("A0A0A0"); + } @Test public void testIntersectionEventTopology() { @@ -86,14 +95,17 @@ public void testIntersectionEventTopology() { // Return builder inputs unchanged for embedded topologies //when(messageIngestAlgorithm.buildTopology(any())).thenAnswer(i -> i.getArguments()[0]); - final var startBsm = BsmTestUtils.bsmAtInstant(Instant.ofEpochMilli(startMillis), bsmId.getBsmId()); - final var endBsm = BsmTestUtils.bsmAtInstant(Instant.ofEpochMilli(endMillis), bsmId.getBsmId()); - final KeyValue, OdeBsmData> kvStartBsm = new KeyValue<>(new Windowed<>(bsmId.getBsmId(), new TimeWindow(startMillis, startMillis + 30000)), startBsm); - final KeyValue, OdeBsmData> kvEndBsm = new KeyValue<>(new Windowed<>(bsmId.getBsmId(), new TimeWindow(startMillis, startMillis + 30000)), endBsm); + final var startBsm = BsmTestUtils.processedBsmAtInstant(Instant.ofEpochMilli(startMillis), bsmId.getBsmId()); + final var endBsm = BsmTestUtils.processedBsmAtInstant(Instant.ofEpochMilli(endMillis), bsmId.getBsmId()); + final KeyValue, ProcessedBsm> kvStartBsm + = new KeyValue<>(new Windowed<>(bsmId.getBsmId(), new TimeWindow(startMillis, startMillis + 30000)), startBsm); + final KeyValue, ProcessedBsm> kvEndBsm + = new KeyValue<>(new Windowed<>(bsmId.getBsmId(), new TimeWindow(startMillis, startMillis + 30000)), endBsm); final int intersectionId = 1; final ProcessedSpat spat = SpatTestUtils.validSpat(intersectionId); - final KeyValue, ProcessedSpat> kvSpat = new KeyValue<>(new Windowed<>("1", new TimeWindow(startMillis, startMillis + 30000)), spat); + final KeyValue, ProcessedSpat> kvSpat + = new KeyValue<>(new Windowed<>("1", new TimeWindow(startMillis, startMillis + 30000)), spat); var conflictMonitorProperties = new ConflictMonitorProperties(); conflictMonitorProperties.setKafkaTopicCmBsmEvent(bsmEventTopic); @@ -135,12 +147,12 @@ public void testIntersectionEventTopology() { var bsmInputTopic = driver.createInputTopic( bsmEventTopic, - JsonSerdes.BsmRsuIdKey().serializer(), - JsonSerdes.BsmEvent().serializer()); + new JsonSerializer(), + new JsonSerializer()); var connectionOfTravelOutputTopic = driver.createOutputTopic( connectionOfTravelTopic, - Serdes.String().deserializer(), - JsonSerdes.ConnectionOfTravelEvent().deserializer()); + new StringDeserializer(), + new JsonDeserializer<>(ConnectionOfTravelEvent.class)); BsmEvent event = new BsmEvent(); event.setStartingBsm(startBsm); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopologyTest.java index df36bba3..22999544 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopologyTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JavaType; -import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.streams.StreamsBuilder; import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.TopologyTestDriver; @@ -10,15 +10,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.message_ingest.MessageIngestParameters; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapIndex; -import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; import us.dot.its.jpo.geojsonconverter.DateJsonMapper; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; +import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; +import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; import java.util.Properties; @@ -70,26 +72,26 @@ public void testMessageIngestTopology() throws JsonProcessingException { try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig)) { var bsmTopic = driver.createInputTopic(bsmTopicName, - JsonSerdes.BsmRsuIdKey().serializer(), - JsonSerdes.OdeBsm().serializer()); + new JsonSerializer(), + new JsonSerializer>()); var spatTopic = driver.createInputTopic(spatTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().serializer(), - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedSpat().serializer()); + new JsonSerializer(), + new JsonSerializer()); var mapTopic = driver.createInputTopic(mapTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().serializer(), - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedMapGeoJson().serializer()); + new JsonSerializer(), + new JsonSerializer>()); var mapBoundingBoxTopic = driver.createOutputTopic(mapBoundingBoxTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().deserializer(), - Serdes.String().deserializer()); + new JsonDeserializer<>(RsuIntersectionKey.class), + new StringDeserializer()); final var rsuKey = new RsuIntersectionKey(rsuId, intersectionId); final var processedMap = getProcessedMap(); mapTopic.pipeInput(rsuKey, processedMap); spatTopic.pipeInput(rsuKey, getProcessedSpat()); - final var bsmKey = new BsmRsuIdKey(); + final var bsmKey = new RsuLogKey(); bsmKey.setBsmId("48C45782"); bsmTopic.pipeInput(bsmKey, getBsm()); @@ -131,26 +133,84 @@ MessageIngestParameters getParamters() { ProcessedMap getProcessedMap() throws JsonProcessingException { var mapper = DateJsonMapper.getInstance(); JavaType javaType = mapper.getTypeFactory().constructParametricType(ProcessedMap.class, LineString.class); - return mapper.readValue(MAP, javaType); + return mapper.readValue(ProcessedMap, javaType); } ProcessedSpat getProcessedSpat() throws JsonProcessingException { var mapper = DateJsonMapper.getInstance(); - return mapper.readValue(SPAT, ProcessedSpat.class); + return mapper.readValue(ProcessedSpat, ProcessedSpat.class); } - OdeBsmData getBsm() throws JsonProcessingException { + ProcessedBsm getBsm() throws JsonProcessingException { var mapper = DateJsonMapper.getInstance(); - return mapper.readValue(BSM, OdeBsmData.class); + final JavaType bsmGeoJsonType = mapper.getTypeFactory().constructParametricType(ProcessedBsm.class, Point.class); + return mapper.readValue(BSM, bsmGeoJsonType); } - final String MAP = "{\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2023-05-03T16:25:03.519Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits\",\"schemaPath\":\"#/$defs/J2735SpeedLimitList_Wrapper/type\"}],\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2023-05-03T16:25:03.519Z\"},\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0906245,39.5876246],[-105.0905203,39.587281],[-105.0904383,39.5870554],[-105.0903588,39.5868383],[-105.0902622,39.5865865],[-105.0901249,39.5862612],[-105.0900451,39.5860819],[-105.0899283,39.5858283],[-105.0898739,39.5857117],[-105.0895814,39.5851569],[-105.0888764,39.5839527]]},\"properties\":{\"nodes\":[{\"delta\":[1511,-1514]},{\"delta\":[723,-3116],\"delevation\":10},{\"delta\":[892,-3818],\"delevation\":20},{\"delta\":[702,-2507],\"delevation\":20},{\"delta\":[681,-2412],\"delevation\":10},{\"delta\":[827,-2798],\"delevation\":10},{\"delta\":[1176,-3614],\"delevation\":20},{\"delta\":[683,-1992]},{\"delta\":[1000,-2818],\"delevation\":10},{\"delta\":[466,-1295],\"delevation\":20},{\"delta\":[2505,-6164],\"delevation\":20},{\"delta\":[6037,-13380],\"delevation\":70}],\"laneId\":1,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.090652,39.5875596],[-105.090534,39.5871793],[-105.0903457,39.5866864],[-105.0902123,39.5863581],[-105.0900802,39.5860572],[-105.0898164,39.5855019],[-105.0895409,39.5849856],[-105.088922,39.5839259]]},\"properties\":{\"nodes\":[{\"delta\":[1192,-1619]},{\"delta\":[807,-3733],\"delevation\":30},{\"delta\":[1010,-4226],\"delevation\":10},{\"delta\":[1612,-5477],\"delevation\":30},{\"delta\":[1142,-3648],\"delevation\":20},{\"delta\":[1131,-3343],\"delevation\":10},{\"delta\":[2259,-6170],\"delevation\":30},{\"delta\":[2359,-5737],\"delevation\":30},{\"delta\":[5300,-11774],\"delevation\":50}],\"laneId\":2,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.090747,39.5877247],[-105.0906498,39.5874141],[-105.0906262,39.5873356],[-105.0905865,39.5872922]]},\"properties\":{\"nodes\":[{\"delta\":[805,-1704],\"delevation\":10},{\"delta\":[380,-1813]},{\"delta\":[832,-3451],\"delevation\":30},{\"delta\":[202,-872]},{\"delta\":[340,-482],\"delevation\":-10}],\"laneId\":3,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910008,39.5878477],[-105.0909927,39.5878181]]},\"properties\":{\"nodes\":[{\"delta\":[-988,-2151],\"delevation\":20},{\"delta\":[69,-329]}],\"laneId\":6,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090959,39.5878557],[-105.0909501,39.5878218]]},\"properties\":{\"nodes\":[{\"delta\":[-630,-2062],\"delevation\":10},{\"delta\":[76,-377],\"delevation\":10}],\"laneId\":5,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090914,39.5878612],[-105.0909051,39.5878298]]},\"properties\":{\"nodes\":[{\"delta\":[-245,-2001],\"delevation\":10},{\"delta\":[76,-349]}],\"laneId\":4,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911626,39.5880622],[-105.0912043,39.5880536]]},\"properties\":{\"nodes\":[{\"delta\":[-2374,232],\"delevation\":10},{\"delta\":[-357,-96]}],\"laneId\":10,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0914565,39.5879427],[-105.0917937,39.5879029],[-105.0922121,39.5878724],[-105.0926509,39.5878748],[-105.0930303,39.5879073],[-105.0932697,39.5879503],[-105.0937243,39.5880569],[-105.0940309,39.5881258],[-105.0943257,39.5881804],[-105.094592,39.5882097]]},\"properties\":{\"nodes\":[{\"delta\":[-2246,-514],\"delevation\":10},{\"delta\":[-2644,-581]},{\"delta\":[-2887,-442],\"delevation\":10},{\"delta\":[-3583,-339],\"delevation\":10},{\"delta\":[-3757,27]},{\"delta\":[-3249,361],\"delevation\":-10},{\"delta\":[-2050,478]},{\"delta\":[-3893,1184]},{\"delta\":[-2625,766],\"delevation\":-10},{\"delta\":[-2524,607],\"delevation\":10},{\"delta\":[-2280,325],\"delevation\":10}],\"laneId\":8,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0914154,39.5879165],[-105.0916346,39.5878851],[-105.0918433,39.5878639],[-105.0921546,39.5878547]]},\"properties\":{\"nodes\":[{\"delta\":[-2216,-915],\"delevation\":10},{\"delta\":[-2322,-471]},{\"delta\":[-1877,-349],\"delevation\":10},{\"delta\":[-1787,-235]},{\"delta\":[-2666,-102],\"delevation\":10}],\"laneId\":7,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.091436,39.5879812],[-105.0916658,39.5879507],[-105.091881,39.5879277],[-105.0921287,39.5878972]]},\"properties\":{\"nodes\":[{\"delta\":[-2295,-169],\"delevation\":10},{\"delta\":[-2420,-499]},{\"delta\":[-1968,-339],\"delevation\":10},{\"delta\":[-1843,-256]},{\"delta\":[-2121,-339]}],\"laneId\":9,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.0911481,39.5886317],[-105.091196,39.588862],[-105.0912349,39.5890282],[-105.0912722,39.5893202],[-105.0913306,39.5897261],[-105.0913695,39.5900324],[-105.0914008,39.5903008],[-105.0914893,39.5913099],[-105.091527,39.5923157]]},\"properties\":{\"nodes\":[{\"delta\":[-1364,1705],\"delevation\":10},{\"delta\":[-885,4854],\"delevation\":-30},{\"delta\":[-410,2559],\"delevation\":10},{\"delta\":[-333,1847],\"delevation\":-10},{\"delta\":[-319,3244],\"delevation\":-20},{\"delta\":[-500,4510]},{\"delta\":[-333,3403],\"delevation\":-30},{\"delta\":[-268,2982]},{\"delta\":[-758,11212],\"delevation\":-30},{\"delta\":[-323,11176],\"delevation\":-70}],\"laneId\":12,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.0911059,39.5886309],[-105.091144,39.5888313],[-105.0911829,39.5890442],[-105.0912308,39.5893169],[-105.0912689,39.5895877],[-105.0913005,39.5898143],[-105.0913313,39.5900714],[-105.0913597,39.5902968],[-105.0914461,39.5913017],[-105.0914756,39.592324]]},\"properties\":{\"nodes\":[{\"delta\":[-992,1735],\"delevation\":10},{\"delta\":[-896,4816],\"delevation\":-30},{\"delta\":[-326,2227],\"delevation\":10},{\"delta\":[-333,2366]},{\"delta\":[-410,3030],\"delevation\":-20},{\"delta\":[-326,3009],\"delevation\":-10},{\"delta\":[-271,2518],\"delevation\":-10},{\"delta\":[-264,2857],\"delevation\":-20},{\"delta\":[-243,2504]},{\"delta\":[-740,11165],\"delevation\":-30},{\"delta\":[-253,11359],\"delevation\":-70}],\"laneId\":13,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911549,39.5884681],[-105.091196,39.5886783],[-105.091222,39.5888049],[-105.0912401,39.5889649]]},\"properties\":{\"nodes\":[{\"delta\":[-1744,1607],\"delevation\":10},{\"delta\":[-563,3136],\"delevation\":-20},{\"delta\":[-352,2336],\"delevation\":-10},{\"delta\":[-223,1407],\"delevation\":10},{\"delta\":[-155,1778]}],\"laneId\":11,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0908389,39.5882151],[-105.0908478,39.5882471]]},\"properties\":{\"nodes\":[{\"delta\":[398,1931],\"delevation\":-10},{\"delta\":[-76,356]}],\"laneId\":14,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907875,39.58822],[-105.0907979,39.5882514]]},\"properties\":{\"nodes\":[{\"delta\":[838,1985],\"delevation\":-20},{\"delta\":[-89,349]}],\"laneId\":15,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.0911626,39.5880622]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0910008,39.5878477]]},\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.090959,39.5878557]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.090914,39.5878612]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911626,39.5880622]]},\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]}}"; - - final String SPAT = "{\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2023-05-03T16:25:04.807Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"}],\"revision\":0,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":false,\"fixedTimeOperation\":false,\"trafficDependentOperation\":false,\"standbyOperation\":false,\"failureMode\":false,\"off\":false,\"recentMAPmessageUpdate\":false,\"recentChangeInMAPassignedLanesIDsUsed\":false,\"noValidMAPisAvailableAtThisTime\":false,\"noValidSPATisAvailableAtThisTime\":false},\"utcTimeStamp\":\"2023-05-03T16:25:04.807Z\",\"states\":[{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_CLEARANCE\",\"timing\":{\"minEndTime\":\"2023-05-03T16:03:18Z\",\"maxEndTime\":\"2023-05-03T16:03:18Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2023-05-03T16:03:21.1Z\",\"maxEndTime\":\"2023-05-03T16:03:21.1Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_CLEARANCE\",\"timing\":{\"minEndTime\":\"2023-05-03T16:03:18Z\",\"maxEndTime\":\"2023-05-03T16:03:18Z\"}}]}]}"; - - final String BSM = "{\"metadata\":{\"bsmSource\":\"RV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"\",\"longitude\":\"\",\"elevation\":\"\",\"speed\":\"\",\"heading\":\"\"},\"rxSource\":\"RV\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"849c3ac6-4747-426f-ae5e-28ac8531b32c\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2023-05-03T16:25:05.988Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"originIp\":\"10.11.81.12\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":12,\"id\":\"48C45782\",\"secMark\":5988,\"position\":{\"latitude\":39.58785476153264,\"longitude\":-105.09073473997064,\"elevation\":1691.9},\"accelSet\":{\"accelLong\":-0.05,\"accelYaw\":-0.65},\"accuracy\":{\"semiMajor\":2,\"semiMinor\":2,\"orientation\":0},\"transmission\":\"UNAVAILABLE\",\"speed\":24.74,\"heading\":347.3,\"brakes\":{\"wheelBrakes\":{\"leftFront\":false,\"rightFront\":false,\"unavailable\":true,\"leftRear\":false,\"rightRear\":false},\"traction\":\"unavailable\",\"abs\":\"off\",\"scs\":\"unavailable\",\"brakeBoost\":\"unavailable\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":180,\"length\":480}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"pathHistory\":{\"crumbData\":[{\"elevationOffset\":0.6,\"latOffset\":-0.0001604,\"lonOffset\":0.0000387,\"timeOffset\":0.8},{\"elevationOffset\":4.3,\"latOffset\":-0.0011603,\"lonOffset\":0.000231,\"timeOffset\":5.6},{\"elevationOffset\":9.1,\"latOffset\":-0.0023425,\"lonOffset\":0.0003834,\"timeOffset\":11}]},\"pathPrediction\":{\"confidence\":80,\"radiusOfCurve\":-1622.5}}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; + final String ProcessedMap = "{\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2023-05-03T16:25:03.519Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits\",\"schemaPath\":\"#/$defs/J2735SpeedLimitList_Wrapper/type\"}],\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2023-05-03T16:25:03.519Z\"},\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0906245,39.5876246],[-105.0905203,39.587281],[-105.0904383,39.5870554],[-105.0903588,39.5868383],[-105.0902622,39.5865865],[-105.0901249,39.5862612],[-105.0900451,39.5860819],[-105.0899283,39.5858283],[-105.0898739,39.5857117],[-105.0895814,39.5851569],[-105.0888764,39.5839527]]},\"properties\":{\"nodes\":[{\"delta\":[1511,-1514]},{\"delta\":[723,-3116],\"delevation\":10},{\"delta\":[892,-3818],\"delevation\":20},{\"delta\":[702,-2507],\"delevation\":20},{\"delta\":[681,-2412],\"delevation\":10},{\"delta\":[827,-2798],\"delevation\":10},{\"delta\":[1176,-3614],\"delevation\":20},{\"delta\":[683,-1992]},{\"delta\":[1000,-2818],\"delevation\":10},{\"delta\":[466,-1295],\"delevation\":20},{\"delta\":[2505,-6164],\"delevation\":20},{\"delta\":[6037,-13380],\"delevation\":70}],\"laneId\":1,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.090652,39.5875596],[-105.090534,39.5871793],[-105.0903457,39.5866864],[-105.0902123,39.5863581],[-105.0900802,39.5860572],[-105.0898164,39.5855019],[-105.0895409,39.5849856],[-105.088922,39.5839259]]},\"properties\":{\"nodes\":[{\"delta\":[1192,-1619]},{\"delta\":[807,-3733],\"delevation\":30},{\"delta\":[1010,-4226],\"delevation\":10},{\"delta\":[1612,-5477],\"delevation\":30},{\"delta\":[1142,-3648],\"delevation\":20},{\"delta\":[1131,-3343],\"delevation\":10},{\"delta\":[2259,-6170],\"delevation\":30},{\"delta\":[2359,-5737],\"delevation\":30},{\"delta\":[5300,-11774],\"delevation\":50}],\"laneId\":2,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.090747,39.5877247],[-105.0906498,39.5874141],[-105.0906262,39.5873356],[-105.0905865,39.5872922]]},\"properties\":{\"nodes\":[{\"delta\":[805,-1704],\"delevation\":10},{\"delta\":[380,-1813]},{\"delta\":[832,-3451],\"delevation\":30},{\"delta\":[202,-872]},{\"delta\":[340,-482],\"delevation\":-10}],\"laneId\":3,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910008,39.5878477],[-105.0909927,39.5878181]]},\"properties\":{\"nodes\":[{\"delta\":[-988,-2151],\"delevation\":20},{\"delta\":[69,-329]}],\"laneId\":6,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090959,39.5878557],[-105.0909501,39.5878218]]},\"properties\":{\"nodes\":[{\"delta\":[-630,-2062],\"delevation\":10},{\"delta\":[76,-377],\"delevation\":10}],\"laneId\":5,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090914,39.5878612],[-105.0909051,39.5878298]]},\"properties\":{\"nodes\":[{\"delta\":[-245,-2001],\"delevation\":10},{\"delta\":[76,-349]}],\"laneId\":4,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911626,39.5880622],[-105.0912043,39.5880536]]},\"properties\":{\"nodes\":[{\"delta\":[-2374,232],\"delevation\":10},{\"delta\":[-357,-96]}],\"laneId\":10,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0914565,39.5879427],[-105.0917937,39.5879029],[-105.0922121,39.5878724],[-105.0926509,39.5878748],[-105.0930303,39.5879073],[-105.0932697,39.5879503],[-105.0937243,39.5880569],[-105.0940309,39.5881258],[-105.0943257,39.5881804],[-105.094592,39.5882097]]},\"properties\":{\"nodes\":[{\"delta\":[-2246,-514],\"delevation\":10},{\"delta\":[-2644,-581]},{\"delta\":[-2887,-442],\"delevation\":10},{\"delta\":[-3583,-339],\"delevation\":10},{\"delta\":[-3757,27]},{\"delta\":[-3249,361],\"delevation\":-10},{\"delta\":[-2050,478]},{\"delta\":[-3893,1184]},{\"delta\":[-2625,766],\"delevation\":-10},{\"delta\":[-2524,607],\"delevation\":10},{\"delta\":[-2280,325],\"delevation\":10}],\"laneId\":8,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0914154,39.5879165],[-105.0916346,39.5878851],[-105.0918433,39.5878639],[-105.0921546,39.5878547]]},\"properties\":{\"nodes\":[{\"delta\":[-2216,-915],\"delevation\":10},{\"delta\":[-2322,-471]},{\"delta\":[-1877,-349],\"delevation\":10},{\"delta\":[-1787,-235]},{\"delta\":[-2666,-102],\"delevation\":10}],\"laneId\":7,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.091436,39.5879812],[-105.0916658,39.5879507],[-105.091881,39.5879277],[-105.0921287,39.5878972]]},\"properties\":{\"nodes\":[{\"delta\":[-2295,-169],\"delevation\":10},{\"delta\":[-2420,-499]},{\"delta\":[-1968,-339],\"delevation\":10},{\"delta\":[-1843,-256]},{\"delta\":[-2121,-339]}],\"laneId\":9,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.0911481,39.5886317],[-105.091196,39.588862],[-105.0912349,39.5890282],[-105.0912722,39.5893202],[-105.0913306,39.5897261],[-105.0913695,39.5900324],[-105.0914008,39.5903008],[-105.0914893,39.5913099],[-105.091527,39.5923157]]},\"properties\":{\"nodes\":[{\"delta\":[-1364,1705],\"delevation\":10},{\"delta\":[-885,4854],\"delevation\":-30},{\"delta\":[-410,2559],\"delevation\":10},{\"delta\":[-333,1847],\"delevation\":-10},{\"delta\":[-319,3244],\"delevation\":-20},{\"delta\":[-500,4510]},{\"delta\":[-333,3403],\"delevation\":-30},{\"delta\":[-268,2982]},{\"delta\":[-758,11212],\"delevation\":-30},{\"delta\":[-323,11176],\"delevation\":-70}],\"laneId\":12,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.0911059,39.5886309],[-105.091144,39.5888313],[-105.0911829,39.5890442],[-105.0912308,39.5893169],[-105.0912689,39.5895877],[-105.0913005,39.5898143],[-105.0913313,39.5900714],[-105.0913597,39.5902968],[-105.0914461,39.5913017],[-105.0914756,39.592324]]},\"properties\":{\"nodes\":[{\"delta\":[-992,1735],\"delevation\":10},{\"delta\":[-896,4816],\"delevation\":-30},{\"delta\":[-326,2227],\"delevation\":10},{\"delta\":[-333,2366]},{\"delta\":[-410,3030],\"delevation\":-20},{\"delta\":[-326,3009],\"delevation\":-10},{\"delta\":[-271,2518],\"delevation\":-10},{\"delta\":[-264,2857],\"delevation\":-20},{\"delta\":[-243,2504]},{\"delta\":[-740,11165],\"delevation\":-30},{\"delta\":[-253,11359],\"delevation\":-70}],\"laneId\":13,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911549,39.5884681],[-105.091196,39.5886783],[-105.091222,39.5888049],[-105.0912401,39.5889649]]},\"properties\":{\"nodes\":[{\"delta\":[-1744,1607],\"delevation\":10},{\"delta\":[-563,3136],\"delevation\":-20},{\"delta\":[-352,2336],\"delevation\":-10},{\"delta\":[-223,1407],\"delevation\":10},{\"delta\":[-155,1778]}],\"laneId\":11,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0908389,39.5882151],[-105.0908478,39.5882471]]},\"properties\":{\"nodes\":[{\"delta\":[398,1931],\"delevation\":-10},{\"delta\":[-76,356]}],\"laneId\":14,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907875,39.58822],[-105.0907979,39.5882514]]},\"properties\":{\"nodes\":[{\"delta\":[838,1985],\"delevation\":-20},{\"delta\":[-89,349]}],\"laneId\":15,\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.0911626,39.5880622]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0910008,39.5878477]]},\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.090959,39.5878557]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.090914,39.5878612]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911626,39.5880622]]},\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]}}"; + + final String ProcessedSpat = "{\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2023-05-03T16:25:04.807Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime\",\"schemaPath\":\"#/$defs/J2735TimeMark/type\"}],\"revision\":0,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":false,\"fixedTimeOperation\":false,\"trafficDependentOperation\":false,\"standbyOperation\":false,\"failureMode\":false,\"off\":false,\"recentMAPmessageUpdate\":false,\"recentChangeInMAPassignedLanesIDsUsed\":false,\"noValidMAPisAvailableAtThisTime\":false,\"noValidSPATisAvailableAtThisTime\":false},\"utcTimeStamp\":\"2023-05-03T16:25:04.807Z\",\"states\":[{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_CLEARANCE\",\"timing\":{\"minEndTime\":\"2023-05-03T16:03:18Z\",\"maxEndTime\":\"2023-05-03T16:03:18Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2023-05-03T16:03:21.1Z\",\"maxEndTime\":\"2023-05-03T16:03:21.1Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_CLEARANCE\",\"timing\":{\"minEndTime\":\"2023-05-03T16:03:18Z\",\"maxEndTime\":\"2023-05-03T16:03:18Z\"}}]}]}"; + + final String BSM = """ + { + "schemaVersion": 1, + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + -105.09073473997064, + 39.58785476153264 + ] + }, + "properties": { + "accelSet": { + "accelLong": -0.050000000000000003, + "accelYaw": -0.65000000000000002 + }, + "accuracy": { + "semiMajor": 2, + "semiMinor": 2, + "orientation": 0 + }, + "brakes": { + "wheelBrakes": { + "leftFront": false, + "rightFront": false, + "unavailable": true, + "leftRear": false, + "rightRear": false + }, + "traction": "unavailable", + "abs": "off", + "scs": "unavailable", + "brakeBoost": "unavailable", + "auxBrakes": "unavailable" + }, + "heading": 347.30000000000001, + "id": "48C45782", + "msgCnt": 12, + "secMark": 5988, + "size": { + "width": 180, + "length": 480 + }, + "transmission": "UNAVAILABLE" + } + } + ], + "messageType": "BSM", + "odeReceivedAt": "2023-05-03T16:25:05.988Z", + "timeStamp": "2023-05-03T16:25:05.988Z", + "originIp": "10.11.81.12", + "validationMessages": [ + ], + "type": "FeatureCollection" + } + """; } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java index f55817ad..bebface0 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java @@ -1,5 +1,9 @@ package us.dot.its.jpo.conflictmonitor.testutils; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmFeature; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.ode.model.OdeBsmData; import us.dot.its.jpo.ode.model.OdeBsmMetadata; import us.dot.its.jpo.ode.model.OdeBsmPayload; @@ -10,6 +14,7 @@ import java.math.BigDecimal; import java.time.*; import java.time.format.DateTimeFormatter; +import java.util.List; /** * Utilities to create BSM test data @@ -37,6 +42,18 @@ public static OdeBsmData bsmAtInstant(Instant instant, String id) { return bsm; } + public static ProcessedBsm processedBsmAtInstant(Instant instant, String id) { + var bsm = validProcessedBsm(); + ZonedDateTime zdt = instant.atZone(ZoneOffset.UTC); + var strDateTime = DateTimeFormatter.ISO_DATE_TIME.format(zdt); + bsm.setOdeReceivedAt(strDateTime); + bsm.setTimeStamp(zdt); + BsmProperties props = bsm.getFeatures()[0].getProperties(); + props.setSecMark(milliOfMinute(instant)); + props.setId(id); + return bsm; + } + public static OdeBsmData bsmWithPosition(Instant instant, String id, double longitude, double latitude, double elevation) { var bsm = bsmAtInstant(instant, id); var coreData = ((J2735Bsm)bsm.getPayload().getData()).getCoreData(); @@ -48,7 +65,13 @@ public static OdeBsmData bsmWithPosition(Instant instant, String id, double long return bsm; } - + public static ProcessedBsm processedBsmWithPosition(Instant instant, String id, double longitude, double latitude, double elevation) { + var bsm = processedBsmAtInstant(instant, id); + var coords = bsm.getFeatures()[0].getGeometry().getCoordinates(); + coords[0] = longitude; + coords[1] = latitude; + return bsm; + } public static OdeBsmData validBsm() { final var bsm = new OdeBsmData(); @@ -75,4 +98,19 @@ public static OdeBsmData validBsm() { return bsm; } + + @SuppressWarnings("unchecked") + public static ProcessedBsm validProcessedBsm() { + final Point geometry = new Point(-105, 40.0); + final BsmProperties properties = new BsmProperties(); + properties.setId("id"); + properties.setSecMark(1000); + properties.setSpeed(BigDecimal.valueOf(50)); + properties.setHeading(BigDecimal.valueOf(90)); + final BsmFeature feature = new BsmFeature(null, geometry, properties); + final ProcessedBsm bsm = new ProcessedBsm<>(List.of(feature).toArray(new BsmFeature[0])); + bsm.setOriginIp("127.0.0.1"); + bsm.setTimeStamp(ZonedDateTime.parse("2020-01-01T00:00:00.000Z")); + return bsm; + } } From 8735460a4fdd1d6be8522b00bb6c60e218e5b26f Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Tue, 31 Dec 2024 14:55:49 -0700 Subject: [PATCH 09/25] Fix unit test --- .../BsmEventProcessor_validateBSMTest.java | 25 +++++++++---------- .../testutils/BsmTestUtils.java | 1 + 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java index 390d0d63..59857c72 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java @@ -3,28 +3,27 @@ import java.util.ArrayList; import java.util.Collection; +import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; -import us.dot.its.jpo.ode.model.*; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -import static us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils.validBsm; import static us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils.validProcessedBsm; /** * Unit tests for {@link BsmEventProcessor#validateBSM} */ @RunWith(Parameterized.class) +@Slf4j public class BsmEventProcessor_validateBSMTest { @Test public void testValidateBSM() { - var processor = new BsmEventProcessor(); + log.info("{}:", description); var actual = BsmEventProcessor.validateBSM(bsm); assertThat(description, actual, equalTo(expected)); } @@ -46,40 +45,40 @@ public static Collection getParams() { bsms.add(new Object[] {"null BSM", null, false}); - final var emptyBsm = new ProcessedBsm(null); + final ProcessedBsm emptyBsm = new ProcessedBsm(null); bsms.add(new Object[] {"empty BSM", emptyBsm, false}); - final OdeBsmData validBsm = validBsm(); + final ProcessedBsm validBsm = validProcessedBsm(); bsms.add(new Object[] {"Valid BSM", validBsm, true}); - final var bsmWithNullId = validProcessedBsm(); + final ProcessedBsm bsmWithNullId = validProcessedBsm(); bsmWithNullId.getFeatures()[0].getProperties().setId(null); bsms.add(new Object[] {"BSM with null id", bsmWithNullId, false}); - final var bsmWithNullSecMark = validProcessedBsm(); + final ProcessedBsm bsmWithNullSecMark = validProcessedBsm(); bsmWithNullSecMark.getFeatures()[0].getProperties().setSecMark(null); bsms.add(new Object[] {"BSM with null secMark", bsmWithNullSecMark, false}); - final var bsmWithNullSpeed = validProcessedBsm(); + final ProcessedBsm bsmWithNullSpeed = validProcessedBsm(); bsmWithNullSpeed.getFeatures()[0].getProperties().setSpeed(null); bsms.add(new Object[] {"BSM with null speed", bsmWithNullSpeed, false}); - final var bsmWithNullHeading = validProcessedBsm(); + final ProcessedBsm bsmWithNullHeading = validProcessedBsm(); bsmWithNullHeading.getFeatures()[0].getProperties().setHeading(null); bsms.add(new Object[] {"BSM with null heading", bsmWithNullHeading, false}); - final var bsmWithNullSource = validProcessedBsm(); + final ProcessedBsm bsmWithNullSource = validProcessedBsm(); bsmWithNullSource.setOriginIp(null); bsmWithNullSource.setLogName(null); bsms.add(new Object[] {"BSM with null source", bsmWithNullSource, false}); - final var bsmWithNullRecordGeneratedAt = validProcessedBsm(); + final ProcessedBsm bsmWithNullRecordGeneratedAt = validProcessedBsm(); bsmWithNullRecordGeneratedAt.setTimeStamp(null); bsms.add(new Object[] {"BSM with null recordGeneratedAt", bsmWithNullRecordGeneratedAt, false}); - final var bsmWithNullOdeReceivedAt = validProcessedBsm(); + final ProcessedBsm bsmWithNullOdeReceivedAt = validProcessedBsm(); bsmWithNullOdeReceivedAt.setOdeReceivedAt(null); bsms.add(new Object[] {"BSM with null odeReceivedAt", bsmWithNullOdeReceivedAt, false}); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java index bebface0..2e6773e0 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java @@ -111,6 +111,7 @@ public static ProcessedBsm validProcessedBsm() { final ProcessedBsm bsm = new ProcessedBsm<>(List.of(feature).toArray(new BsmFeature[0])); bsm.setOriginIp("127.0.0.1"); bsm.setTimeStamp(ZonedDateTime.parse("2020-01-01T00:00:00.000Z")); + bsm.setOdeReceivedAt("2020-01-01T00:00:25.123Z"); return bsm; } } From bc6d11d8a8a41b4d33f5ed25662b3fcc0eee5b60 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:09:30 -0700 Subject: [PATCH 10/25] Update jpo-utils --- jpo-utils | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jpo-utils b/jpo-utils index 615efe4d..2c461202 160000 --- a/jpo-utils +++ b/jpo-utils @@ -1 +1 @@ -Subproject commit 615efe4d71399f0450f32f5da6321fefa1dce68a +Subproject commit 2c46120222e127d599663376134ab060d0e2587f From 6ddd726ef4795a51c1b4ba9880d8f0b5a77c5d25 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:25:17 -0700 Subject: [PATCH 11/25] Use ProcessedBsm feature --- jpo-conflictmonitor/pom.xml | 2 +- .../monitor/processors/BsmEventProcessor.java | 36 ++--------- .../BsmMessageCountProgressionProcessor.java | 59 ++++++++----------- .../monitor/utils/BsmUtils.java | 17 +----- 4 files changed, 34 insertions(+), 80 deletions(-) diff --git a/jpo-conflictmonitor/pom.xml b/jpo-conflictmonitor/pom.xml index 4ae02dc4..e1141866 100644 --- a/jpo-conflictmonitor/pom.xml +++ b/jpo-conflictmonitor/pom.xml @@ -113,7 +113,7 @@ usdot.jpo.ode jpo-geojsonconverter - 1.4.2 + 2.0.0 diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java index 432c4060..d85c09b3 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java @@ -27,15 +27,9 @@ import us.dot.its.jpo.conflictmonitor.monitor.utils.CoordinateConversion; import us.dot.its.jpo.conflictmonitor.monitor.utils.MathTransformPair; import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmFeature; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; -import us.dot.its.jpo.ode.model.OdeBsmMetadata; -import us.dot.its.jpo.ode.model.OdeBsmPayload; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; -import us.dot.its.jpo.ode.plugin.j2735.J2735BsmCoreData; - import java.time.Duration; import java.time.Instant; import java.util.*; @@ -313,25 +307,7 @@ public static boolean validateBSM(ProcessedBsm[] features = bsm.getFeatures(); - if (features.length == 0) { - logger.error("BSM features.length = 0 {}", bsm); - return false; - } - if (features.length > 1) { - logger.error("ProcessedBsm has more than one point, {}", bsm); - return false; - } - - BsmFeature feature = features[0]; - - - if (feature.getGeometry() instanceof us.dot.its.jpo.geojsonconverter.pojos.geojson.Point pointGeom) { + if (bsm.getGeometry() instanceof us.dot.its.jpo.geojsonconverter.pojos.geojson.Point pointGeom) { double[] coords = pointGeom.getCoordinates(); if (coords == null) { logger.error("BSM coordinates missing {}", bsm); @@ -343,11 +319,11 @@ public static boolean validateBSM(ProcessedBsm> record) { ProcessedBsm lastProcessedBsm = lastProcessedStateStore.get(key); Instant startTime; if (lastProcessedBsm != null) { - startTime = lastProcessedBsm.getTimeStamp().toInstant(); + startTime = lastProcessedBsm.getProperties().getTimeStamp().toInstant(); } else { // No transitions yet, base start time on time window startTime = Instant.ofEpochMilli(context().currentStreamTimeMs()) @@ -91,34 +90,29 @@ public void process(Record> record) { recordCount++; // Skip records older than the last processed state - if (lastProcessedBsm != null && thisState.getTimeStamp().isBefore(lastProcessedBsm.getTimeStamp())) { + if (lastProcessedBsm != null && thisState.getProperties().getTimeStamp().isBefore(lastProcessedBsm.getProperties().getTimeStamp())) { continue; } if (previousState != null) { - long timeDifference = thisState.getTimeStamp().toInstant().toEpochMilli() - previousState.getTimeStamp().toInstant().toEpochMilli(); + long timeDifference = thisState.getProperties().getTimeStamp().toInstant().toEpochMilli() - previousState.getProperties().getTimeStamp().toInstant().toEpochMilli(); if (timeDifference < parameters.getBufferTimeMs()) { int previousHash = calculateHash(previousState); int currentHash = calculateHash(thisState); - BsmFeature[] previousFeatures = previousState.getFeatures(); - BsmFeature[] currentFeatures = thisState.getFeatures(); + BsmProperties previousProperties = previousState.getProperties(); + BsmProperties currentProperties = thisState.getProperties(); - for (int i = 0; i < Math.min(previousFeatures.length, currentFeatures.length); i++) { - BsmProperties previousProperties = previousFeatures[i].getProperties(); - BsmProperties currentProperties = currentFeatures[i].getProperties(); + int previousMessageCount = previousProperties.getMsgCnt(); + int currentMessageCount = currentProperties.getMsgCnt(); - int previousMessageCount = previousProperties.getMsgCnt(); - int currentMessageCount = currentProperties.getMsgCnt(); - - if (previousHash == currentHash && previousMessageCount == currentMessageCount); // No change - else if (previousHash != currentHash && (previousMessageCount + 1) % 128 == currentMessageCount); // changed with valid increment, including wrap-around from 127 to 0 - else { - BsmMessageCountProgressionEvent event = createEvent(previousState, thisState, i); - context().forward(new Record<>(key, event, state.timestamp())); - } - } + if (previousHash == currentHash && previousMessageCount == currentMessageCount); // No change + else if (previousHash != currentHash && (previousMessageCount + 1) % 128 == currentMessageCount); // changed with valid increment, including wrap-around from 127 to 0 + else { + BsmMessageCountProgressionEvent event = createEvent(previousState, thisState, i); + context().forward(new Record<>(key, event, state.timestamp())); + } } } previousState = thisState; @@ -131,26 +125,21 @@ public void process(Record> record) { } private int calculateHash(ProcessedBsm bsmData) { - ZonedDateTime timeStamp = bsmData.getTimeStamp(); - String odeReceivedAt = bsmData.getOdeReceivedAt(); - bsmData.setTimeStamp(null); - bsmData.setOdeReceivedAt(null); - BsmFeature[] features = bsmData.getFeatures(); - int[] originalMsgCnts = new int[features.length]; - // Save original msgCnt values and set them to 0 - for (int i = 0; i < features.length; i++) { - originalMsgCnts[i] = features[i].getProperties().getMsgCnt(); - features[i].getProperties().setMsgCnt(0); - } + final ZonedDateTime timeStamp = bsmData.getProperties().getTimeStamp(); + final String odeReceivedAt = bsmData.getProperties().getOdeReceivedAt(); + bsmData.getProperties().setTimeStamp(null); + bsmData.getProperties().setOdeReceivedAt(null); + + // Save original msgCnt value and set them to 0 + final int originalMsgCnt = bsmData.getProperties().getMsgCnt(); + bsmData.getProperties().setMsgCnt(0); int hash = bsmData.hashCode(); // Restore original msgCnt values - for (int i = 0; i < features.length; i++) { - features[i].getProperties().setMsgCnt(originalMsgCnts[i]); - } - bsmData.setTimeStamp(timeStamp); - bsmData.setOdeReceivedAt(odeReceivedAt); + bsmData.getProperties().setMsgCnt(originalMsgCnt); + bsmData.getProperties().setTimeStamp(timeStamp); + bsmData.getProperties().setOdeReceivedAt(odeReceivedAt); return hash; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java index 932a2ee7..0a7dc0e6 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java @@ -3,7 +3,6 @@ import lombok.extern.slf4j.Slf4j; import org.locationtech.jts.geom.CoordinateXY; import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmFeature; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.ode.model.OdeBsmData; @@ -34,11 +33,7 @@ public static CoordinateXY getPosition(ProcessedBsm processedBsm) { return position; } - public static Optional> getFeature(ProcessedBsm processedBsm) { - if (processedBsm == null) return Optional.empty(); - if (processedBsm.getFeatures() == null || processedBsm.getFeatures().length < 1) return Optional.empty(); - return Optional.of(processedBsm.getFeatures()[0]); - } + /** * Get geometry @@ -46,10 +41,7 @@ public static Optional> getFeature(ProcessedBsm processedBsm) { * @return The Point geometry, or empty if geometry is not a geojson Point. */ public static Optional getGeometry(ProcessedBsm processedBsm) { - Optional> optionalFeature = getFeature(processedBsm); - if (optionalFeature.isEmpty()) return Optional.empty(); - BsmFeature feature = optionalFeature.get(); - Object geom = feature.getGeometry(); + Object geom = processedBsm.getGeometry(); if (geom == null) return Optional.empty(); if (geom instanceof Point point) { return Optional.of(point); @@ -59,10 +51,7 @@ public static Optional getGeometry(ProcessedBsm processedBsm) { } public static Optional getProperties(ProcessedBsm processedBsm) { - Optional> optFeature = getFeature(processedBsm); - if (optFeature.isEmpty()) return Optional.empty(); - BsmFeature feature = optFeature.get(); - BsmProperties properties = feature.getProperties(); + BsmProperties properties = processedBsm.getProperties(); if (properties == null) return Optional.empty(); return Optional.of(properties); } From 89ca3358a7023c834c2bbd3fcf08e71ba261c898 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Tue, 7 Jan 2025 22:03:36 -0700 Subject: [PATCH 12/25] Update unit tests --- .../models/bsm/BsmTimestampExtractor.java | 2 +- .../BsmMessageCountProgressionProcessor.java | 22 ++++++++++--------- .../BsmEventProcessor_validateBSMTest.java | 18 +++++++-------- .../topologies/BsmEventTopologyTest.java | 8 ++----- .../testutils/BsmTestUtils.java | 20 +++++++---------- 5 files changed, 32 insertions(+), 38 deletions(-) diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmTimestampExtractor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmTimestampExtractor.java index a118a42a..42664b6c 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmTimestampExtractor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmTimestampExtractor.java @@ -25,7 +25,7 @@ public long extract(ConsumerRecord record, long partitionTime) { public static long getBsmTimestamp(ProcessedBsm bsm){ try{ - ZonedDateTime time = ZonedDateTime.parse(bsm.getOdeReceivedAt(), DateTimeFormatter.ISO_ZONED_DATE_TIME); + ZonedDateTime time = ZonedDateTime.parse(bsm.getProperties().getOdeReceivedAt(), DateTimeFormatter.ISO_ZONED_DATE_TIME); BsmProperties properties = BsmUtils.getProperties(bsm).orElseThrow(); final int secMark = properties.getSecMark(); final ZonedDateTime refTime = getRefTime(secMark, time); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java index 106c0d09..edf0f92a 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java @@ -107,10 +107,12 @@ public void process(Record> record) { int previousMessageCount = previousProperties.getMsgCnt(); int currentMessageCount = currentProperties.getMsgCnt(); - if (previousHash == currentHash && previousMessageCount == currentMessageCount); // No change - else if (previousHash != currentHash && (previousMessageCount + 1) % 128 == currentMessageCount); // changed with valid increment, including wrap-around from 127 to 0 - else { - BsmMessageCountProgressionEvent event = createEvent(previousState, thisState, i); + if (previousHash == currentHash && previousMessageCount == currentMessageCount) { + // No change + } else if (previousHash != currentHash && (previousMessageCount + 1) % 128 == currentMessageCount) { + // changed with valid increment, including wrap-around from 127 to 0 + } else { + BsmMessageCountProgressionEvent event = createEvent(previousState, thisState); context().forward(new Record<>(key, event, state.timestamp())); } } @@ -143,18 +145,18 @@ private int calculateHash(ProcessedBsm bsmData) { return hash; } - private BsmMessageCountProgressionEvent createEvent(ProcessedBsm previousState, ProcessedBsm thisState, int featureIndex) { - BsmProperties previousProperties = previousState.getFeatures()[featureIndex].getProperties(); - BsmProperties currentProperties = thisState.getFeatures()[featureIndex].getProperties(); + private BsmMessageCountProgressionEvent createEvent(ProcessedBsm previousState, ProcessedBsm thisState) { + BsmProperties previousProperties = previousState.getProperties(); + BsmProperties currentProperties = thisState.getProperties(); BsmMessageCountProgressionEvent event = new BsmMessageCountProgressionEvent(); event.setMessageType("BSM"); event.setMessageCountA(previousProperties.getMsgCnt()); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); - event.setTimestampA(previousState.getTimeStamp().format(formatter)); + event.setTimestampA(previousState.getProperties().getTimeStamp().format(formatter)); event.setMessageCountB(currentProperties.getMsgCnt()); - event.setTimestampB(thisState.getTimeStamp().format(formatter)); - event.setVehicleId(thisState.getFeatures()[featureIndex].getId().toString()); + event.setTimestampB(thisState.getProperties().getTimeStamp().format(formatter)); + event.setVehicleId(thisState.getProperties().getId()); return event; diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java index 59857c72..d1d6f6fe 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor_validateBSMTest.java @@ -45,7 +45,7 @@ public static Collection getParams() { bsms.add(new Object[] {"null BSM", null, false}); - final ProcessedBsm emptyBsm = new ProcessedBsm(null); + final ProcessedBsm emptyBsm = new ProcessedBsm(null, null, null); bsms.add(new Object[] {"empty BSM", emptyBsm, false}); @@ -53,33 +53,33 @@ public static Collection getParams() { bsms.add(new Object[] {"Valid BSM", validBsm, true}); final ProcessedBsm bsmWithNullId = validProcessedBsm(); - bsmWithNullId.getFeatures()[0].getProperties().setId(null); + bsmWithNullId.getProperties().setId(null); bsms.add(new Object[] {"BSM with null id", bsmWithNullId, false}); final ProcessedBsm bsmWithNullSecMark = validProcessedBsm(); - bsmWithNullSecMark.getFeatures()[0].getProperties().setSecMark(null); + bsmWithNullSecMark.getProperties().setSecMark(null); bsms.add(new Object[] {"BSM with null secMark", bsmWithNullSecMark, false}); final ProcessedBsm bsmWithNullSpeed = validProcessedBsm(); - bsmWithNullSpeed.getFeatures()[0].getProperties().setSpeed(null); + bsmWithNullSpeed.getProperties().setSpeed(null); bsms.add(new Object[] {"BSM with null speed", bsmWithNullSpeed, false}); final ProcessedBsm bsmWithNullHeading = validProcessedBsm(); - bsmWithNullHeading.getFeatures()[0].getProperties().setHeading(null); + bsmWithNullHeading.getProperties().setHeading(null); bsms.add(new Object[] {"BSM with null heading", bsmWithNullHeading, false}); final ProcessedBsm bsmWithNullSource = validProcessedBsm(); - bsmWithNullSource.setOriginIp(null); - bsmWithNullSource.setLogName(null); + bsmWithNullSource.getProperties().setOriginIp(null); + bsmWithNullSource.getProperties().setLogName(null); bsms.add(new Object[] {"BSM with null source", bsmWithNullSource, false}); final ProcessedBsm bsmWithNullRecordGeneratedAt = validProcessedBsm(); - bsmWithNullRecordGeneratedAt.setTimeStamp(null); + bsmWithNullRecordGeneratedAt.getProperties().setTimeStamp(null); bsms.add(new Object[] {"BSM with null recordGeneratedAt", bsmWithNullRecordGeneratedAt, false}); final ProcessedBsm bsmWithNullOdeReceivedAt = validProcessedBsm(); - bsmWithNullOdeReceivedAt.setOdeReceivedAt(null); + bsmWithNullOdeReceivedAt.getProperties().setOdeReceivedAt(null); bsms.add(new Object[] {"BSM with null odeReceivedAt", bsmWithNullOdeReceivedAt, false}); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java index eb4d3d08..7c5f706f 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmEventTopologyTest.java @@ -16,7 +16,6 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmTimestampExtractor; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapIndex; -import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; import us.dot.its.jpo.conflictmonitor.testutils.TopologyTestUtils; import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; import us.dot.its.jpo.geojsonconverter.pojos.ProcessedValidationMessage; @@ -24,15 +23,12 @@ import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; import java.time.Instant; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -import static us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils.bsmAtInstant; import static us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils.processedBsmAtInstant; public class BsmEventTopologyTest { @@ -102,7 +98,7 @@ public void testBsmEventTopology() { ProcessedBsm invalidBsm = processedBsmAtInstant(startTime, id2.getBsmId()); var validationMessage = new ProcessedValidationMessage(); validationMessage.setMessage("Invalid BSM"); - invalidBsm.setValidationMessages(List.of(validationMessage)); + invalidBsm.getProperties().setValidationMessages(List.of(validationMessage)); inputTopic.pipeInput(id2, invalidBsm, startTime); // Include a BSM with an earlier timestamp than the previous BSM for validation coverage @@ -112,7 +108,7 @@ public void testBsmEventTopology() { var output = outputTopic.readKeyValuesToList(); assertThat(output, hasSize(1)); - var outputItem = output.iterator().next(); + var outputItem = output.getFirst(); logger.info("BSM Event: {}", outputItem); BsmIntersectionIdKey key = outputItem.key; assertThat(key.getBsmId(), endsWith(id1.getBsmId())); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java index 2e6773e0..18de8eae 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java @@ -1,7 +1,6 @@ package us.dot.its.jpo.conflictmonitor.testutils; import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmFeature; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.ode.model.OdeBsmData; @@ -14,7 +13,6 @@ import java.math.BigDecimal; import java.time.*; import java.time.format.DateTimeFormatter; -import java.util.List; /** * Utilities to create BSM test data @@ -46,9 +44,9 @@ public static ProcessedBsm processedBsmAtInstant(Instant instant, String var bsm = validProcessedBsm(); ZonedDateTime zdt = instant.atZone(ZoneOffset.UTC); var strDateTime = DateTimeFormatter.ISO_DATE_TIME.format(zdt); - bsm.setOdeReceivedAt(strDateTime); - bsm.setTimeStamp(zdt); - BsmProperties props = bsm.getFeatures()[0].getProperties(); + bsm.getProperties().setOdeReceivedAt(strDateTime); + bsm.getProperties().setTimeStamp(zdt); + BsmProperties props = bsm.getProperties(); props.setSecMark(milliOfMinute(instant)); props.setId(id); return bsm; @@ -67,7 +65,7 @@ public static OdeBsmData bsmWithPosition(Instant instant, String id, double long public static ProcessedBsm processedBsmWithPosition(Instant instant, String id, double longitude, double latitude, double elevation) { var bsm = processedBsmAtInstant(instant, id); - var coords = bsm.getFeatures()[0].getGeometry().getCoordinates(); + var coords = bsm.getGeometry().getCoordinates(); coords[0] = longitude; coords[1] = latitude; return bsm; @@ -107,11 +105,9 @@ public static ProcessedBsm validProcessedBsm() { properties.setSecMark(1000); properties.setSpeed(BigDecimal.valueOf(50)); properties.setHeading(BigDecimal.valueOf(90)); - final BsmFeature feature = new BsmFeature(null, geometry, properties); - final ProcessedBsm bsm = new ProcessedBsm<>(List.of(feature).toArray(new BsmFeature[0])); - bsm.setOriginIp("127.0.0.1"); - bsm.setTimeStamp(ZonedDateTime.parse("2020-01-01T00:00:00.000Z")); - bsm.setOdeReceivedAt("2020-01-01T00:00:25.123Z"); - return bsm; + properties.setOriginIp("127.0.0.1"); + properties.setTimeStamp(ZonedDateTime.parse("2020-01-01T00:00:00.000Z")); + properties.setOdeReceivedAt("2020-01-01T00:00:25.123Z"); + return new ProcessedBsm<>(null, geometry, properties); } } From 931452d6f7206ce430a339b98c78f0a8c9b43b3b Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Tue, 7 Jan 2025 22:56:11 -0700 Subject: [PATCH 13/25] Update MessageIngestTopology --- .../ConnectionOfTravelAnalytics.java | 2 +- .../models/bsm/BsmIntersectionIdKey.java | 14 ++++----- .../monitor/processors/BsmEventProcessor.java | 6 ++-- .../topologies/IntersectionEventTopology.java | 1 - .../topologies/MessageIngestTopology.java | 29 +++++++------------ .../IntersectionEventTopologyTest.java | 19 ++++++------ 6 files changed, 31 insertions(+), 40 deletions(-) diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/ConnectionOfTravelAnalytics.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/ConnectionOfTravelAnalytics.java index 819dc389..f1d08b0f 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/ConnectionOfTravelAnalytics.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/ConnectionOfTravelAnalytics.java @@ -11,7 +11,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmTimestampExtractor; import us.dot.its.jpo.conflictmonitor.monitor.models.events.ConnectionOfTravelEvent; -// TODO Use Processed BSM + @Component(DEFAULT_CONNECTION_OF_TRAVEL_ALGORITHM) public class ConnectionOfTravelAnalytics implements ConnectionOfTravelAlgorithm{ diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmIntersectionIdKey.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmIntersectionIdKey.java index 285d9bce..7665f6cb 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmIntersectionIdKey.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/bsm/BsmIntersectionIdKey.java @@ -1,10 +1,7 @@ package us.dot.its.jpo.conflictmonitor.monitor.models.bsm; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import lombok.*; import us.dot.its.jpo.conflictmonitor.monitor.models.IntersectionRegion; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; @@ -12,21 +9,24 @@ @Setter @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) +@Generated public class BsmIntersectionIdKey extends RsuIntersectionKey { String bsmId; - // TODO Add log file + String logId; public BsmIntersectionIdKey() {} - public BsmIntersectionIdKey(String bsmId, String rsuId, int intersectionId) { + public BsmIntersectionIdKey(String bsmId, String rsuId, int intersectionId, String logId) { super(rsuId, intersectionId); this.bsmId = bsmId; + this.logId = logId; } - public BsmIntersectionIdKey(String bsmId, String rsuId, int intersectionId, int region) { + public BsmIntersectionIdKey(String bsmId, String rsuId, int intersectionId, int region, String logId) { super(rsuId, intersectionId, region); this.bsmId = bsmId; + this.logId = logId; } @JsonIgnore diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java index d85c09b3..bd40e5e3 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java @@ -116,7 +116,7 @@ public void process(Record(bsmIntersectionIdKey, value, timestamp); var intersectionRecord = inputRecord.withKey(bsmIntersectionIdKey); context().forward(intersectionRecord, BsmEventTopology.PARTITIONED_BSM_SINK); @@ -251,13 +251,13 @@ private void newEvent( BsmEvent event = getNewEvent(value, timestamp, true); event.setWktMapBoundingBox(map.getBoundingPolygonWkt()); event.setIntersectionID(map.getIntersectionId()); - var eventKey = new BsmIntersectionIdKey(key.getBsmId(), key.getRsuId(), map.getIntersectionId(), map.getRegion()); + var eventKey = new BsmIntersectionIdKey(key.getBsmId(), key.getRsuId(), map.getIntersectionId(), map.getRegion(), key.getLogId()); stateStore.put(eventKey, ValueAndTimestamp.make(event, timestamp)); } private void newEvent(ProcessedBsm value, RsuLogKey key, long timestamp) throws ParseException { BsmEvent event = getNewEvent(value, timestamp, false); - var eventKey = new BsmIntersectionIdKey(key.getBsmId(), key.getRsuId(), 0); + var eventKey = new BsmIntersectionIdKey(key.getBsmId(), key.getRsuId(), -1, key.getLogId()); stateStore.put(eventKey, ValueAndTimestamp.make(event, timestamp)); } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java index 6000f92a..4cb2b40b 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopology.java @@ -232,7 +232,6 @@ public void setStopLineStopParameters(StopLineStopParameters stopsParams) { - // TODO Use ProcessedBsm private static BsmAggregator getBsmsByTimeVehicle(ReadOnlyWindowStore> bsmWindowStore, Instant start, Instant end, BsmIntersectionIdKey key){ logger.info("getBsmsByTimeVehicle: Start: {}, End: {}, key: {}", start, end, key); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java index e4e8d51a..fd4e2ee1 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java @@ -39,7 +39,7 @@ import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; +//import us.dot.its.jpo.ode.model.OdeBsmData; import java.time.Duration; @@ -73,8 +73,6 @@ public EventStateProgressionAlgorithm getEventStateProgressionAlgorithm() { @Override public void buildTopology(StreamsBuilder builder) { - - /* * * @@ -82,28 +80,23 @@ public void buildTopology(StreamsBuilder builder) { * */ - //BSM Input Stream // Ingest only BSMs within the intersection bounding box - KStream bsmJsonStream = + KStream> bsmJsonStream = builder.stream( parameters.getBsmTopic(), Consumed.with( - JsonSerdes.BsmIntersectionIdKey(), - JsonSerdes.OdeBsm()) + JsonSerdes.BsmIntersectionIdKey(), + us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedBsm()) .withTimestampExtractor(new BsmTimestampExtractor()) ); - - - //Group up all of the BSM's based upon the new ID. - KGroupedStream bsmKeyGroup = - bsmJsonStream.groupByKey(Grouped.with(JsonSerdes.BsmIntersectionIdKey(), JsonSerdes.OdeBsm())); - - - - + KGroupedStream> bsmKeyGroup = + bsmJsonStream.groupByKey( + Grouped.with( + JsonSerdes.BsmIntersectionIdKey(), + us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedBsm())); //Take the BSM's and Materialize them into a Temporal Time window. The length of the time window shouldn't matter much //but enables kafka to temporally query the records later. If there are duplicate keys, the more recent value is taken. @@ -113,9 +106,9 @@ public void buildTopology(StreamsBuilder builder) { System.out.println("Overwriting BSM"); return newValue; }, - Materialized.>as(parameters.getBsmStoreName()) + Materialized., WindowStore>as(parameters.getBsmStoreName()) .withKeySerde(JsonSerdes.BsmIntersectionIdKey()) - .withValueSerde(JsonSerdes.OdeBsm()) + .withValueSerde(us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedBsm()) .withCachingDisabled() // .withLoggingEnabled(loggingConfig) .withLoggingDisabled() diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopologyTest.java index c58ccb92..44dd0295 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/IntersectionEventTopologyTest.java @@ -26,6 +26,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_stop.StopLineStopParameters; import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmIntersectionIdKey; import us.dot.its.jpo.conflictmonitor.monitor.models.events.ConnectionOfTravelEvent; import us.dot.its.jpo.conflictmonitor.testutils.BsmTestUtils; import us.dot.its.jpo.conflictmonitor.testutils.SpatTestUtils; @@ -82,12 +83,9 @@ public class IntersectionEventTopologyTest { final long startMillis = 1682615309868L; final long endMillis = 1682615347488L; - final RsuLogKey bsmId = new RsuLogKey(); + final BsmIntersectionIdKey bsmId = new BsmIntersectionIdKey("A0A0A0", "127.0.0.1", 1000, 25, "log"); + - public IntersectionEventTopologyTest() { - bsmId.setRsuId("127.0.0.1"); - bsmId.setBsmId("A0A0A0"); - } @Test public void testIntersectionEventTopology() { @@ -97,10 +95,11 @@ public void testIntersectionEventTopology() { final var startBsm = BsmTestUtils.processedBsmAtInstant(Instant.ofEpochMilli(startMillis), bsmId.getBsmId()); final var endBsm = BsmTestUtils.processedBsmAtInstant(Instant.ofEpochMilli(endMillis), bsmId.getBsmId()); - final KeyValue, ProcessedBsm> kvStartBsm - = new KeyValue<>(new Windowed<>(bsmId.getBsmId(), new TimeWindow(startMillis, startMillis + 30000)), startBsm); - final KeyValue, ProcessedBsm> kvEndBsm - = new KeyValue<>(new Windowed<>(bsmId.getBsmId(), new TimeWindow(startMillis, startMillis + 30000)), endBsm); + + final KeyValue, ProcessedBsm> kvStartBsm + = new KeyValue<>(new Windowed(bsmId, new TimeWindow(startMillis, startMillis + 30000)), startBsm); + final KeyValue, ProcessedBsm> kvEndBsm + = new KeyValue<>(new Windowed<>(bsmId, new TimeWindow(startMillis, startMillis + 30000)), endBsm); final int intersectionId = 1; final ProcessedSpat spat = SpatTestUtils.validSpat(intersectionId); @@ -147,7 +146,7 @@ public void testIntersectionEventTopology() { var bsmInputTopic = driver.createInputTopic( bsmEventTopic, - new JsonSerializer(), + new JsonSerializer(), new JsonSerializer()); var connectionOfTravelOutputTopic = driver.createOutputTopic( connectionOfTravelTopic, From 44290ae5bbf6f337bd041251bc7531bbf206953a Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:46:49 -0700 Subject: [PATCH 14/25] Remove unused code --- .../LaneDirectionOfTravelAnalytics.java | 4 +- .../models/Intersection/VehiclePath.java | 2 +- .../monitor/processors/BsmEventProcessor.java | 2 +- .../processors/MapSequenceProcessor.java | 141 ------ .../processors/SpatSequenceProcessor.java | 10 - .../monitor/serialization/JsonSerdes.java | 8 +- .../monitor/topologies/ConflictTopology.java | 112 ----- .../topologies/MessageIngestTopology.java | 2 +- .../monitor/utils/BsmUtils.java | 87 ---- .../testutils/BsmTestUtils.java | 57 --- jpo-deduplicator/Dockerfile | 65 --- jpo-deduplicator/LICENSE-2.0.html | 228 --------- jpo-deduplicator/docker-compose.yml | 23 - jpo-deduplicator/pom.xml | 294 ------------ jpo-deduplicator/sample.env | 2 - .../deduplicator/DeduplicatorApplication.java | 57 --- .../deduplicator/DeduplicatorProperties.java | 444 ------------------ .../jpo/deduplicator/KafkaConfiguration.java | 197 -------- .../deduplicator/StreamsExceptionHandler.java | 56 --- .../DeduplicatorServiceController.java | 107 ----- .../deduplicator/models/JsonPair.java | 21 - .../deduplicator/models/OdeBsmPair.java | 20 - .../deduplicator/models/OdeMapPair.java | 20 - .../deduplicator/models/Pair.java | 19 - .../deduplicator/models/ProcessedMapPair.java | 21 - .../models/ProcessedMapWktPair.java | 20 - .../processors/DeduplicationProcessor.java | 69 --- .../processors/OdeBsmJsonProcessor.java | 80 ---- .../processors/OdeMapJsonProcessor.java | 70 --- .../OdeRawEncodedTimJsonProcessor.java | 43 -- .../processors/OdeTimJsonProcessor.java | 42 -- .../processors/ProcessedMapProcessor.java | 57 --- .../processors/ProcessedMapWktProcessor.java | 55 --- .../processors/ProcessedSpatProcessor.java | 64 --- .../OdeBsmJsonProcessorSupplier.java | 26 - .../OdeMapJsonProcessorSupplier.java | 22 - .../OdeRawEncodedTimProcessorSupplier.java | 22 - .../OdeTimJsonProcessorSupplier.java | 22 - .../ProcessedMapProcessorSupplier.java | 23 - .../ProcessedMapWktProcessorSupplier.java | 22 - .../ProcessedSpatProcessorSupplier.java | 22 - .../serialization/JsonSerdes.java | 24 - .../serialization/PairSerdes.java | 52 -- .../topologies/BsmDeduplicatorTopology.java | 125 ----- .../topologies/MapDeduplicatorTopology.java | 121 ----- .../OdeRawEncodedTimDeduplicatorTopology.java | 131 ------ .../ProcessedMapDeduplicatorTopology.java | 92 ---- .../ProcessedMapWktDeduplicatorTopology.java | 93 ---- .../ProcessedSpatDeduplicatorTopology.java | 97 ---- .../topologies/TimDeduplicatorTopology.java | 126 ----- .../src/main/resources/application.yaml | 96 ---- .../src/main/resources/logback.xml | 20 - .../BsmDeduplicatorTopologyTest.java | 116 ----- .../MapDeduplicatorTopologyTest.java | 96 ---- ...RawEncodedTimDeduplicatorTopologyTest.java | 89 ---- .../ProcessedMapDeduplicatorTopologyTest.java | 99 ---- ...ocessedMapWktDeduplicatorTopologyTest.java | 101 ---- ...ProcessedSpatDeduplicatorTopologyTest.java | 106 ----- .../TimDeduplicatorTopologyTest.java | 89 ---- .../resources/application-testConfig.yaml | 1 - .../src/test/resources/logback-test.xml | 11 - 61 files changed, 6 insertions(+), 4337 deletions(-) delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/MapSequenceProcessor.java delete mode 100644 jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/ConflictTopology.java delete mode 100644 jpo-deduplicator/Dockerfile delete mode 100644 jpo-deduplicator/LICENSE-2.0.html delete mode 100644 jpo-deduplicator/docker-compose.yml delete mode 100644 jpo-deduplicator/pom.xml delete mode 100644 jpo-deduplicator/sample.env delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorApplication.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorProperties.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/KafkaConfiguration.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/StreamsExceptionHandler.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/DeduplicatorServiceController.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/JsonPair.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeMapPair.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/Pair.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapPair.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapWktPair.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/DeduplicationProcessor.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeBsmJsonProcessor.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeMapJsonProcessor.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeRawEncodedTimJsonProcessor.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeTimJsonProcessor.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapProcessor.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapWktProcessor.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedSpatProcessor.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeBsmJsonProcessorSupplier.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeMapJsonProcessorSupplier.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeRawEncodedTimProcessorSupplier.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeTimJsonProcessorSupplier.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapProcessorSupplier.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapWktProcessorSupplier.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedSpatProcessorSupplier.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/JsonSerdes.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/PairSerdes.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/BsmDeduplicatorTopology.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/MapDeduplicatorTopology.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/OdeRawEncodedTimDeduplicatorTopology.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapDeduplicatorTopology.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapWktDeduplicatorTopology.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedSpatDeduplicatorTopology.java delete mode 100644 jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/TimDeduplicatorTopology.java delete mode 100644 jpo-deduplicator/src/main/resources/application.yaml delete mode 100644 jpo-deduplicator/src/main/resources/logback.xml delete mode 100644 jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java delete mode 100644 jpo-deduplicator/src/test/java/deduplicator/MapDeduplicatorTopologyTest.java delete mode 100644 jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java delete mode 100644 jpo-deduplicator/src/test/java/deduplicator/ProcessedMapDeduplicatorTopologyTest.java delete mode 100644 jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java delete mode 100644 jpo-deduplicator/src/test/java/deduplicator/ProcessedSpatDeduplicatorTopologyTest.java delete mode 100644 jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java delete mode 100644 jpo-deduplicator/src/test/resources/application-testConfig.yaml delete mode 100644 jpo-deduplicator/src/test/resources/logback-test.xml diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/LaneDirectionOfTravelAnalytics.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/LaneDirectionOfTravelAnalytics.java index 58780911..00a10637 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/LaneDirectionOfTravelAnalytics.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/analytics/LaneDirectionOfTravelAnalytics.java @@ -65,9 +65,9 @@ protected HashMap> getBsmsByLaneSegment(VehicleP for(int i =0; i < pathPoints.getNumPoints(); i++){ Point pathPoint = pathPoints.getPointN(i); - // OdeBsmData bsm = path.getBsms().getBsms().get(i); + for(LaneSegment segment: segments){ - if(segment.getPolygon().contains(pathPoint)){// && ((J2735Bsm)bsm.getPayload().getData()).getCoreData().getSpeed().doubleValue() > this.parameters.getMinimumSpeedThreshold()){ + if(segment.getPolygon().contains(pathPoint)){ // Add BSM to existing list if available, otherwise create a new list to store the BSM if(segmentBsmMap.get(segment) != null){ diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/VehiclePath.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/VehiclePath.java index fcb4ec18..fa00cb72 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/VehiclePath.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/Intersection/VehiclePath.java @@ -156,7 +156,7 @@ public LineVehicleIntersection findLineVehicleIntersection( * Find the BSMs that are in the ingress lane and within the upstream search distance * @param lane - The ingress lane to search * @param upstreamSearchDistanceFeet - The upstream distance along the lane to search - * @return List + * @return List */ public List> findBsmsInIngressLane(Lane lane, final double upstreamSearchDistanceFeet) { diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java index bd40e5e3..a16e8a84 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmEventProcessor.java @@ -117,7 +117,7 @@ public void process(Record(bsmIntersectionIdKey, value, timestamp); + var intersectionRecord = inputRecord.withKey(bsmIntersectionIdKey); context().forward(intersectionRecord, BsmEventTopology.PARTITIONED_BSM_SINK); } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/MapSequenceProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/MapSequenceProcessor.java deleted file mode 100644 index 0a09e75d..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/MapSequenceProcessor.java +++ /dev/null @@ -1,141 +0,0 @@ -// package us.dot.its.jpo.conflictmonitor.monitor.processors; - -// import java.time.Duration; - -// import org.apache.kafka.streams.KeyValue; -// import org.apache.kafka.streams.processor.api.ContextualProcessor; -// import org.apache.kafka.streams.processor.api.ProcessorContext; -// import org.apache.kafka.streams.processor.api.Record; -// import org.apache.kafka.streams.state.KeyValueIterator; -// import org.apache.kafka.streams.state.KeyValueStore; -// import org.apache.kafka.streams.state.TimestampedKeyValueStore; -// import org.apache.kafka.streams.state.ValueAndTimestamp; - -// import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsParameters; -// import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmEvent; -// import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmTimestampExtractor; -// import us.dot.its.jpo.conflictmonitor.monitor.models.events.TimeChangeDetailsEvent; -// import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetail; -// import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetailAggregator; -// import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetailPair; -// import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetailState; -// import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -// import us.dot.its.jpo.ode.model.OdeBsmData; -// import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; -// import us.dot.its.jpo.ode.plugin.j2735.J2735MovementPhaseState; - - - - -// // Pulls incoming spats and holds a buffer of messages. -// // Acts as a Jitter Buffer to ensure messages are properly sequenced and ensure messages are processed in order. -// public class MapSequenceProcessor extends ContextualProcessor { -// private KeyValueStore stateStore; -// private SpatTimeChangeDetailsParameters parameters; - -// public MapSequenceProcessor(SpatTimeChangeDetailsParameters parameters) { -// this.parameters = parameters; -// } - -// @Override -// public void init(ProcessorContext context) { -// super.init(context); -// stateStore = (KeyValueStore) context.getStateStore(this.parameters.getSpatTimeChangeDetailsStateStoreName()); -// } - - - -// @Override -// public void process(Record record) { -// ProcessedSpat inputSpat = record.value(); -// // Key the BSM's based upon vehicle ID. -// //key = key + "_" + ((J2735Bsm)value.getPayload().getData()).getCoreData().getId(); -// String key = inputSpat.getOriginIp()+"_"+inputSpat.getRegion()+"_"+inputSpat.getIntersectionId(); -// SpatTimeChangeDetailAggregator agg = stateStore.get(key); - -// if (agg != null) { -// SpatTimeChangeDetailPair oldestPair = agg.add(SpatTimeChangeDetail.fromProcessedSpat(inputSpat)); -// stateStore.put(key, agg); - -// if(oldestPair != null){ -// SpatTimeChangeDetail first = oldestPair.getFirst(); -// SpatTimeChangeDetail second = oldestPair.getSecond(); - - -// if(first.getStates() != null && second.getStates() != null){ -// for(SpatTimeChangeDetailState firstState: first.getStates()){ -// for(SpatTimeChangeDetailState secondState: second.getStates()){ -// if(firstState.getSignalGroup() == secondState.getSignalGroup()){ -// if(firstState.getMinEndTime() > secondState.getMinEndTime() && firstState.getEventState() != secondState.getEventState()){ -// //TimeChangeDetailsEvent event = buildEvent(first, second, firstState, secondState); -// TimeChangeDetailsEvent event = new TimeChangeDetailsEvent(); -// event.setRoadRegulatorID(first.getRegion()); -// event.setIntersectionID(first.getIntersectionID()); -// event.setSignalGroup(firstState.getSignalGroup()); -// event.setFirstSpatTimestamp(first.getTimestamp()); -// event.setSecondSpatTimestamp(second.getTimestamp()); -// event.setFirstConflictingTimemark(firstState.getMinEndTime()); -// event.setSecondConflictingTimemark(secondState.getMinEndTime()); - -// context().forward(new Record<>(key, event, event.getFirstSpatTimestamp())); - -// } -// if(firstState.getMaxEndTime() < secondState.getMaxEndTime() && firstState.getEventState() != secondState.getEventState()){ -// TimeChangeDetailsEvent event = new TimeChangeDetailsEvent(); -// event.setRoadRegulatorID(first.getRegion()); -// event.setIntersectionID(first.getIntersectionID()); -// event.setSignalGroup(firstState.getSignalGroup()); -// event.setFirstSpatTimestamp(first.getTimestamp()); -// event.setSecondSpatTimestamp(second.getTimestamp()); -// event.setFirstConflictingTimemark(firstState.getMaxEndTime()); -// event.setSecondConflictingTimemark(secondState.getMaxEndTime()); - -// context().forward(new Record<>(key, event, event.getFirstSpatTimestamp())); - -// } -// if((firstState.getMinEndTime() != secondState.getMaxEndTime()) && isStateClearance(firstState.getEventState())){ -// TimeChangeDetailsEvent event = new TimeChangeDetailsEvent(); -// event.setRoadRegulatorID(first.getRegion()); -// event.setIntersectionID(first.getIntersectionID()); -// event.setSignalGroup(firstState.getSignalGroup()); -// event.setFirstSpatTimestamp(first.getTimestamp()); -// event.setSecondSpatTimestamp(second.getTimestamp()); -// event.setFirstConflictingTimemark(firstState.getMinEndTime()); -// event.setSecondConflictingTimemark(secondState.getMaxEndTime()); - -// context().forward(new Record<>(key, event, event.getFirstSpatTimestamp())); -// } - -// break; -// } -// } -// if(firstState.getMaxEndTime() != firstState.getMinEndTime() && isStateClearance(firstState.getEventState())){ -// TimeChangeDetailsEvent event = new TimeChangeDetailsEvent(); -// event.setRoadRegulatorID(first.getRegion()); -// event.setIntersectionID(first.getIntersectionID()); -// event.setSignalGroup(firstState.getSignalGroup()); -// event.setFirstSpatTimestamp(first.getTimestamp()); -// event.setSecondSpatTimestamp(first.getTimestamp()); -// event.setFirstConflictingTimemark(firstState.getMaxEndTime()); -// event.setSecondConflictingTimemark(firstState.getMinEndTime()); - -// context().forward(new Record<>(key, event, event.getFirstSpatTimestamp())); -// } -// } -// } -// } - - -// } else { -// agg = new SpatTimeChangeDetailAggregator(this.parameters.getJitterBufferSize()); -// agg.add(SpatTimeChangeDetail.fromProcessedSpat(inputSpat)); -// stateStore.put(key, agg); -// } -// } - -// public boolean isStateClearance(J2735MovementPhaseState state){ -// return state.equals(J2735MovementPhaseState.PERMISSIVE_CLEARANCE) || state.equals(J2735MovementPhaseState.PROTECTED_CLEARANCE); -// } - - -// } \ No newline at end of file diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/SpatSequenceProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/SpatSequenceProcessor.java index d65a136b..3afcb294 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/SpatSequenceProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/SpatSequenceProcessor.java @@ -1,29 +1,19 @@ package us.dot.its.jpo.conflictmonitor.monitor.processors; -import java.time.Duration; - -import org.apache.kafka.streams.KeyValue; import org.apache.kafka.streams.processor.api.ContextualProcessor; import org.apache.kafka.streams.processor.api.ProcessorContext; import org.apache.kafka.streams.processor.api.Record; -import org.apache.kafka.streams.state.KeyValueIterator; import org.apache.kafka.streams.state.KeyValueStore; -import org.apache.kafka.streams.state.TimestampedKeyValueStore; -import org.apache.kafka.streams.state.ValueAndTimestamp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsParameters; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmEvent; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmTimestampExtractor; import us.dot.its.jpo.conflictmonitor.monitor.models.events.TimeChangeDetailsEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetail; import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetailAggregator; import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetailPair; import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetailState; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; import us.dot.its.jpo.ode.plugin.j2735.J2735MovementPhaseState; diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/JsonSerdes.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/JsonSerdes.java index 0f3a0784..97f74e2f 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/JsonSerdes.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/JsonSerdes.java @@ -53,15 +53,9 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.broadcast_rate.MapBroadcastRateNotification; import us.dot.its.jpo.conflictmonitor.monitor.models.assessments.Assessment; import us.dot.its.jpo.conflictmonitor.monitor.models.events.Event; -import us.dot.its.jpo.ode.model.OdeBsmData; + public class JsonSerdes { - - public static Serde OdeBsm() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(OdeBsmData.class)); - } public static Serde BsmDataAggregator() { return Serdes.serdeFrom( diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/ConflictTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/ConflictTopology.java deleted file mode 100644 index 51abd06b..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/ConflictTopology.java +++ /dev/null @@ -1,112 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.topologies; - -import java.time.format.DateTimeFormatter; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; - - -public class ConflictTopology { - - public static Topology build(String mapGeoJsonTopic, String spatGeoJsonTopic) { - StreamsBuilder builder = new StreamsBuilder(); - DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME; - - - - // GeoJson Input Spat Stream - // KStream geoJsonSpatStream = - // builder.stream( - // spatGeoJsonTopic, - // Consumed.with( - // Serdes.String(), - // us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.SpatGeoJson()) - // ); - - //geoJsonSpatStream.print(Printed.toSysOut()); - - // BSM Input Stream - // KStream bsmJsonStream = - // builder.stream( - // "topic.OdeBsmJson", - // Consumed.with( - // Serdes.String(), - // JsonSerdes.OdeBsm()) - // ); - - //bsmJsonStream.print(Printed.toSysOut()); - - - // Group the BSM's by Key (Source IP) - // KGroupedStream bsmGroup = - // bsmJsonStream.groupByKey(); - - // Aggregate the BSM's using the BSM Aggregator - // Initializer bsmAggregatorInitializer = BsmAggregator::new; - - // Aggregator currentBsmAdder = - // (key, value, aggregate) -> aggregate.add(value); - - // Aggregator currentBsmSubtractor = - // (key, value, aggregate) -> aggregate.subtract(value); - - - // KTable bsmtable = - // bsmGroup.aggregate( - // bsmAggregatorInitializer, - // currentBsmAdder, - // Materialized.>as("current-bsms") - // .withKeySerde(Serdes.String()) - // .withValueSerde(JsonSerdes.BsmDataAggregator()) - // ); - - - // - // KStream windowedStream = builder.stream( - // "topic.OdeBsmJson", - // Consumed.with(Serdes.String(), JsonSerdes.OdeBsm())) - // .groupByKey() - // .windowedBy(SessionWindows.with(Duration.ofSeconds(10)).grace(Duration.ofSeconds(5))) - // // .aggregate( - // // bsmAggregatorInitializer, - // // currentBsmAdder, - // // Materialized.>as("current-bsms") - // // .withKeySerde(Serdes.String()) - // // .withValueSerde(JsonSerdes.BsmDataAggregator()) - // // ) - - // .count() - // //.suppress(Suppressed.untilWindowCloses(BufferConfig.unbounded().shutDownWhenFull())) - // .toStream() - // .map((windowedKey, count)->{ - // //String start = timeFormatter.format(windowedKey.window().startTime()); - // //String end = timeFormatter.format(windowedKey.window().endTime()); - // //String sessionInfo = String.format("Session info started: %s ended: %s with count %s", start, end, count); - // String sessionInfo = "StartTime" + windowedKey.window().startTime() +"EndTime: "+ windowedKey.window().endTime()+ " Count: " + count; - // return KeyValue.pair(windowedKey.key(), sessionInfo); - // }) - // ; - - // windowedStream.print(Printed.toSysOut()); - - - //bsmtable.toStream().print(Printed.toSysOut()); - - - // Join Input BSM Stream with Stream of Spat Messages - // KStream spatJoinedBsms = - // geoJsonSpatStream.leftJoin(bsmtable, (spatGeoJson, bsmAggregator) -> { - - - // return null; - // }, - // Joined.as("spat-joined-bsms").withKeySerde(Serdes.String()) - // .withValueSerde(us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.SpatGeoJson()).withOtherValueSerde(JsonSerdes.BsmDataAggregator())); - - return builder.build(); - } -} - - - - - diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java index fd4e2ee1..af2b4fd8 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MessageIngestTopology.java @@ -39,7 +39,7 @@ import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -//import us.dot.its.jpo.ode.model.OdeBsmData; + import java.time.Duration; diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java index 0a7dc0e6..4c52b1cc 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/BsmUtils.java @@ -5,15 +5,7 @@ import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.model.OdeBsmMetadata; -import us.dot.its.jpo.ode.model.OdeBsmPayload; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; -import us.dot.its.jpo.ode.plugin.j2735.J2735BsmCoreData; -import us.dot.its.jpo.ode.plugin.j2735.OdePosition3D; -import java.time.Instant; -import java.time.format.DateTimeParseException; import java.util.Optional; @Slf4j @@ -56,29 +48,6 @@ public static Optional getProperties(ProcessedBsm processedBsm return Optional.of(properties); } - - - public static CoordinateXY getPosition(OdeBsmData bsm) { - CoordinateXY position = new CoordinateXY(); - Optional optionalCoreData = getCoreData(bsm); - if (optionalCoreData.isEmpty()) return position; - J2735BsmCoreData coreData = optionalCoreData.get(); - OdePosition3D pos = coreData.getPosition(); - if (pos == null) return position; - position.setX(pos.getLongitude() != null ? pos.getLongitude().doubleValue() : 0.0); - position.setY(pos.getLatitude() != null ? pos.getLatitude().doubleValue() : 0.0); - return position; - } - - public static Optional getHeading(OdeBsmData bsm) { - Optional optionalCoreData = getCoreData(bsm); - if (optionalCoreData.isEmpty()) return Optional.empty(); - J2735BsmCoreData coreData = optionalCoreData.get(); - if (coreData.getHeading() == null) return Optional.empty(); - double vehicleHeading = coreData.getHeading().doubleValue(); - return Optional.of(vehicleHeading); - } - public static Optional getHeading(ProcessedBsm processedBsm) { Optional optProps = getProperties(processedBsm); if (optProps.isEmpty()) return Optional.empty(); @@ -88,33 +57,6 @@ public static Optional getHeading(ProcessedBsm processedBsm) { return Optional.of(vehicleHeading); } - public static Optional getJ2735Bsm(OdeBsmData bsm) { - if (bsm == null) return Optional.empty(); - if (bsm.getPayload() == null) return Optional.empty(); - if (!(bsm.getPayload() instanceof OdeBsmPayload)) return Optional.empty(); - var payload = (OdeBsmPayload)bsm.getPayload(); - if (payload.getBsm() == null) return Optional.empty(); - return Optional.of(payload.getBsm()); - } - - public static Optional getCoreData(OdeBsmData bsm) { - Optional optionalBsm = getJ2735Bsm(bsm); - if (optionalBsm.isEmpty()) return Optional.empty(); - J2735Bsm j2735Bsm = optionalBsm.get(); - if (j2735Bsm.getCoreData() == null) return Optional.empty(); - return Optional.of(j2735Bsm.getCoreData()); - } - - public static Optional getSpeedMPH(OdeBsmData bsm) { - Optional optionalCoreData = getCoreData(bsm); - if (optionalCoreData.isEmpty()) return Optional.empty(); - J2735BsmCoreData coreData = optionalCoreData.get(); - if (coreData.getSpeed() == null) return Optional.empty(); - double speedMetersPerSecond = coreData.getSpeed().doubleValue(); - double speedMPH = speedMetersPerSecond * 2.23694; // convert m/s to mph - return Optional.of(speedMPH); - } - public static Optional getSpeedMPH(ProcessedBsm processedBsm) { Optional optProps = getProperties(processedBsm); if (optProps.isEmpty()) return Optional.empty(); @@ -125,13 +67,6 @@ public static Optional getSpeedMPH(ProcessedBsm processedBsm) { return Optional.of(speedMPH); } - public static String getVehicleId(OdeBsmData bsm) { - Optional optionalCoreData = getCoreData(bsm); - if (optionalCoreData.isEmpty()) return ""; - J2735BsmCoreData coreData = optionalCoreData.get(); - return coreData.getId(); - } - public static String getVehicleId(ProcessedBsm processedBsm) { Optional optProps = getProperties(processedBsm); if (optProps.isEmpty()) return ""; @@ -139,26 +74,4 @@ public static String getVehicleId(ProcessedBsm processedBsm) { return props.getId(); } - public static String getRsuIp(OdeBsmData bsm) { - String ip = ""; - if (bsm.getMetadata() != null && bsm.getMetadata() instanceof OdeBsmMetadata) { - var metadata = (OdeBsmMetadata) bsm.getMetadata(); - ip = metadata.getOriginIp(); - } - return ip; - } - - public static long getOdeReceivedAt(OdeBsmData bsm) { - long odeReceivedAt = 0; - if (bsm != null && bsm.getMetadata() != null && bsm.getMetadata() instanceof OdeBsmMetadata metadata) { - String strOdeReceivedAt = metadata.getOdeReceivedAt(); - assert(strOdeReceivedAt != null); - try { - odeReceivedAt = Instant.parse(strOdeReceivedAt).toEpochMilli(); - } catch (DateTimeParseException ex) { - log.error(String.format("Error parsing odeReceivedAt: %s", strOdeReceivedAt), ex); - } - } - return odeReceivedAt; - } } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java index 18de8eae..29e980a8 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/testutils/BsmTestUtils.java @@ -3,12 +3,6 @@ import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.model.OdeBsmMetadata; -import us.dot.its.jpo.ode.model.OdeBsmPayload; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; -import us.dot.its.jpo.ode.plugin.j2735.J2735BsmCoreData; -import us.dot.its.jpo.ode.plugin.j2735.OdePosition3D; import java.math.BigDecimal; import java.time.*; @@ -27,19 +21,6 @@ public static int milliOfMinute(Instant instant) { return (int)minDuration.toMillis(); } - public static OdeBsmData bsmAtInstant(Instant instant, String id) { - var bsm = validBsm(); - var coreData = ((J2735Bsm)bsm.getPayload().getData()).getCoreData(); - var metadata = (OdeBsmMetadata)bsm.getMetadata(); - ZonedDateTime zdt = instant.atZone(ZoneOffset.UTC); - var strDateTime = DateTimeFormatter.ISO_DATE_TIME.format(zdt); - metadata.setOdeReceivedAt(strDateTime); - metadata.setRecordGeneratedAt(strDateTime); - coreData.setSecMark(milliOfMinute(instant)); - coreData.setId(id); - return bsm; - } - public static ProcessedBsm processedBsmAtInstant(Instant instant, String id) { var bsm = validProcessedBsm(); ZonedDateTime zdt = instant.atZone(ZoneOffset.UTC); @@ -52,17 +33,6 @@ public static ProcessedBsm processedBsmAtInstant(Instant instant, String return bsm; } - public static OdeBsmData bsmWithPosition(Instant instant, String id, double longitude, double latitude, double elevation) { - var bsm = bsmAtInstant(instant, id); - var coreData = ((J2735Bsm)bsm.getPayload().getData()).getCoreData(); - var lon = BigDecimal.valueOf(longitude); - var lat = BigDecimal.valueOf(latitude); - var el = BigDecimal.valueOf(elevation); - var position = new OdePosition3D(lat, lon, el); - coreData.setPosition(position); - return bsm; - } - public static ProcessedBsm processedBsmWithPosition(Instant instant, String id, double longitude, double latitude, double elevation) { var bsm = processedBsmAtInstant(instant, id); var coords = bsm.getGeometry().getCoordinates(); @@ -71,33 +41,6 @@ public static ProcessedBsm processedBsmWithPosition(Instant instant, Stri return bsm; } - public static OdeBsmData validBsm() { - final var bsm = new OdeBsmData(); - final var payload = new OdeBsmPayload(); - final var data = new J2735Bsm(); - final var coreData = new J2735BsmCoreData(); - final var position = new OdePosition3D(); - final var metadata = new OdeBsmMetadata(); - position.setLatitude(BigDecimal.valueOf(40.0)); - position.setLongitude(BigDecimal.valueOf(-105)); - position.setElevation(BigDecimal.valueOf(1600)); - coreData.setPosition(position); - coreData.setId("id"); - coreData.setSecMark(1000); - coreData.setSpeed(BigDecimal.valueOf(50)); - coreData.setHeading(BigDecimal.valueOf(90)); - data.setCoreData(coreData); - payload.setData(data); - bsm.setPayload(payload); - metadata.setBsmSource(OdeBsmMetadata.BsmSource.unknown); - metadata.setOriginIp("127.0.0.1"); - metadata.setRecordGeneratedAt("2020-01-01T00:00:00.000Z"); - bsm.setMetadata(metadata); - - return bsm; - } - - @SuppressWarnings("unchecked") public static ProcessedBsm validProcessedBsm() { final Point geometry = new Point(-105, 40.0); final BsmProperties properties = new BsmProperties(); diff --git a/jpo-deduplicator/Dockerfile b/jpo-deduplicator/Dockerfile deleted file mode 100644 index 5e80b808..00000000 --- a/jpo-deduplicator/Dockerfile +++ /dev/null @@ -1,65 +0,0 @@ -FROM maven:3.8-eclipse-temurin-21-alpine as builder - -WORKDIR /home - -# Copy only the files needed to avoid putting all sorts of junk from your local env on to the image -COPY ../jpo-geojsonconverter/jpo-ode/pom.xml ./jpo-ode/ -COPY ../jpo-geojsonconverter/jpo-ode/jpo-ode-common/pom.xml ./jpo-ode/jpo-ode-common/ -COPY ../jpo-geojsonconverter/jpo-ode/jpo-ode-common/src ./jpo-ode/jpo-ode-common/src -COPY ../jpo-geojsonconverter/jpo-ode/jpo-ode-plugins/pom.xml ./jpo-ode/jpo-ode-plugins/ -COPY ../jpo-geojsonconverter/jpo-ode/jpo-ode-plugins/src ./jpo-ode/jpo-ode-plugins/src -COPY ../jpo-geojsonconverter/jpo-ode/jpo-ode-core/pom.xml ./jpo-ode/jpo-ode-core/ -COPY ../jpo-geojsonconverter/jpo-ode/jpo-ode-core/src ./jpo-ode/jpo-ode-core/src/ -COPY ../jpo-geojsonconverter/jpo-ode/jpo-ode-svcs/pom.xml ./jpo-ode/jpo-ode-svcs/ -COPY ../jpo-geojsonconverter/jpo-ode/jpo-ode-svcs/src ./jpo-ode/jpo-ode-svcs/src - -COPY ../jpo-geojsonconverter/jpo-geojsonconverter/pom.xml ./jpo-geojsonconverter/ -COPY ../jpo-geojsonconverter/jpo-geojsonconverter/src ./jpo-geojsonconverter/src - -COPY ../jpo-conflictmonitor/pom.xml ./jpo-conflictmonitor/ -COPY ../jpo-conflictmonitor/src ./jpo-conflictmonitor/src - -COPY ./pom.xml ./jpo-deduplicator/ -COPY ./src ./jpo-deduplicator/src - -WORKDIR /home/jpo-ode - -RUN mvn install -DskipTests - -WORKDIR /home/jpo-geojsonconverter - -RUN mvn clean install -DskipTests - -WORKDIR /home/jpo-conflictmonitor - -RUN mvn clean install -DskipTests - -WORKDIR /home/jpo-deduplicator - -RUN mvn clean package -DskipTests -# ENTRYPOINT ["tail", "-f", "/dev/null"] - -FROM amazoncorretto:21 - -WORKDIR /home - -COPY --from=builder /home/jpo-conflictvisualizer-api/src/main/resources/application.yaml /home -COPY --from=builder /home/jpo-conflictvisualizer-api/src/main/resources/logback.xml /home -COPY --from=builder /home/jpo-conflictvisualizer-api/target/jpo-deduplicator.jar /home - -#COPY cert.crt /home/cert.crt -#RUN keytool -import -trustcacerts -keystore /usr/local/openjdk-11/lib/security/cacerts -storepass changeit -noprompt -alias mycert -file cert.crt - -ENTRYPOINT ["java", \ - "-Djava.rmi.server.hostname=$DOCKER_HOST_IP", \ - "-Dcom.sun.management.jmxremote.port=9090", \ - "-Dcom.sun.management.jmxremote.rmi.port=9090", \ - "-Dcom.sun.management.jmxremote", \ - "-Dcom.sun.management.jmxremote.local.only=true", \ - "-Dcom.sun.management.jmxremote.authenticate=false", \ - "-Dcom.sun.management.jmxremote.ssl=false", \ - "-Dlogback.configurationFile=/home/logback.xml", \ - "-jar", \ - "/home/jpo-deduplicator"] - -# ENTRYPOINT ["tail", "-f", "/dev/null"] diff --git a/jpo-deduplicator/LICENSE-2.0.html b/jpo-deduplicator/LICENSE-2.0.html deleted file mode 100644 index d1055c8a..00000000 --- a/jpo-deduplicator/LICENSE-2.0.html +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - Apache License, Version 2.0 - - -
- -

Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/

-

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND - DISTRIBUTION

-

1. - Definitions.

-

"License" shall mean the terms and conditions for use, - reproduction, and distribution as defined by Sections 1 through 9 - of this document.

-

"Licensor" shall mean the copyright owner or entity authorized - by the copyright owner that is granting the License.

-

"Legal Entity" shall mean the union of the acting entity and - all other entities that control, are controlled by, or are under - common control with that entity. For the purposes of this - definition, "control" means (i) the power, direct or indirect, to - cause the direction or management of such entity, whether by - contract or otherwise, or (ii) ownership of fifty percent (50%) - or more of the outstanding shares, or (iii) beneficial ownership - of such entity.

-

"You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License.

-

"Source" form shall mean the preferred form for making - modifications, including but not limited to software source code, - documentation source, and configuration files.

-

"Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but not - limited to compiled object code, generated documentation, and - conversions to other media types.

-

"Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work (an - example is provided in the Appendix below).

-

"Derivative Works" shall mean any work, whether in Source or - Object form, that is based on (or derived from) the Work and for - which the editorial revisions, annotations, elaborations, or - other modifications represent, as a whole, an original work of - authorship. For the purposes of this License, Derivative Works - shall not include works that remain separable from, or merely - link (or bind by name) to the interfaces of, the Work and - Derivative Works thereof.

-

"Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or - additions to that Work or Derivative Works thereof, that is - intentionally submitted to Licensor for inclusion in the Work by - the copyright owner or by an individual or Legal Entity - authorized to submit on behalf of the copyright owner. For the - purposes of this definition, "submitted" means any form of - electronic, verbal, or written communication sent to the Licensor - or its representatives, including but not limited to - communication on electronic mailing lists, source code control - systems, and issue tracking systems that are managed by, or on - behalf of, the Licensor for the purpose of discussing and - improving the Work, but excluding communication that is - conspicuously marked or otherwise designated in writing by the - copyright owner as "Not a Contribution."

-

"Contributor" shall mean Licensor and any individual or Legal - Entity on behalf of whom a Contribution has been received by - Licensor and subsequently incorporated within the Work.

-

2. Grant of - Copyright License. Subject to the terms and - conditions of this License, each Contributor hereby grants to You - a perpetual, worldwide, non-exclusive, no-charge, royalty-free, - irrevocable copyright license to reproduce, prepare Derivative - Works of, publicly display, publicly perform, sublicense, and - distribute the Work and such Derivative Works in Source or Object - form.

-

3. Grant of Patent - License. Subject to the terms and conditions of this - License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have - made, use, offer to sell, sell, import, and otherwise transfer - the Work, where such license applies only to those patent claims - licensable by such Contributor that are necessarily infringed by - their Contribution(s) alone or by combination of their - Contribution(s) with the Work to which such Contribution(s) was - submitted. If You institute patent litigation against any entity - (including a cross-claim or counterclaim in a lawsuit) alleging - that the Work or a Contribution incorporated within the Work - constitutes direct or contributory patent infringement, then any - patent licenses granted to You under this License for that Work - shall terminate as of the date such litigation is filed.

-

4. - Redistribution. You may reproduce and distribute - copies of the Work or Derivative Works thereof in any medium, - with or without modifications, and in Source or Object form, - provided that You meet the following conditions:

-
    -
  1. You must give any other recipients of the Work or - Derivative Works a copy of this License; and
  2. -
  3. You must cause any modified files to carry prominent - notices stating that You changed the files; and
  4. -
  5. You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, excluding - those notices that do not pertain to any part of the Derivative - Works; and
  6. -
  7. If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute - must include a readable copy of the attribution notices - contained within such NOTICE file, excluding those notices that - do not pertain to any part of the Derivative Works, in at least - one of the following places: within a NOTICE text file - distributed as part of the Derivative Works; within the Source - form or documentation, if provided along with the Derivative - Works; or, within a display generated by the Derivative Works, - if and wherever such third-party notices normally appear. The - contents of the NOTICE file are for informational purposes only - and do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed as - modifying the License.
    -
    - You may add Your own copyright statement to Your modifications - and may provide additional or different license terms and - conditions for use, reproduction, or distribution of Your - modifications, or for any such Derivative Works as a whole, - provided Your use, reproduction, and distribution of the Work - otherwise complies with the conditions stated in this - License.
  8. -
-

5. - Submission of Contributions. Unless You explicitly - state otherwise, any Contribution intentionally submitted for - inclusion in the Work by You to the Licensor shall be under the - terms and conditions of this License, without any additional - terms or conditions. Notwithstanding the above, nothing herein - shall supersede or modify the terms of any separate license - agreement you may have executed with Licensor regarding such - Contributions.

-

6. - Trademarks. This License does not grant permission - to use the trade names, trademarks, service marks, or product - names of the Licensor, except as required for reasonable and - customary use in describing the origin of the Work and - reproducing the content of the NOTICE file.

-

7. Disclaimer - of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or - conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or - FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for - determining the appropriateness of using or redistributing the - Work and assume any risks associated with Your exercise of - permissions under this License.

-

8. Limitation - of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, - special, incidental, or consequential damages of any character - arising as a result of this License or out of the use or - inability to use the Work (including but not limited to damages - for loss of goodwill, work stoppage, computer failure or - malfunction, or any and all other commercial damages or losses), - even if such Contributor has been advised of the possibility of - such damages.

-

9. Accepting - Warranty or Additional Liability. While - redistributing the Work or Derivative Works thereof, You may - choose to offer, and charge a fee for, acceptance of support, - warranty, indemnity, or other liability obligations and/or rights - consistent with this License. However, in accepting such - obligations, You may act only on Your own behalf and on Your sole - responsibility, not on behalf of any other Contributor, and only - if You agree to indemnify, defend, and hold each Contributor - harmless for any liability incurred by, or claims asserted - against, such Contributor by reason of your accepting any such - warranty or additional liability.

-

END OF TERMS AND CONDITIONS

-

APPENDIX: How to apply the Apache License to your - work

-

To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a file - or class name and description of purpose be included on the same - "printed page" as the copyright notice for easier identification - within third-party archives.

-
-
Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-    
-
-
- - - diff --git a/jpo-deduplicator/docker-compose.yml b/jpo-deduplicator/docker-compose.yml deleted file mode 100644 index 3ce565c8..00000000 --- a/jpo-deduplicator/docker-compose.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: '3.9' -services: - deduplicator: - build: . - image: jpo-deduplicator:latest - restart: always - environment: - DOCKER_HOST_IP: ${DOCKER_HOST_IP} - KAFKA_BOOTSTRAP_SERVERS: ${KAFKA_BOOTSTRAP_SERVERS:?error} - spring.kafka.bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:?error} - healthcheck: - test: ["CMD", "java", "-version"] - interval: 10s - timeout: 10s - retries: 20 - logging: - options: - max-size: "10m" - max-file: "5" - deploy: - resources: - limits: - memory: 3G diff --git a/jpo-deduplicator/pom.xml b/jpo-deduplicator/pom.xml deleted file mode 100644 index 3a358e23..00000000 --- a/jpo-deduplicator/pom.xml +++ /dev/null @@ -1,294 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.1.3 - - - usdot.jpo.ode - jpo-deduplicator - 1.3.1 - jar - jpo-deduplicator - http://maven.apache.org - - UTF-8 - 29-SNAPSHOT - usdot-jpo-ode - https://sonarcloud.io - - Deduplicates Messages generated by Subcomponents of the ODE - 21 - - ^ - - - 0.8.11 - jacoco - reuseReports - ${project.basedir}/target/site/jacoco/jacoco.xml - java - - - - - org.springframework.boot - spring-boot-starter - - - org.apache.logging.log4j - log4j-to-slf4j - - - - - org.springframework.boot - spring-boot-starter-test - test - - - com.vaadin.external.google - android-json - - - - - - org.springframework.boot - spring-boot-devtools - runtime - - - org.springframework.boot - spring-boot-starter-data-rest - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.restdocs - spring-restdocs-mockmvc - test - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.springframework.boot - spring-boot-starter-websocket - - - org.springframework.kafka - spring-kafka - - - org.springframework.kafka - spring-kafka-test - test - - - - - usdot.jpo.ode - jpo-ode-core - 3.0.0 - - - usdot.jpo.ode - jpo-ode-plugins - 3.0.0 - - - usdot.jpo.ode - jpo-geojsonconverter - 1.4.2 - - - usdot.jpo.ode - jpo-conflictmonitor - 1.5.0 - - - junit - junit - 4.13.2 - test - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - - - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - test - - - org.mockito - mockito-core - 5.10.0 - test - - - - com.google.guava - guava - 33.0.0-jre - - - - - - - - org.projectlombok - lombok - 1.18.30 - - - - - - - - - false - - central - Central Repository - https://repo.maven.apache.org/maven2 - - - - - - ${project.artifactId} - - - org.sonarsource.scanner.maven - sonar-maven-plugin - 3.10.0.2594 - - - org.springframework.boot - spring-boot-maven-plugin - - @{argLine} - - - - build-info - - build-info - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.2.5 - - all - exit - - - - @{argLine} - -XX:+EnableDynamicAgentLoading - - - - - - org.apache.maven.surefire - surefire-junit47 - 3.2.5 - - - - - - org.jacoco - jacoco-maven-plugin - ${jacoco.version} - - - jacoco-initialize - - prepare-agent - - - - jacoco-site - package - - report - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.3.0 - - - - jar - - package - - - jpo-deduplicator - - - - - - - - org.apache.maven.plugins - maven-surefire-report-plugin - 3.2.5 - - - - diff --git a/jpo-deduplicator/sample.env b/jpo-deduplicator/sample.env deleted file mode 100644 index 174535fe..00000000 --- a/jpo-deduplicator/sample.env +++ /dev/null @@ -1,2 +0,0 @@ -export DOCKER_HOST_IP= -export KAFKA_BOOTSTRAP_SERVERS=${DOCKER_HOST_IP}:9092 diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorApplication.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorApplication.java deleted file mode 100644 index 6b483c9d..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorApplication.java +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************* - * Copyright 2018 572682 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package us.dot.its.jpo.deduplicator; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.MBeanRegistrationException; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; - -@SpringBootApplication -@EnableConfigurationProperties(DeduplicatorProperties.class) -public class DeduplicatorApplication { - - private static final Logger logger = LoggerFactory.getLogger(DeduplicatorApplication.class); - - static final int DEFAULT_NO_THREADS = 10; - static final String DEFAULT_SCHEMA = "default"; - - public static void main(String[] args) throws MalformedObjectNameException, InterruptedException, - InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { - - logger.info("Starting Message Deduplicator"); - SpringApplication.run(DeduplicatorApplication.class, args); - // MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - // SystemConfig mBean = new SystemConfig(DEFAULT_NO_THREADS, DEFAULT_SCHEMA); - // ObjectName name = new ObjectName("us.dot.its.jpo.geojson:type=SystemConfig"); - // mbs.registerMBean(mBean, name); - logger.info("Message Deduplicator has started"); - - } - - @Bean - CommandLineRunner init(DeduplicatorProperties geojsonProperties) { - return args -> { - }; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorProperties.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorProperties.java deleted file mode 100644 index c60f522d..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorProperties.java +++ /dev/null @@ -1,444 +0,0 @@ -/******************************************************************************* - * Copyright 2018 572682 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - ******************************************************************************/ -package us.dot.its.jpo.deduplicator; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Properties; -import java.util.UUID; - -import jakarta.annotation.PostConstruct; - -import org.apache.commons.lang3.SystemUtils; -import org.apache.kafka.clients.producer.ProducerConfig; -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.StreamsConfig; -import org.apache.kafka.streams.errors.LogAndContinueExceptionHandler; -import org.apache.kafka.streams.processor.LogAndSkipOnInvalidTimestamp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.info.BuildProperties; -import org.springframework.context.EnvironmentAware; -import org.springframework.core.env.Environment; - -import lombok.Getter; -import lombok.Setter; -import lombok.AccessLevel; -import us.dot.its.jpo.conflictmonitor.AlwaysContinueProductionExceptionHandler; -import us.dot.its.jpo.ode.eventlog.EventLogger; -import us.dot.its.jpo.ode.util.CommonUtils; - -// import us.dot.its.jpo.conflictmonitor.AlwaysContinueProductionExceptionHandler; - -@Getter -@Setter -@ConfigurationProperties -public class DeduplicatorProperties implements EnvironmentAware { - - private static final Logger logger = LoggerFactory.getLogger(DeduplicatorProperties.class); - - // Processed Map Configuration - private String kafkaTopicProcessedMap; - private String kafkaTopicDeduplicatedProcessedMap; - private boolean enableProcessedMapDeduplication; - private String kafkaStateStoreProcessedMapName = "ProcessedMap-store"; - - // Processed Map WKT Configuration - private String kafkaTopicProcessedMapWKT; - private String kafkaTopicDeduplicatedProcessedMapWKT; - private boolean enableProcessedMapWktDeduplication; - private String kafkaStateStoreProcessedMapWKTName = "ProcessedMapWKT-store"; - - // Ode Map Json Configuration - private String kafkaTopicOdeMapJson; - private String kafkaTopicDeduplicatedOdeMapJson; - private boolean enableOdeMapDeduplication; - private String kafkaStateStoreOdeMapJsonName = "OdeMapJson-store"; - - // Ode Tim Json Configuration - private String kafkaTopicOdeTimJson; - private String kafkaTopicDeduplicatedOdeTimJson; - private boolean enableOdeTimDeduplication; - private String kafkaStateStoreOdeTimJsonName = "OdeTimJson-store"; - - // Ode Raw Encoded Tim Json Configuration - private String kafkaTopicOdeRawEncodedTimJson; - private String kafkaTopicDeduplicatedOdeRawEncodedTimJson; - private boolean enableOdeRawEncodedTimDeduplication; - private String kafkaStateStoreOdeRawEncodedTimJsonName = "OdeRawEncodedTimJson-store"; - - //Ode BsmJson Configuration - private String kafkaTopicOdeBsmJson; - private String kafkaTopicDeduplicatedOdeBsmJson; - private boolean enableOdeBsmDeduplication; - private long odeBsmMaximumTimeDelta; - private double odeBsmMaximumPositionDelta; - private double odeBsmAlwaysIncludeAtSpeed; - private String kafkaStateStoreOdeBsmJsonName = "OdeBsmJson-store"; - - // Confluent Properties - private boolean confluentCloudEnabled = false; - private String confluentKey = null; - private String confluentSecret = null; - - // Processed SPaT Configuration - private String kafkaTopicProcessedSpat; - private String kafkaTopicDeduplicatedProcessedSpat; - private boolean enableProcessedSpatDeduplication; - private String kafkaStateStoreProcessedSpatName = "ProcessedSpat-store"; - - - private int lingerMs = 0; - - - - @Autowired - @Setter(AccessLevel.NONE) - private Environment env; - - /* - * General Properties - */ - private String version; - // public static final int OUTPUT_SCHEMA_VERSION = 6; - - @Setter(AccessLevel.NONE) - private String kafkaBrokers = null; - - private static final String DEFAULT_KAFKA_PORT = "9092"; - private static final String DEFAULT_CONNECT_PORT = "8083"; - - @Setter(AccessLevel.NONE) - private String hostId; - - // @Setter(AccessLevel.NONE) - // private String connectURL = null; - - // @Setter(AccessLevel.NONE) - // private String dockerHostIP = null; - - @Setter(AccessLevel.NONE) - private String kafkaBrokerIP = null; - - - // @Setter(AccessLevel.NONE) - // private String dbHostIP = null; - - - @Setter(AccessLevel.NONE) - @Autowired - BuildProperties buildProperties; - - @PostConstruct - void initialize() { - setVersion(buildProperties.getVersion()); - logger.info("groupId: {}", buildProperties.getGroup()); - logger.info("artifactId: {}", buildProperties.getArtifact()); - logger.info("version: {}", version); - //OdeMsgMetadata.setStaticSchemaVersion(OUTPUT_SCHEMA_VERSION); - - - - String hostname; - try { - hostname = InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException e) { - // Let's just use a random hostname - hostname = UUID.randomUUID().toString(); - logger.info("Unknown host error: {}, using random", e); - } - hostId = hostname; - logger.info("Host ID: {}", hostId); - EventLogger.logger.info("Initializing services on host {}", hostId); - - // if(dbHostIP == null){ - // String dbHost = CommonUtils.getEnvironmentVariable("MONGO_IP"); - - // if(dbHost == null){ - // logger.warn( - // "DB Host IP not defined, Defaulting to localhost."); - // dbHost = "localhost"; - // } - // dbHostIP = dbHost; - // } - - if (kafkaBrokers == null) { - - String kafkaBrokers = CommonUtils.getEnvironmentVariable("KAFKA_BOOTSTRAP_SERVERS"); - - logger.info("ode.kafkaBrokers property not defined. Will try KAFKA_BOOTSTRAP_SERVERS => {}", kafkaBrokers); - - if (kafkaBrokers == null) { - logger.warn( - "Neither ode.kafkaBrokers ode property nor KAFKA_BOOTSTRAP_SERVERS environment variable are defined. Defaulting to localhost:9092"); - kafkaBrokers = "localhost:9092"; - } - - } - - String kafkaType = CommonUtils.getEnvironmentVariable("KAFKA_TYPE"); - if (kafkaType != null) { - confluentCloudEnabled = kafkaType.equals("CONFLUENT"); - if (confluentCloudEnabled) { - - System.out.println("Enabling Confluent Cloud Integration"); - - confluentKey = CommonUtils.getEnvironmentVariable("CONFLUENT_KEY"); - confluentSecret = CommonUtils.getEnvironmentVariable("CONFLUENT_SECRET"); - } - } - - // Initialize the Kafka Connect URL - // if (connectURL == null) { - // String connectURL = CommonUtils.getEnvironmentVariable("CONNECT_URL"); - // if (connectURL == null) { - // connectURL = String.format("http://%s:%s", "localhost", DEFAULT_CONNECT_PORT); - // } - // } - - // List asList = Arrays.asList(this.getKafkaTopicsDisabled()); - // logger.info("Disabled Topics: {}", asList); - // kafkaTopicsDisabledSet.addAll(asList); - } - - public Properties createStreamProperties(String name) { - Properties streamProps = new Properties(); - streamProps.put(StreamsConfig.APPLICATION_ID_CONFIG, name); - - streamProps.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaBrokers); - - streamProps.put(StreamsConfig.DEFAULT_DESERIALIZATION_EXCEPTION_HANDLER_CLASS_CONFIG, - LogAndContinueExceptionHandler.class.getName()); - - streamProps.put(StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, - LogAndSkipOnInvalidTimestamp.class.getName()); - - streamProps.put(StreamsConfig.DEFAULT_PRODUCTION_EXCEPTION_HANDLER_CLASS_CONFIG, - AlwaysContinueProductionExceptionHandler.class.getName()); - - streamProps.put(StreamsConfig.NUM_STREAM_THREADS_CONFIG, 2); - - // streamProps.put(StreamsConfig.producerPrefix("acks"), "all"); - streamProps.put(StreamsConfig.producerPrefix(ProducerConfig.ACKS_CONFIG), "all"); - - // Reduce cache buffering per topology to 1MB - streamProps.put(StreamsConfig.STATESTORE_CACHE_MAX_BYTES_CONFIG, 1 * 1024 * 1024L); - - // Decrease default commit interval. Default for 'at least once' mode of 30000ms - // is too slow. - streamProps.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 100); - - // All the keys are Strings in this app - streamProps.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName()); - - // Configure the state store location - if (SystemUtils.IS_OS_LINUX) { - streamProps.put(StreamsConfig.STATE_DIR_CONFIG, "/var/lib/ode/kafka-streams"); - } else if (SystemUtils.IS_OS_WINDOWS) { - streamProps.put(StreamsConfig.STATE_DIR_CONFIG, "C:/temp/ode"); - } - // streamProps.put(StreamsConfig.STATE_DIR_CONFIG, "/var/lib/")\ - - // Increase max.block.ms and delivery.timeout.ms for streams - final int FIVE_MINUTES_MS = 5 * 60 * 1000; - streamProps.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, FIVE_MINUTES_MS); - streamProps.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, FIVE_MINUTES_MS); - - // Disable batching - // streamProps.put(ProducerConfig.BATCH_SIZE_CONFIG, 0); - - streamProps.put(ProducerConfig.COMPRESSION_TYPE_CONFIG, "zstd"); - streamProps.put(ProducerConfig.LINGER_MS_CONFIG, getKafkaLingerMs()); - - if (confluentCloudEnabled) { - streamProps.put("ssl.endpoint.identification.algorithm", "https"); - streamProps.put("security.protocol", "SASL_SSL"); - streamProps.put("sasl.mechanism", "PLAIN"); - - if (confluentKey != null && confluentSecret != null) { - String auth = "org.apache.kafka.common.security.plain.PlainLoginModule required " + - "username=\"" + confluentKey + "\" " + - "password=\"" + confluentSecret + "\";"; - streamProps.put("sasl.jaas.config", auth); - } - else { - logger.error("Environment variables CONFLUENT_KEY and CONFLUENT_SECRET are not set. Set these in the .env file to use Confluent Cloud"); - } - } - - - return streamProps; - } - - public String getProperty(String key) { - return env.getProperty(key); - } - - public String getProperty(String key, String defaultValue) { - return env.getProperty(key, defaultValue); - } - - public Object getProperty(String key, int i) { - return env.getProperty(key, Integer.class, i); - } - - public Boolean getConfluentCloudStatus() { - return confluentCloudEnabled; - } - - - @Value("${kafkaTopicProcessedMap}") - public void setKafkaTopicProcessedMap(String kafkaTopicProcessedMap) { - this.kafkaTopicProcessedMap = kafkaTopicProcessedMap; - } - - @Value("${kafkaTopicDeduplicatedProcessedMap}") - public void setKafkaTopicDeduplicatedProcessedMap(String kafkaTopicDeduplicatedProcessedMap) { - this.kafkaTopicDeduplicatedProcessedMap = kafkaTopicDeduplicatedProcessedMap; - } - - @Value("${enableProcessedMapDeduplication}") - public void setEnableProcessedMapDeduplication(boolean enableProcessedMapDeduplication) { - this.enableProcessedMapDeduplication = enableProcessedMapDeduplication; - } - - @Value("${kafkaTopicProcessedMapWKT}") - public void setKafkaTopicProcessedMapWKT(String kafkaTopicProcessedMapWKT) { - this.kafkaTopicProcessedMapWKT = kafkaTopicProcessedMapWKT; - } - - @Value("${kafkaTopicDeduplicatedProcessedMapWKT}") - public void setKafkaTopicDeduplicatedProcessedMapWKT(String kafkaTopicDeduplicatedProcessedMapWKT) { - this.kafkaTopicDeduplicatedProcessedMapWKT = kafkaTopicDeduplicatedProcessedMapWKT; - } - - @Value("${enableProcessedMapWktDeduplication}") - public void setEnableProcessedMapWktDeduplication(boolean enableProcessedMapWktDeduplication) { - this.enableProcessedMapWktDeduplication = enableProcessedMapWktDeduplication; - } - - @Value("${kafkaTopicOdeMapJson}") - public void setKafkaTopicOdeMapJson(String kafkaTopicOdeMapJson) { - this.kafkaTopicOdeMapJson = kafkaTopicOdeMapJson; - } - - @Value("${kafkaTopicDeduplicatedOdeMapJson}") - public void setKafkaTopicDeduplicatedOdeMapJson(String kafkaTopicDeduplicatedOdeMapJson) { - this.kafkaTopicDeduplicatedOdeMapJson = kafkaTopicDeduplicatedOdeMapJson; - } - - @Value("${enableOdeMapDeduplication}") - public void setEnableOdeMapDeduplication(boolean enableOdeMapDeduplication) { - this.enableOdeMapDeduplication = enableOdeMapDeduplication; - } - - @Value("${kafkaTopicOdeTimJson}") - public void setKafkaTopicOdeTimJson(String kafkaTopicOdeTimJson) { - this.kafkaTopicOdeTimJson = kafkaTopicOdeTimJson; - } - - @Value("${kafkaTopicDeduplicatedOdeTimJson}") - public void setKafkaTopicDeduplicatedOdeTimJson(String kafkaTopicDeduplicatedOdeTimJson) { - this.kafkaTopicDeduplicatedOdeTimJson = kafkaTopicDeduplicatedOdeTimJson; - } - - @Value("${enableOdeTimDeduplication}") - public void setEnableOdeTimDeduplication(boolean enableOdeTimDeduplication) { - this.enableOdeTimDeduplication = enableOdeTimDeduplication; - } - - @Value("${kafkaTopicOdeRawEncodedTimJson}") - public void setKafkaTopicOdeRawEncodedTimJson(String kafkaTopicOdeRawEncodedTimJson) { - this.kafkaTopicOdeRawEncodedTimJson = kafkaTopicOdeRawEncodedTimJson; - } - - @Value("${kafkaTopicDeduplicatedOdeRawEncodedTimJson}") - public void setKafkaTopicDeduplicatedOdeRawEncodedTimJson(String kafkaTopicDeduplicatedOdeRawEncodedTimJson) { - this.kafkaTopicDeduplicatedOdeRawEncodedTimJson = kafkaTopicDeduplicatedOdeRawEncodedTimJson; - } - - @Value("${enableOdeRawEncodedTimDeduplication}") - public void setEnableOdeRawEncodedTimDeduplication(boolean enableOdeRawEncodedTimDeduplication) { - this.enableOdeRawEncodedTimDeduplication = enableOdeRawEncodedTimDeduplication; - } - - @Value("${kafkaTopicOdeBsmJson}") - public void setkafkaTopicOdeBsmJson(String kafkaTopicOdeBsmJson) { - this.kafkaTopicOdeBsmJson = kafkaTopicOdeBsmJson; - } - - @Value("${kafkaTopicDeduplicatedOdeBsmJson}") - public void setkafkaTopicDeduplicatedOdeBsmJson(String kafkaTopicDeduplicatedOdeBsmJson) { - this.kafkaTopicDeduplicatedOdeBsmJson = kafkaTopicDeduplicatedOdeBsmJson; - } - - @Value("${enableOdeBsmDeduplication}") - public void setenableOdeBsmDeduplication(boolean enableOdeBsmDeduplication) { - this.enableOdeBsmDeduplication = enableOdeBsmDeduplication; - } - - @Value("${odeBsmMaximumTimeDelta}") - public void setMaximumTimeDelta(long maximumTimeDelta) { - this.odeBsmMaximumTimeDelta = maximumTimeDelta; - } - - @Value("${odeBsmMaximumPositionDelta}") - public void setMaximumPositionDelta(double maximumPositionDelta) { - this.odeBsmMaximumPositionDelta = maximumPositionDelta; - } - - @Value("${odeBsmAlwaysIncludeAtSpeed}") - public void setAlwaysIncludeAtSpeed(double alwaysIncludeAtSpeed) { - this.odeBsmAlwaysIncludeAtSpeed = alwaysIncludeAtSpeed; - } - - @Value("${spring.kafka.bootstrap-servers}") - public void setKafkaBrokers(String kafkaBrokers) { - this.kafkaBrokers = kafkaBrokers; - } - - @Value("${kafkaTopicProcessedSpat}") - public void setKafkaTopicProcessedSpat(String kafkaTopicProcessedSpat) { - this.kafkaTopicProcessedSpat = kafkaTopicProcessedSpat; - } - - @Value("${kafkaTopicDeduplicatedProcessedSpat}") - public void setKafkaTopicDeduplicatedProcessedSpat(String kafkaTopicDeduplicatedProcessedSpat) { - this.kafkaTopicDeduplicatedProcessedSpat = kafkaTopicDeduplicatedProcessedSpat; - } - - @Value("${enableProcessedSpatDeduplication}") - public void setEnableProcessedSpatDeduplication(boolean enableProcessedSpatDeduplication) { - this.enableProcessedSpatDeduplication = enableProcessedSpatDeduplication; - } - - @Override - public void setEnvironment(Environment environment) { - env = environment; - } - - @Value("${kafka.linger_ms}") - public void setKafkaLingerMs(int lingerMs) { - this.lingerMs = lingerMs; - } - - public int getKafkaLingerMs() { - return lingerMs; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/KafkaConfiguration.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/KafkaConfiguration.java deleted file mode 100644 index a5cac5f2..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/KafkaConfiguration.java +++ /dev/null @@ -1,197 +0,0 @@ -package us.dot.its.jpo.deduplicator; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import org.apache.kafka.clients.admin.NewTopic; -import org.apache.kafka.common.serialization.StringSerializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.kafka.config.TopicBuilder; -import org.springframework.kafka.core.DefaultKafkaProducerFactory; -import org.springframework.kafka.core.KafkaAdmin; -import org.springframework.kafka.core.KafkaAdmin.NewTopics; -import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.kafka.core.ProducerFactory; -import org.springframework.stereotype.Component; -import org.apache.kafka.clients.producer.ProducerConfig; - -@Component -@ConfigurationProperties(prefix = "kafka.topics") -public class KafkaConfiguration { - - @Autowired - private DeduplicatorProperties properties; - - @Bean(name = "createKafkaTopics") - public KafkaAdmin.NewTopics createKafkaTopics() { - logger.info("createTopic"); - List newTopics = new ArrayList<>(); - - if(!properties.getConfluentCloudStatus()){ - try { - for(var propEntry : admin.getConfigurationProperties().entrySet()) { - logger.info("KafkaAdmin property {} = {}", propEntry.getKey(), propEntry.getValue()); - } - - if (!autoCreateTopics) { - logger.info("Auto create topics is disabled"); - return null; - } - - logger.info("Creating topics: {}", createTopics); - - - - List topicNames = new ArrayList<>(); - for (var topic : createTopics) { - - // Get the name and config settings for the topic - String topicName = (String)topic.getOrDefault("name", null); - if (topicName == null) { - logger.error("CreateTopic {} has no topic name", topic); - break; - } - topicNames.add(topicName); - - Map topicConfigs = new HashMap<>(); - String cleanupPolicy = (String)topic.getOrDefault("cleanupPolicy", null); - if (cleanupPolicy != null) { - topicConfigs.put("cleanup.policy", cleanupPolicy); - } - Integer retentionMs = (Integer)topic.getOrDefault("retentionMs", null); - if (retentionMs != null) { - topicConfigs.put("retention.ms", retentionMs.toString()); - } - - NewTopic newTopic = TopicBuilder - .name(topicName) - .partitions(numPartitions) - .replicas(numReplicas) - .configs(topicConfigs) - .build(); - newTopics.add(newTopic); - logger.info("New Topic: {}", newTopic); - } - - // Explicitly create the topics here to prevent error on first run - admin.initialize(); - admin.createOrModifyTopics(newTopics.toArray(new NewTopic[0])); - - // Check that topics were created - var topicDescMap = admin.describeTopics(topicNames.toArray(new String[0])); - for (var entry : topicDescMap.entrySet()) { - String topicName = entry.getKey(); - var desc = entry.getValue(); - logger.info("Created topic {}: {}", topicName, desc); - } - - - } catch (Exception e) { - logger.error("Exception in createKafkaTopics", e); - throw e; - } - } - - // List out existing topics - // Admin adminClient = Admin.create(properties.createStreamProperties("DeduplicatorAdminClient")); - // ListTopicsOptions listTopicsOptions = new ListTopicsOptions().listInternal(true); - // ListTopicsResult topicsResult = adminClient.listTopics(listTopicsOptions); - // KafkaFuture> topicsFuture = topicsResult.names(); - // try { - // List topicNames = new ArrayList<>(); - // for(String topicName: topicsFuture.get()){ - // logger.info("Found Topic: " + topicName); - // topicNames.add(topicName); - // } - - // } catch (InterruptedException e) { - // logger.error("Interruption Exception in createKafkaTopics. Unable to List existing Topics", e); - // } catch (ExecutionException e) { - // logger.error("Execution Exception in createKafkaTopics. Unable to List existing Topics", e); - // } - - - return new NewTopics(newTopics.toArray(NewTopic[]::new)); - } - - @Bean - public ProducerFactory producerFactory() { - Properties configProps = properties.createStreamProperties("Deduplicator-producer-factory"); - - Map map = new HashMap<>(); - - for (Map.Entry entry : configProps.entrySet()) { - String key = (String) entry.getKey(); - Object value = entry.getValue(); - map.put(key, value); - } - - map.put( - ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, - StringSerializer.class); - map.put( - ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, - StringSerializer.class); - - return new DefaultKafkaProducerFactory(map); - } - - @Bean - public KafkaTemplate kafkaTemplate() { - return new KafkaTemplate<>(producerFactory()); - } - - private static final Logger logger = LoggerFactory.getLogger(KafkaConfiguration.class); - - private boolean autoCreateTopics; - private int numPartitions; - private int numReplicas; - private List> createTopics; - - public boolean getAutoCreateTopics() { - return autoCreateTopics; - } - - public void setAutoCreateTopics(boolean autoCreateTopics) { - this.autoCreateTopics = autoCreateTopics; - } - - public int getNumPartitions() { - return numPartitions; - } - - public int getNumReplicas() { - return numReplicas; - } - - public List> getCreateTopics() { - return createTopics; - } - - public void setNumPartitions(int numPartitions) { - this.numPartitions = numPartitions; - logger.info("kafka.topics.numPartitions = {}", numPartitions); - } - - public void setNumReplicas(int numReplicas) { - this.numReplicas = numReplicas; - } - - public void setCreateTopics(List> createTopics) { - this.createTopics = createTopics; - } - - - - @Autowired - private KafkaAdmin admin; - - - -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/StreamsExceptionHandler.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/StreamsExceptionHandler.java deleted file mode 100644 index 71132f3e..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/StreamsExceptionHandler.java +++ /dev/null @@ -1,56 +0,0 @@ -package us.dot.its.jpo.deduplicator; - -import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.kafka.core.KafkaTemplate; - - - -/** - * Handler for unhandled exceptions thrown from Streams topologies that - * logs the exception to a topic, and allows choosing the shutdown behavior. - * - * See {@link https://cwiki.apache.org/confluence/display/KAFKA/KIP-671%3A+Introduce+Kafka+Streams+Specific+Uncaught+Exception+Handler} - * for a description of the options. - */ -public class StreamsExceptionHandler implements StreamsUncaughtExceptionHandler { - - final static Logger logger = LoggerFactory.getLogger(StreamsExceptionHandler.class); - - final KafkaTemplate kafkaTemplate; - final String topology; - final String notificationTopic; - - @Autowired - public StreamsExceptionHandler(KafkaTemplate kafkaTemplate, String topology, String notificationTopic) { - this.kafkaTemplate = kafkaTemplate; - this.topology = topology; - this.notificationTopic = notificationTopic; - } - - @Override - public StreamThreadExceptionResponse handle(Throwable exception) { - try { - logger.error(String.format("Uncaught exception in stream topology %s", topology), exception); - } catch (Exception ex) { - logger.error("Exception sending kafka streams error event", ex); - } - - - // SHUTDOWN_CLIENT option shuts down quickly. - return StreamThreadExceptionResponse.SHUTDOWN_CLIENT; - - // SHUTDOWN_APPLICATION shuts down more slowly, but cleans up more thoroughly - //return StreamThreadExceptionResponse.SHUTDOWN_APPLICATION; - - // "Replace Thread" mode can be used to keep the streams client alive, - // however if the cause of the error was not transient, but due to a code error processing - // a record, it can result in the record being repeatedly processed throwing the - // same error - // - //return StreamThreadExceptionResponse.REPLACE_THREAD; - } - -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/DeduplicatorServiceController.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/DeduplicatorServiceController.java deleted file mode 100644 index 89b44dad..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/DeduplicatorServiceController.java +++ /dev/null @@ -1,107 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator; - -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.kafka.streams.KafkaStreams; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.DependsOn; -import org.springframework.context.annotation.Profile; -import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.stereotype.Controller; - -import lombok.Getter; -import us.dot.its.jpo.conflictmonitor.monitor.MonitorServiceController; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.BsmDeduplicatorTopology; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.MapDeduplicatorTopology; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.TimDeduplicatorTopology; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.OdeRawEncodedTimDeduplicatorTopology; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedMapDeduplicatorTopology; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedMapWktDeduplicatorTopology; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedSpatDeduplicatorTopology; - -@Controller -@DependsOn("createKafkaTopics") -@Profile("!test && !testConfig") -public class DeduplicatorServiceController { - - private static final Logger logger = LoggerFactory.getLogger(MonitorServiceController.class); - - // Temporary for KafkaStreams that don't implement the Algorithm interface - @Getter - final ConcurrentHashMap streamsMap = new ConcurrentHashMap(); - - @Getter - final ConcurrentHashMap algoMap = new ConcurrentHashMap(); - - - - @Autowired - public DeduplicatorServiceController(final DeduplicatorProperties props, - final KafkaTemplate kafkaTemplate) { - - - try { - - if(props.isEnableProcessedMapDeduplication()){ - ProcessedMapDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapDeduplicatorTopology( - props, - props.createStreamProperties("ProcessedMapDeduplicator") - ); - processedMapDeduplicatorTopology.start(); - } - - if(props.isEnableProcessedMapWktDeduplication()){ - ProcessedMapWktDeduplicatorTopology processedMapWktDeduplicatorTopology = new ProcessedMapWktDeduplicatorTopology( - props, - props.createStreamProperties("ProcessedMapWKTdeduplicator") - ); - processedMapWktDeduplicatorTopology.start(); - } - - if(props.isEnableProcessedMapDeduplication()){ - MapDeduplicatorTopology mapDeduplicatorTopology = new MapDeduplicatorTopology( - props, - props.createStreamProperties("MapDeduplicator") - ); - mapDeduplicatorTopology.start(); - } - - if(props.isEnableOdeTimDeduplication()){ - TimDeduplicatorTopology timDeduplicatorTopology = new TimDeduplicatorTopology( - props, - props.createStreamProperties("TimDeduplicator") - ); - timDeduplicatorTopology.start(); - } - - if(props.isEnableOdeRawEncodedTimDeduplication()){ - OdeRawEncodedTimDeduplicatorTopology odeRawEncodedTimDeduplicatorTopology = new OdeRawEncodedTimDeduplicatorTopology( - props, - props.createStreamProperties("OdeRawEncodedTimDeduplicator") - ); - odeRawEncodedTimDeduplicatorTopology.start(); - } - - if(props.isEnableProcessedSpatDeduplication()){ - ProcessedSpatDeduplicatorTopology processedSpatDeduplicatorTopology = new ProcessedSpatDeduplicatorTopology( - props, - props.createStreamProperties("ProcessedSpatDeduplicator") - ); - processedSpatDeduplicatorTopology.start(); - } - - if(props.isEnableOdeBsmDeduplication()){ - BsmDeduplicatorTopology bsmDeduplicatorTopology = new BsmDeduplicatorTopology(props); - bsmDeduplicatorTopology.start(); - } - - - } catch (Exception e) { - logger.error("Encountered issue with creating topologies", e); - } - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/JsonPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/JsonPair.java deleted file mode 100644 index d0f43773..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/JsonPair.java +++ /dev/null @@ -1,21 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.models; - -import com.fasterxml.jackson.databind.JsonNode; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@NoArgsConstructor -@Setter -@Getter -public class JsonPair { - - public JsonNode message; - public boolean shouldSend; - - public JsonPair(JsonNode message, boolean shouldSend){ - this.message = message; - this.shouldSend = shouldSend; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java deleted file mode 100644 index 208622b7..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java +++ /dev/null @@ -1,20 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.models; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import us.dot.its.jpo.ode.model.OdeBsmData; - -@NoArgsConstructor -@Setter -@Getter -public class OdeBsmPair { - - public OdeBsmData message; - public boolean shouldSend; - - public OdeBsmPair(OdeBsmData message, boolean shouldSend){ - this.message = message; - this.shouldSend = shouldSend; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeMapPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeMapPair.java deleted file mode 100644 index 24c265a3..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeMapPair.java +++ /dev/null @@ -1,20 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.models; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import us.dot.its.jpo.ode.model.OdeMapData; - -@NoArgsConstructor -@Setter -@Getter -public class OdeMapPair { - - public OdeMapData message; - public boolean shouldSend; - - public OdeMapPair(OdeMapData message, boolean shouldSend){ - this.message = message; - this.shouldSend = shouldSend; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/Pair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/Pair.java deleted file mode 100644 index fd0ee44a..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/Pair.java +++ /dev/null @@ -1,19 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.models; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@NoArgsConstructor -@Setter -@Getter -public class Pair { - - public T message; - public boolean shouldSend; - - public Pair(T message, boolean shouldSend){ - this.message = message; - this.shouldSend = shouldSend; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapPair.java deleted file mode 100644 index b1400c55..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapPair.java +++ /dev/null @@ -1,21 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.models; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; - -@NoArgsConstructor -@Setter -@Getter -public class ProcessedMapPair { - - public ProcessedMap message; - public boolean shouldSend; - - public ProcessedMapPair(ProcessedMap message, boolean shouldSend){ - this.message = message; - this.shouldSend = shouldSend; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapWktPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapWktPair.java deleted file mode 100644 index d6acacad..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapWktPair.java +++ /dev/null @@ -1,20 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.models; - -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; - -@NoArgsConstructor -@Setter -@Getter -public class ProcessedMapWktPair { - - public ProcessedMap message; - public boolean shouldSend; - - public ProcessedMapWktPair(ProcessedMap message, boolean shouldSend){ - this.message = message; - this.shouldSend = shouldSend; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/DeduplicationProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/DeduplicationProcessor.java deleted file mode 100644 index 55b669c4..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/DeduplicationProcessor.java +++ /dev/null @@ -1,69 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors; - -import java.time.Duration; -import java.time.Instant; - -import org.apache.kafka.streams.processor.PunctuationType; -import org.apache.kafka.streams.processor.api.Processor; -import org.apache.kafka.streams.processor.api.ProcessorContext; -import org.apache.kafka.streams.processor.api.Record; -import org.apache.kafka.streams.state.KeyValueStore; - -import org.apache.kafka.streams.state.KeyValueIterator; -import org.apache.kafka.streams.KeyValue; - -public abstract class DeduplicationProcessor implements Processor{ - - private ProcessorContext context; - private KeyValueStore store; - public String storeName; - - @Override - public void init(ProcessorContext context) { - this.context = context; - store = context.getStateStore(storeName); - this.context.schedule(Duration.ofHours(1), PunctuationType.WALL_CLOCK_TIME, this::cleanupOldKeys); - } - - @Override - public void process(Record record) { - - // Don't do anything if key is bad - if(record.key().equals("")){ - return; - } - - T lastRecord = store.get(record.key()); - if(lastRecord == null){ - store.put(record.key(), record.value()); - context.forward(record); - return; - } - - if(!isDuplicate(lastRecord, record.value())){ - store.put(record.key(), record.value()); - context.forward(record); - return; - } - } - - private void cleanupOldKeys(final long timestamp) { - try (KeyValueIterator iterator = store.all()) { - while (iterator.hasNext()) { - - KeyValue record = iterator.next(); - // Delete any record more than 2 hours old. - if(Instant.ofEpochMilli(timestamp).minusSeconds(2 * 60 * 60).isAfter(getMessageTime(record.value))){ - store.delete(record.key); - } - } - } - } - - // returns an instant representing the time of the message - public abstract Instant getMessageTime(T message); - - // returns if two messages are duplicates of one another - public abstract boolean isDuplicate(T lastMessage, T newMessage); - -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeBsmJsonProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeBsmJsonProcessor.java deleted file mode 100644 index 2197b23d..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeBsmJsonProcessor.java +++ /dev/null @@ -1,80 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors; - - -import java.time.Duration; -import java.time.Instant; -import java.time.format.DateTimeFormatter; - -import org.geotools.referencing.GeodeticCalculator; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.model.OdeBsmMetadata; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; -import us.dot.its.jpo.ode.plugin.j2735.J2735BsmCoreData; - -public class OdeBsmJsonProcessor extends DeduplicationProcessor{ - - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - DeduplicatorProperties props; - GeodeticCalculator calculator; - - public OdeBsmJsonProcessor(String storeName, DeduplicatorProperties props){ - this.storeName = storeName; - this.props = props; - calculator = new GeodeticCalculator(); - } - - - @Override - public Instant getMessageTime(OdeBsmData message) { - try { - String time = ((OdeBsmMetadata)message.getMetadata()).getOdeReceivedAt(); - return Instant.from(formatter.parse(time)); - } catch (Exception e) { - System.out.println("Failed to Parse Time"); - return Instant.ofEpochMilli(0); - } - } - - @Override - public boolean isDuplicate(OdeBsmData lastMessage, OdeBsmData newMessage) { - Instant newValueTime = getMessageTime(newMessage); - Instant oldValueTime = getMessageTime(lastMessage); - - // If the messages are more than a certain time apart, forward the new message on - if(newValueTime.minus(Duration.ofMillis(props.getOdeBsmMaximumTimeDelta())).isAfter(oldValueTime)){ - return false; - } - - J2735BsmCoreData oldCore = ((J2735Bsm)lastMessage.getPayload().getData()).getCoreData(); - J2735BsmCoreData newCore = ((J2735Bsm)newMessage.getPayload().getData()).getCoreData(); - - - // If the Vehicle is moving, forward the message on - if(newCore.getSpeed().doubleValue() > props.getOdeBsmAlwaysIncludeAtSpeed()){ - return false; - } - - - double distance = calculateGeodeticDistance( - newCore.getPosition().getLatitude().doubleValue(), - newCore.getPosition().getLongitude().doubleValue(), - oldCore.getPosition().getLatitude().doubleValue(), - oldCore.getPosition().getLongitude().doubleValue() - ); - - // If the position delta between the messages is suitable large, forward the message on - if(distance > props.getOdeBsmMaximumPositionDelta()){ - return false; - } - - return true; - } - - public double calculateGeodeticDistance(double lat1, double lon1, double lat2, double lon2) { - calculator.setStartingGeographicPoint(lon1, lat1); - calculator.setDestinationGeographicPoint(lon2, lat2); - return calculator.getOrthodromicDistance(); - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeMapJsonProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeMapJsonProcessor.java deleted file mode 100644 index adaf6db2..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeMapJsonProcessor.java +++ /dev/null @@ -1,70 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors; - -import java.time.Duration; -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Objects; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.ode.model.OdeMapData; -import us.dot.its.jpo.ode.model.OdeMapMetadata; -import us.dot.its.jpo.ode.model.OdeMapPayload; - -public class OdeMapJsonProcessor extends DeduplicationProcessor{ - - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - - DeduplicatorProperties props; - - public OdeMapJsonProcessor(DeduplicatorProperties props){ - this.props = props; - this.storeName = props.getKafkaStateStoreOdeMapJsonName(); - } - - - @Override - public Instant getMessageTime(OdeMapData message) { - try { - String time = ((OdeMapMetadata)message.getMetadata()).getOdeReceivedAt(); - return Instant.from(formatter.parse(time)); - } catch (Exception e) { - return Instant.ofEpochMilli(0); - } - } - - @Override - public boolean isDuplicate(OdeMapData lastMessage, OdeMapData newMessage) { - - Instant newValueTime = getMessageTime(newMessage); - Instant oldValueTime = getMessageTime(lastMessage); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return false; - - }else{ - OdeMapPayload oldPayload = (OdeMapPayload)lastMessage.getPayload(); - OdeMapPayload newPayload = (OdeMapPayload)newMessage.getPayload(); - - Integer oldTimestamp = oldPayload.getMap().getTimeStamp(); - Integer newTimestamp = newPayload.getMap().getTimeStamp(); - - - newPayload.getMap().setTimeStamp(oldTimestamp); - - int oldHash = hashMapMessage(lastMessage); - int newhash = hashMapMessage(newMessage); - - if(oldHash != newhash){ - newPayload.getMap().setTimeStamp(newTimestamp); - return false; - } - } - return true; - } - - public int hashMapMessage(OdeMapData map){ - OdeMapPayload payload = (OdeMapPayload)map.getPayload(); - return Objects.hash(payload.toJson()); - - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeRawEncodedTimJsonProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeRawEncodedTimJsonProcessor.java deleted file mode 100644 index cca49a7b..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeRawEncodedTimJsonProcessor.java +++ /dev/null @@ -1,43 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors; - -import java.time.Duration; -import java.time.Instant; -import java.time.format.DateTimeFormatter; - -import com.fasterxml.jackson.databind.JsonNode; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; - -public class OdeRawEncodedTimJsonProcessor extends DeduplicationProcessor{ - - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - - DeduplicatorProperties props; - - public OdeRawEncodedTimJsonProcessor(DeduplicatorProperties props){ - this.props = props; - this.storeName = props.getKafkaStateStoreOdeRawEncodedTimJsonName(); - } - - - @Override - public Instant getMessageTime(JsonNode message) { - try { - String time = message.get("metadata").get("odeReceivedAt").asText(); - return Instant.from(formatter.parse(time)); - } catch (Exception e) { - return Instant.ofEpochMilli(0); - } - } - - @Override - public boolean isDuplicate(JsonNode lastMessage, JsonNode newMessage) { - Instant oldValueTime = getMessageTime(lastMessage); - Instant newValueTime = getMessageTime(newMessage); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return false; - } - return true; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeTimJsonProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeTimJsonProcessor.java deleted file mode 100644 index 751ce8cd..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeTimJsonProcessor.java +++ /dev/null @@ -1,42 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors; - -import java.time.Duration; -import java.time.Instant; -import java.time.format.DateTimeFormatter; - -import com.fasterxml.jackson.databind.JsonNode; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; - -public class OdeTimJsonProcessor extends DeduplicationProcessor{ - - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - - DeduplicatorProperties props; - public OdeTimJsonProcessor(DeduplicatorProperties props){ - this.props = props; - this.storeName = props.getKafkaStateStoreOdeTimJsonName(); - } - - - @Override - public Instant getMessageTime(JsonNode message) { - try { - String time = message.get("metadata").get("odeReceivedAt").asText(); - return Instant.from(formatter.parse(time)); - } catch (Exception e) { - return Instant.ofEpochMilli(0); - } - } - - @Override - public boolean isDuplicate(JsonNode lastMessage, JsonNode newMessage) { - Instant oldValueTime = getMessageTime(lastMessage); - Instant newValueTime = getMessageTime(newMessage); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return false; - } - return true; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapProcessor.java deleted file mode 100644 index 35e2c2f6..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapProcessor.java +++ /dev/null @@ -1,57 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors; - -import java.time.Duration; -import java.time.Instant; -import java.time.ZonedDateTime; -import java.util.Objects; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; - -public class ProcessedMapProcessor extends DeduplicationProcessor>{ - - DeduplicatorProperties props; - - public ProcessedMapProcessor(DeduplicatorProperties props){ - this.props = props; - this.storeName = props.getKafkaStateStoreProcessedMapName(); - } - - - @Override - public Instant getMessageTime(ProcessedMap message) { - try { - return message.getProperties().getOdeReceivedAt().toInstant(); - } catch (Exception e) { - return Instant.ofEpochMilli(0); - } - } - - @Override - public boolean isDuplicate(ProcessedMap lastMessage, ProcessedMap newMessage) { - - Instant newValueTime = getMessageTime(newMessage); - Instant oldValueTime = getMessageTime(lastMessage); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return false; - }else{ - ZonedDateTime newValueTimestamp = newMessage.getProperties().getTimeStamp(); - ZonedDateTime newValueOdeReceivedAt = newMessage.getProperties().getOdeReceivedAt(); - - newMessage.getProperties().setTimeStamp(lastMessage.getProperties().getTimeStamp()); - newMessage.getProperties().setOdeReceivedAt(lastMessage.getProperties().getOdeReceivedAt()); - - int oldHash = Objects.hash(lastMessage.toString()); - int newHash = Objects.hash(newMessage.toString()); - - if(oldHash != newHash){ - newMessage.getProperties().setTimeStamp(newValueTimestamp); - newMessage.getProperties().setOdeReceivedAt(newValueOdeReceivedAt); - return false; - } - } - return true; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapWktProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapWktProcessor.java deleted file mode 100644 index 75560602..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapWktProcessor.java +++ /dev/null @@ -1,55 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors; - -import java.time.Duration; -import java.time.Instant; -import java.time.ZonedDateTime; -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; - -public class ProcessedMapWktProcessor extends DeduplicationProcessor>{ - - DeduplicatorProperties props; - - public ProcessedMapWktProcessor(DeduplicatorProperties props){ - this.props = props; - this.storeName = props.getKafkaStateStoreProcessedMapWKTName(); - } - - - @Override - public Instant getMessageTime(ProcessedMap message) { - try { - return message.getProperties().getOdeReceivedAt().toInstant(); - } catch (Exception e) { - return Instant.ofEpochMilli(0); - } - } - - @Override - public boolean isDuplicate(ProcessedMap lastMessage, ProcessedMap newMessage) { - - Instant newValueTime = newMessage.getProperties().getTimeStamp().toInstant(); - Instant oldValueTime = lastMessage.getProperties().getTimeStamp().toInstant(); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return false; - }else{ - ZonedDateTime newValueTimestamp = newMessage.getProperties().getTimeStamp(); - ZonedDateTime newValueOdeReceivedAt = newMessage.getProperties().getOdeReceivedAt(); - - newMessage.getProperties().setTimeStamp(lastMessage.getProperties().getTimeStamp()); - newMessage.getProperties().setOdeReceivedAt(lastMessage.getProperties().getOdeReceivedAt()); - - int oldHash = lastMessage.getProperties().hashCode(); - int newhash = newMessage.getProperties().hashCode(); - - if(oldHash != newhash){ - newMessage.getProperties().setTimeStamp(newValueTimestamp); - newMessage.getProperties().setOdeReceivedAt(newValueOdeReceivedAt); - return false; - } - } - - return true; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedSpatProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedSpatProcessor.java deleted file mode 100644 index 2cc58afd..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedSpatProcessor.java +++ /dev/null @@ -1,64 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors; - - -import java.time.Duration; -import java.time.Instant; -import java.util.HashMap; -import java.util.List; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.geojsonconverter.pojos.spat.MovementEvent; -import us.dot.its.jpo.geojsonconverter.pojos.spat.MovementState; -import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; - -public class ProcessedSpatProcessor extends DeduplicationProcessor{ - - DeduplicatorProperties props; - - public ProcessedSpatProcessor(DeduplicatorProperties props){ - this.props = props; - this.storeName = props.getKafkaStateStoreProcessedSpatName(); - } - - - @Override - public Instant getMessageTime(ProcessedSpat message) { - return message.getUtcTimeStamp().toInstant(); - } - - @Override - public boolean isDuplicate(ProcessedSpat lastMessage, ProcessedSpat newMessage) { - - Instant newValueTime = getMessageTime(newMessage); - Instant oldValueTime = getMessageTime(lastMessage); - - if(newValueTime.minus(Duration.ofMinutes(1)).isAfter(oldValueTime)){ - return false; - }else{ - HashMap> lastMessageStates = new HashMap<>(); - for(MovementState state: lastMessage.getStates()){ - lastMessageStates.put(state.getSignalGroup(), state.getStateTimeSpeed()); - } - - if(lastMessageStates.size() != newMessage.getStates().size()){ - return false; // message cannot be duplicate if the signal groups have a different number of signal groups - } - - for(MovementState state: newMessage.getStates()){ - List lastMessageState = lastMessageStates.get(state.getSignalGroup()); - - if(lastMessageState == null){ - return false; // messages cannot be duplicates if they have different signal groups - } - - - for(int i=0; i< state.getStateTimeSpeed().size(); i++){ - if(state.getStateTimeSpeed().get(i).getEventState() != lastMessageState.get(i).getEventState()){ - return false; // Some signal group light has changed. Therefore the SPaTs are different - } - } - } - } - return true; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeBsmJsonProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeBsmJsonProcessorSupplier.java deleted file mode 100644 index 6b08b9f6..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeBsmJsonProcessorSupplier.java +++ /dev/null @@ -1,26 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers; - -import java.time.format.DateTimeFormatter; -import org.apache.kafka.streams.processor.api.Processor; -import org.apache.kafka.streams.processor.api.ProcessorSupplier; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.OdeBsmJsonProcessor; -import us.dot.its.jpo.ode.model.OdeBsmData; - -public class OdeBsmJsonProcessorSupplier implements ProcessorSupplier { - - String storeName; - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - DeduplicatorProperties props; - - public OdeBsmJsonProcessorSupplier(String storeName, DeduplicatorProperties props){ - this.storeName = storeName; - this.props = props; - } - - @Override - public Processor get() { - return new OdeBsmJsonProcessor(storeName, props); - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeMapJsonProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeMapJsonProcessorSupplier.java deleted file mode 100644 index 829af131..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeMapJsonProcessorSupplier.java +++ /dev/null @@ -1,22 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers; - -import org.apache.kafka.streams.processor.api.Processor; -import org.apache.kafka.streams.processor.api.ProcessorSupplier; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.OdeMapJsonProcessor; -import us.dot.its.jpo.ode.model.OdeMapData; - -public class OdeMapJsonProcessorSupplier implements ProcessorSupplier { - - DeduplicatorProperties props; - - public OdeMapJsonProcessorSupplier(DeduplicatorProperties props){ - this.props = props; - } - - @Override - public Processor get() { - return new OdeMapJsonProcessor(props); - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeRawEncodedTimProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeRawEncodedTimProcessorSupplier.java deleted file mode 100644 index ef0ebb7f..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeRawEncodedTimProcessorSupplier.java +++ /dev/null @@ -1,22 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers; - -import org.apache.kafka.streams.processor.api.Processor; -import org.apache.kafka.streams.processor.api.ProcessorSupplier; -import com.fasterxml.jackson.databind.JsonNode; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.OdeRawEncodedTimJsonProcessor; - -public class OdeRawEncodedTimProcessorSupplier implements ProcessorSupplier { - - DeduplicatorProperties props; - - public OdeRawEncodedTimProcessorSupplier(DeduplicatorProperties props){ - this.props = props; - } - - @Override - public Processor get() { - return new OdeRawEncodedTimJsonProcessor(props); - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeTimJsonProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeTimJsonProcessorSupplier.java deleted file mode 100644 index 7a27588d..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeTimJsonProcessorSupplier.java +++ /dev/null @@ -1,22 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers; - -import org.apache.kafka.streams.processor.api.Processor; -import org.apache.kafka.streams.processor.api.ProcessorSupplier; -import com.fasterxml.jackson.databind.JsonNode; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.OdeTimJsonProcessor; - -public class OdeTimJsonProcessorSupplier implements ProcessorSupplier { - - String storeName; - DeduplicatorProperties props; - public OdeTimJsonProcessorSupplier(DeduplicatorProperties props){ - this.props = props; - } - - @Override - public Processor get() { - return new OdeTimJsonProcessor(props); - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapProcessorSupplier.java deleted file mode 100644 index 9e45cd03..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapProcessorSupplier.java +++ /dev/null @@ -1,23 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers; - -import org.apache.kafka.streams.processor.api.Processor; -import org.apache.kafka.streams.processor.api.ProcessorSupplier; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.ProcessedMapProcessor; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; - -public class ProcessedMapProcessorSupplier implements ProcessorSupplier, String, ProcessedMap> { - - DeduplicatorProperties props; - - public ProcessedMapProcessorSupplier(DeduplicatorProperties props){ - this.props = props; - } - - @Override - public Processor, String, ProcessedMap> get() { - return new ProcessedMapProcessor(props); - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapWktProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapWktProcessorSupplier.java deleted file mode 100644 index 3dbaa8c1..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapWktProcessorSupplier.java +++ /dev/null @@ -1,22 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers; - -import org.apache.kafka.streams.processor.api.Processor; -import org.apache.kafka.streams.processor.api.ProcessorSupplier; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.ProcessedMapWktProcessor; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; - -public class ProcessedMapWktProcessorSupplier implements ProcessorSupplier, String, ProcessedMap> { - - DeduplicatorProperties props; - - public ProcessedMapWktProcessorSupplier(DeduplicatorProperties props){ - this.props = props; - } - - @Override - public Processor, String, ProcessedMap> get() { - return new ProcessedMapWktProcessor(props); - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedSpatProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedSpatProcessorSupplier.java deleted file mode 100644 index e6661ac1..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedSpatProcessorSupplier.java +++ /dev/null @@ -1,22 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers; - -import org.apache.kafka.streams.processor.api.Processor; -import org.apache.kafka.streams.processor.api.ProcessorSupplier; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.ProcessedSpatProcessor; -import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; - -public class ProcessedSpatProcessorSupplier implements ProcessorSupplier { - - DeduplicatorProperties props; - - public ProcessedSpatProcessorSupplier(DeduplicatorProperties props){ - this.props = props; - } - - @Override - public Processor get() { - return new ProcessedSpatProcessor(props); - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/JsonSerdes.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/JsonSerdes.java deleted file mode 100644 index 8f65168a..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/JsonSerdes.java +++ /dev/null @@ -1,24 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.serialization; - -import org.apache.kafka.common.serialization.Serde; -import org.apache.kafka.common.serialization.Serdes; - -import com.fasterxml.jackson.databind.JsonNode; - -import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; -import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; -import us.dot.its.jpo.ode.model.OdeTimData; - -public class JsonSerdes { - public static Serde Tim() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(OdeTimData.class)); - } - - public static Serde JSON(){ - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(JsonNode.class)); - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/PairSerdes.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/PairSerdes.java deleted file mode 100644 index e509fa00..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/PairSerdes.java +++ /dev/null @@ -1,52 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.serialization; - -import org.apache.kafka.common.serialization.Serde; -import org.apache.kafka.common.serialization.Serdes; - -import us.dot.its.jpo.deduplicator.deduplicator.models.ProcessedMapPair; -import us.dot.its.jpo.deduplicator.deduplicator.models.ProcessedMapWktPair; -import us.dot.its.jpo.deduplicator.deduplicator.models.OdeMapPair; -import us.dot.its.jpo.deduplicator.deduplicator.models.OdeBsmPair; -import us.dot.its.jpo.deduplicator.deduplicator.models.JsonPair; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.DeserializedRawMap; -import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; -import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; - - -public class PairSerdes { - public static Serde ProcessedMapPair() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(ProcessedMapPair.class)); - } - - public static Serde ProcessedMapWktPair() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(ProcessedMapWktPair.class)); - } - - public static Serde OdeMapPair() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(OdeMapPair.class)); - } - - public static Serde OdeBsmPair() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(OdeBsmPair.class)); - } - - public static Serde RawMap() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(DeserializedRawMap.class)); - } - - public static Serde JsonPair() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(JsonPair.class)); - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/BsmDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/BsmDeduplicatorTopology.java deleted file mode 100644 index 6b26d676..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/BsmDeduplicatorTopology.java +++ /dev/null @@ -1,125 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.topologies; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; - -import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.ode.model.OdeBsmData; -import us.dot.its.jpo.ode.model.OdeBsmMetadata; -import us.dot.its.jpo.ode.model.OdeMapData; -import us.dot.its.jpo.ode.model.OdeMapPayload; -import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; -import us.dot.its.jpo.ode.plugin.j2735.J2735BsmCoreData; -import org.apache.kafka.streams.kstream.*; -import org.apache.kafka.streams.state.Stores; -import org.geotools.referencing.GeodeticCalculator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Objects; - -import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.OdeBsmJsonProcessorSupplier; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; - -public class BsmDeduplicatorTopology { - - private static final Logger logger = LoggerFactory.getLogger(BsmDeduplicatorTopology.class); - - Topology topology; - KafkaStreams streams; - DeduplicatorProperties props; - ObjectMapper objectMapper; - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - GeodeticCalculator calculator; - - - - public BsmDeduplicatorTopology(DeduplicatorProperties props){ - this.props = props; - this.objectMapper = DateJsonMapper.getInstance(); - calculator = new GeodeticCalculator(); - } - - - - public void start() { - if (streams != null && streams.state().isRunningOrRebalancing()) { - throw new IllegalStateException("Start called while streams is already running."); - } - Topology topology = buildTopology(); - streams = new KafkaStreams(topology, props.createStreamProperties("BsmDeduplicator")); - if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); - if (stateListener != null) streams.setStateListener(stateListener); - logger.info("Starting Bsm Deduplicator Topology"); - streams.start(); - } - - public Instant getInstantFromBsm(OdeBsmData bsm){ - String time = ((OdeBsmMetadata)bsm.getMetadata()).getOdeReceivedAt(); - - return Instant.from(formatter.parse(time)); - } - - public int hashMapMessage(OdeMapData map){ - OdeMapPayload payload = (OdeMapPayload)map.getPayload(); - return Objects.hash(payload.toJson()); - - } - - public Topology buildTopology() { - StreamsBuilder builder = new StreamsBuilder(); - - KStream inputStream = builder.stream(this.props.getKafkaTopicOdeBsmJson(), Consumed.with(Serdes.Void(), JsonSerdes.OdeBsm())); - - builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreOdeBsmJsonName()), - Serdes.String(), JsonSerdes.OdeBsm())); - - KStream bsmRekeyedStream = inputStream.selectKey((key, value)->{ - J2735BsmCoreData core = ((J2735Bsm)value.getPayload().getData()).getCoreData(); - return core.getId(); - }).repartition(Repartitioned.with(Serdes.String(), JsonSerdes.OdeBsm())); - - KStream deduplicatedStream = bsmRekeyedStream.process(new OdeBsmJsonProcessorSupplier(props.getKafkaStateStoreOdeBsmJsonName(), props), props.getKafkaStateStoreOdeBsmJsonName()); - - - deduplicatedStream.to(this.props.getKafkaTopicDeduplicatedOdeBsmJson(), Produced.with(Serdes.String(), JsonSerdes.OdeBsm())); - - return builder.build(); - - } - - public void stop() { - logger.info("Stopping Bsm deduplicator Socket Broadcast Topology."); - if (streams != null) { - streams.close(); - streams.cleanUp(); - streams = null; - } - logger.info("Stopped Bsm deduplicator Socket Broadcast Topology."); - } - - StateListener stateListener; - public void registerStateListener(StateListener stateListener) { - this.stateListener = stateListener; - } - - StreamsUncaughtExceptionHandler exceptionHandler; - public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } - - public double calculateGeodeticDistance(double lat1, double lon1, double lat2, double lon2) { - calculator.setStartingGeographicPoint(lon1, lat1); - calculator.setDestinationGeographicPoint(lon2, lat2); - return calculator.getOrthodromicDistance(); - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/MapDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/MapDeduplicatorTopology.java deleted file mode 100644 index c8ac7f6b..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/MapDeduplicatorTopology.java +++ /dev/null @@ -1,121 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.topologies; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.OdeMapJsonProcessorSupplier; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; -import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; -import us.dot.its.jpo.ode.model.OdeMapData; -import us.dot.its.jpo.ode.model.OdeMapMetadata; -import us.dot.its.jpo.ode.model.OdeMapPayload; -import us.dot.its.jpo.ode.plugin.j2735.J2735IntersectionReferenceID; - -import org.apache.kafka.streams.kstream.*; -import org.apache.kafka.streams.state.Stores; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Objects; -import java.util.Properties; - -public class MapDeduplicatorTopology { - - private static final Logger logger = LoggerFactory.getLogger(MapDeduplicatorTopology.class); - - Topology topology; - KafkaStreams streams; - String inputTopic; - String outputTopic; - Properties streamsProperties; - ObjectMapper objectMapper; - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - DeduplicatorProperties props; - - - public MapDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ - this.props = props; - this.streamsProperties = streamsProperties; - this.objectMapper = DateJsonMapper.getInstance(); - } - - - - public void start() { - if (streams != null && streams.state().isRunningOrRebalancing()) { - throw new IllegalStateException("Start called while streams is already running."); - } - Topology topology = buildTopology(); - streams = new KafkaStreams(topology, streamsProperties); - if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); - if (stateListener != null) streams.setStateListener(stateListener); - logger.info("Starting Map Deduplicator Topology"); - streams.start(); - } - - public Instant getInstantFromMap(OdeMapData map){ - String time = ((OdeMapMetadata)map.getMetadata()).getOdeReceivedAt(); - - return Instant.from(formatter.parse(time)); - } - - public int hashMapMessage(OdeMapData map){ - OdeMapPayload payload = (OdeMapPayload)map.getPayload(); - return Objects.hash(payload.toJson()); - - } - - public Topology buildTopology() { - StreamsBuilder builder = new StreamsBuilder(); - - KStream inputStream = builder.stream(props.getKafkaTopicOdeMapJson(), Consumed.with(Serdes.Void(), JsonSerdes.OdeMap())); - - builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreOdeMapJsonName()), - Serdes.String(), JsonSerdes.OdeMap())); - - KStream mapRekeyedStream = inputStream.selectKey((key, value)->{ - J2735IntersectionReferenceID intersectionId = ((OdeMapPayload)value.getPayload()).getMap().getIntersections().getIntersections().get(0).getId(); - RsuIntersectionKey newKey = new RsuIntersectionKey(); - newKey.setRsuId(((OdeMapMetadata)value.getMetadata()).getOriginIp()); - newKey.setIntersectionReferenceID(intersectionId); - return newKey.toString(); - }).repartition(Repartitioned.with(Serdes.String(), JsonSerdes.OdeMap())); - - KStream deduplicatedStream = mapRekeyedStream.process(new OdeMapJsonProcessorSupplier(props), props.getKafkaStateStoreOdeMapJsonName()); - - deduplicatedStream.to(props.getKafkaTopicDeduplicatedOdeMapJson(), Produced.with(Serdes.String(), JsonSerdes.OdeMap())); - - return builder.build(); - - } - - public void stop() { - logger.info("Stopping Map Deduplicator Socket Broadcast Topology."); - if (streams != null) { - streams.close(); - streams.cleanUp(); - streams = null; - } - logger.info("Stopped Map Deduplicator Socket Broadcast Topology."); - } - - StateListener stateListener; - public void registerStateListener(StateListener stateListener) { - this.stateListener = stateListener; - } - - StreamsUncaughtExceptionHandler exceptionHandler; - public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/OdeRawEncodedTimDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/OdeRawEncodedTimDeduplicatorTopology.java deleted file mode 100644 index 9431d6b4..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/OdeRawEncodedTimDeduplicatorTopology.java +++ /dev/null @@ -1,131 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.topologies; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.serialization.JsonSerdes; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; - -import org.apache.kafka.streams.kstream.*; -import org.apache.kafka.streams.state.Stores; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Objects; -import java.util.Properties; - -import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.OdeRawEncodedTimProcessorSupplier; - -public class OdeRawEncodedTimDeduplicatorTopology { - - private static final Logger logger = LoggerFactory.getLogger(OdeRawEncodedTimDeduplicatorTopology.class); - - Topology topology; - KafkaStreams streams; - String inputTopic; - String outputTopic; - Properties streamsProperties; - ObjectMapper objectMapper; - DeduplicatorProperties props; - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - - public OdeRawEncodedTimDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ - this.streamsProperties = streamsProperties; - this.objectMapper = DateJsonMapper.getInstance(); - this.props = props; - } - - - public void start() { - if (streams != null && streams.state().isRunningOrRebalancing()) { - throw new IllegalStateException("Start called while streams is already running."); - } - Topology topology = buildTopology(); - streams = new KafkaStreams(topology, streamsProperties); - if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); - if (stateListener != null) streams.setStateListener(stateListener); - logger.info("Starting Tim Deduplicator Topology"); - streams.start(); - } - - public JsonNode genJsonNode(){ - return objectMapper.createObjectNode(); - } - - public Instant getInstantFromJsonTim(JsonNode tim){ - try{ - String time = tim.get("metadata").get("odeReceivedAt").asText(); - return Instant.from(formatter.parse(time)); - }catch(Exception e){ - System.out.println("Failed to parse time"); - return Instant.ofEpochMilli(0); - } - } - - - public Topology buildTopology() { - StreamsBuilder builder = new StreamsBuilder(); - - KStream inputStream = builder.stream(props.getKafkaTopicOdeRawEncodedTimJson(), Consumed.with(Serdes.Void(), JsonSerdes.JSON())); - - builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreOdeRawEncodedTimJsonName()), - Serdes.String(), JsonSerdes.JSON())); - - KStream timRekeyedStream = inputStream.selectKey((key, value)->{ - try{ - - String messageBytes = value.get("payload") - .get("data") - .get("bytes").asText(); - - int hash = Objects.hash(messageBytes); - - String rsuIP = value.get("metadata").get("originIp").asText(); - - String newKey = rsuIP + "_" + hash; - return newKey; - }catch(Exception e){ - return ""; - } - }).repartition(Repartitioned.with(Serdes.String(), JsonSerdes.JSON())); - - - - KStream deduplicatedStream = timRekeyedStream.process(new OdeRawEncodedTimProcessorSupplier(props), props.getKafkaStateStoreOdeRawEncodedTimJsonName()); - - deduplicatedStream.to(props.getKafkaTopicDeduplicatedOdeRawEncodedTimJson(), Produced.with(Serdes.String(), JsonSerdes.JSON())); - - return builder.build(); - - } - - public void stop() { - logger.info("Stopping OdeRawEncodedTim Deduplicator Socket Broadcast Topology."); - if (streams != null) { - streams.close(); - streams.cleanUp(); - streams = null; - } - logger.info("Stopped OdeRawEncodedTim Deduplicator Socket Broadcast Topology."); - } - - StateListener stateListener; - public void registerStateListener(StateListener stateListener) { - this.stateListener = stateListener; - } - - StreamsUncaughtExceptionHandler exceptionHandler; - public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapDeduplicatorTopology.java deleted file mode 100644 index 5f9da3dd..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapDeduplicatorTopology.java +++ /dev/null @@ -1,92 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.topologies; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.ProcessedMapProcessorSupplier; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; -import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; -import org.apache.kafka.streams.kstream.*; -import org.apache.kafka.streams.state.Stores; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.ObjectMapper; - - -import java.util.Properties; - -public class ProcessedMapDeduplicatorTopology { - - private static final Logger logger = LoggerFactory.getLogger(MapDeduplicatorTopology.class); - - Topology topology; - KafkaStreams streams; - Properties streamsProperties; - ObjectMapper objectMapper; - DeduplicatorProperties props; - - public ProcessedMapDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ - this.props = props; - this.streamsProperties = streamsProperties; - this.objectMapper = DateJsonMapper.getInstance(); - } - - - public void start() { - if (streams != null && streams.state().isRunningOrRebalancing()) { - throw new IllegalStateException("Start called while streams is already running."); - } - Topology topology = buildTopology(); - streams = new KafkaStreams(topology, streamsProperties); - if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); - if (stateListener != null) streams.setStateListener(stateListener); - logger.info("Starting Processed Map Deduplicator Topology"); - streams.start(); - } - - public Topology buildTopology() { - StreamsBuilder builder = new StreamsBuilder(); - - KStream> inputStream = builder.stream(props.getKafkaTopicProcessedMap(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); - - builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreProcessedMapName()), - Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); - - KStream> deduplicatedStream = inputStream.process(new ProcessedMapProcessorSupplier(props), props.getKafkaStateStoreProcessedMapName()); - - deduplicatedStream.to(props.getKafkaTopicDeduplicatedProcessedMap(), Produced.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); - - return builder.build(); - - } - - public void stop() { - logger.info("Stopping Processed Map deduplicator Socket Broadcast Topology."); - if (streams != null) { - streams.close(); - streams.cleanUp(); - streams = null; - } - logger.info("Stopped Processed Map deduplicator Socket Broadcast Topology."); - } - - StateListener stateListener; - public void registerStateListener(StateListener stateListener) { - this.stateListener = stateListener; - } - - StreamsUncaughtExceptionHandler exceptionHandler; - public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } - - - -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapWktDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapWktDeduplicatorTopology.java deleted file mode 100644 index 872e66fa..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapWktDeduplicatorTopology.java +++ /dev/null @@ -1,93 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.topologies; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.ProcessedMapWktProcessorSupplier; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; -import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; - -import org.apache.kafka.streams.kstream.*; -import org.apache.kafka.streams.state.Stores; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.util.Properties; - -public class ProcessedMapWktDeduplicatorTopology { - - private static final Logger logger = LoggerFactory.getLogger(MapDeduplicatorTopology.class); - - Topology topology; - KafkaStreams streams; - String inputTopic; - String outputTopic; - Properties streamsProperties; - ObjectMapper objectMapper; - DeduplicatorProperties props; - - public ProcessedMapWktDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ - this.props = props; - this.streamsProperties = streamsProperties; - this.objectMapper = DateJsonMapper.getInstance(); - } - - - public void start() { - if (streams != null && streams.state().isRunningOrRebalancing()) { - throw new IllegalStateException("Start called while streams is already running."); - } - Topology topology = buildTopology(); - streams = new KafkaStreams(topology, streamsProperties); - if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); - if (stateListener != null) streams.setStateListener(stateListener); - logger.info("Starting Processed Map WKT Deduplicator Topology"); - streams.start(); - } - - public Topology buildTopology() { - StreamsBuilder builder = new StreamsBuilder(); - - KStream> inputStream = builder.stream(props.getKafkaTopicProcessedMapWKT(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedMapWKT())); - - builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreProcessedMapWKTName()), - Serdes.String(), JsonSerdes.ProcessedMapWKT())); - - KStream> deduplicatedStream = inputStream.process(new ProcessedMapWktProcessorSupplier(props), props.getKafkaStateStoreProcessedMapWKTName()); - - deduplicatedStream.to(props.getKafkaTopicDeduplicatedProcessedMapWKT(), Produced.with(Serdes.String(), JsonSerdes.ProcessedMapWKT())); - - return builder.build(); - - } - - public void stop() { - logger.info("Stopping Processed Map deduplicator Socket Broadcast Topology."); - if (streams != null) { - streams.close(); - streams.cleanUp(); - streams = null; - } - logger.info("Stopped Processed Map deduplicator Socket Broadcast Topology."); - } - - StateListener stateListener; - public void registerStateListener(StateListener stateListener) { - this.stateListener = stateListener; - } - - StreamsUncaughtExceptionHandler exceptionHandler; - public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } - - - -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedSpatDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedSpatDeduplicatorTopology.java deleted file mode 100644 index b478669c..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedSpatDeduplicatorTopology.java +++ /dev/null @@ -1,97 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.topologies; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.ProcessedSpatProcessorSupplier; -import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; - -import org.apache.kafka.streams.kstream.*; -import org.apache.kafka.streams.state.Stores; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.time.format.DateTimeFormatter; -import java.util.Properties; - -public class ProcessedSpatDeduplicatorTopology { - - private static final Logger logger = LoggerFactory.getLogger(ProcessedSpatDeduplicatorTopology.class); - - Topology topology; - KafkaStreams streams; - String inputTopic; - String outputTopic; - Properties streamsProperties; - ObjectMapper objectMapper; - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - DeduplicatorProperties props; - - - public ProcessedSpatDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ - this.props = props; - this.streamsProperties = streamsProperties; - this.objectMapper = DateJsonMapper.getInstance(); - } - - - - public void start() { - if (streams != null && streams.state().isRunningOrRebalancing()) { - throw new IllegalStateException("Start called while streams is already running."); - } - Topology topology = buildTopology(); - streams = new KafkaStreams(topology, streamsProperties); - if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); - if (stateListener != null) streams.setStateListener(stateListener); - logger.info("Starting Map Deduplicator Topology"); - streams.start(); - } - - public Topology buildTopology() { - StreamsBuilder builder = new StreamsBuilder(); - - KStream inputStream = builder.stream(props.getKafkaTopicProcessedSpat(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedSpat())); - - builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreProcessedSpatName()), - Serdes.String(), JsonSerdes.ProcessedSpat())); - - KStream deduplicatedStream = inputStream.process(new ProcessedSpatProcessorSupplier(props), props.getKafkaStateStoreProcessedSpatName()); - - deduplicatedStream.print(Printed.toSysOut()); - - deduplicatedStream.to(props.getKafkaTopicDeduplicatedProcessedSpat(), Produced.with(Serdes.String(), JsonSerdes.ProcessedSpat())); - - return builder.build(); - - } - - public void stop() { - logger.info("Stopping Processed SPaT deduplicator Socket Broadcast Topology."); - if (streams != null) { - streams.close(); - streams.cleanUp(); - streams = null; - } - logger.info("Stopped Processed SPaT deduplicator Socket Broadcast Topology."); - } - - StateListener stateListener; - public void registerStateListener(StateListener stateListener) { - this.stateListener = stateListener; - } - - StreamsUncaughtExceptionHandler exceptionHandler; - public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } -} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/TimDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/TimDeduplicatorTopology.java deleted file mode 100644 index d8cf5708..00000000 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/TimDeduplicatorTopology.java +++ /dev/null @@ -1,126 +0,0 @@ -package us.dot.its.jpo.deduplicator.deduplicator.topologies; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; - -import us.dot.its.jpo.deduplicator.deduplicator.serialization.JsonSerdes; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; - -import org.apache.kafka.streams.kstream.*; -import org.apache.kafka.streams.state.Stores; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.time.format.DateTimeFormatter; -import java.util.Properties; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.OdeTimJsonProcessorSupplier; - - -public class TimDeduplicatorTopology { - - private static final Logger logger = LoggerFactory.getLogger(TimDeduplicatorTopology.class); - - Topology topology; - KafkaStreams streams; - Properties streamsProperties; - ObjectMapper objectMapper; - DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; - DeduplicatorProperties props; - - public TimDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties) { - this.props = props; - this.streamsProperties = streamsProperties; - this.objectMapper = DateJsonMapper.getInstance(); - } - - public void start() { - if (streams != null && streams.state().isRunningOrRebalancing()) { - throw new IllegalStateException("Start called while streams is already running."); - } - Topology topology = buildTopology(); - streams = new KafkaStreams(topology, streamsProperties); - if (exceptionHandler != null) - streams.setUncaughtExceptionHandler(exceptionHandler); - if (stateListener != null) - streams.setStateListener(stateListener); - logger.info("Starting Tim Deduplicator Topology"); - streams.start(); - } - - public JsonNode genJsonNode() { - return objectMapper.createObjectNode(); - } - - - - public Topology buildTopology() { - StreamsBuilder builder = new StreamsBuilder(); - - KStream inputStream = builder.stream(props.getKafkaTopicOdeTimJson(), - Consumed.with(Serdes.Void(), JsonSerdes.JSON())); - - builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreOdeTimJsonName()), - Serdes.String(), JsonSerdes.JSON())); - - - - KStream timRekeyedStream = inputStream.selectKey((key, value) -> { - try { - - JsonNode travellerInformation = value.get("payload") - .get("data") - .get("MessageFrame") - .get("value") - .get("TravelerInformation"); - - String rsuIP = value.get("metadata").get("originIp").asText(); - String packetId = travellerInformation.get("packetID").asText(); - String msgCnt = travellerInformation.get("msgCnt").asText(); - - String newKey = rsuIP + "_" + packetId + "_" + msgCnt; - return newKey; - } catch (Exception e) { - return ""; - } - }).repartition(Repartitioned.with(Serdes.String(), JsonSerdes.JSON())); - - KStream deduplicatedStream = timRekeyedStream.process(new OdeTimJsonProcessorSupplier(props), props.getKafkaStateStoreOdeTimJsonName()); - - deduplicatedStream.to(props.getKafkaTopicDeduplicatedOdeTimJson(), Produced.with(Serdes.String(), JsonSerdes.JSON())); - - return builder.build(); - - } - - public void stop() { - logger.info("Stopping Tim deduplicator Socket Broadcast Topology."); - if (streams != null) { - streams.close(); - streams.cleanUp(); - streams = null; - } - logger.info("Stopped Tim deduplicator Socket Broadcast Topology."); - } - - StateListener stateListener; - - public void registerStateListener(StateListener stateListener) { - this.stateListener = stateListener; - } - - StreamsUncaughtExceptionHandler exceptionHandler; - - public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } - -} diff --git a/jpo-deduplicator/src/main/resources/application.yaml b/jpo-deduplicator/src/main/resources/application.yaml deleted file mode 100644 index 3102c6b8..00000000 --- a/jpo-deduplicator/src/main/resources/application.yaml +++ /dev/null @@ -1,96 +0,0 @@ -#General Properties -#================== -groupId: ^project.groupId^ -artifactId: ^project.artifactId^ -version: ^project.version^ -server.port: 8085 - -# Kafka properties -spring.kafka.bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:9092} -logging.level.org.apache.kafka: INFO -logging.level: INFO -log4j.logger.kafka: OFF -log4j.logger.org.apache.kafka: OFF - - - -# Processed Map Configuration -kafkaTopicProcessedMap: topic.ProcessedMap -kafkaTopicDeduplicatedProcessedMap: topic.DeduplicatedProcessedMap -enableProcessedMapDeduplication: true - -# Processed Map WKT Configuration -kafkaTopicProcessedMapWKT: topic.ProcessedMapWKT -kafkaTopicDeduplicatedProcessedMapWKT: topic.DeduplicatedProcessedMapWKT -enableProcessedMapWktDeduplication: true - -# Ode Map Json Configuration -kafkaTopicOdeMapJson: topic.OdeMapJson -kafkaTopicDeduplicatedOdeMapJson: topic.DeduplicatedOdeMapJson -enableOdeMapDeduplication: true - -# Ode Tim Json Configuration -kafkaTopicOdeTimJson: topic.OdeTimJson -kafkaTopicDeduplicatedOdeTimJson: topic.DeduplicatedOdeTimJson -enableOdeTimDeduplication: true - -# Ode Raw Encoded Tim Json Configuration -kafkaTopicOdeRawEncodedTimJson: topic.OdeRawEncodedTIMJson -kafkaTopicDeduplicatedOdeRawEncodedTimJson: topic.DeduplicatedOdeRawEncodedTIMJson -enableOdeRawEncodedTimDeduplication: true - -# Ode Bsm Json Configuration -kafkaTopicOdeBsmJson: topic.OdeBsmJson -kafkaTopicDeduplicatedOdeBsmJson: topic.DeduplicatedOdeBsmJson -enableOdeBsmDeduplication: true -odeBsmMaximumTimeDelta: 10000 # Milliseconds -odeBsmMaximumPositionDelta: 1 # Meter -odeBsmAlwaysIncludeAtSpeed: 1 # Meter / Second - -# Processed Map Configuration -kafkaTopicProcessedSpat: topic.ProcessedSpat -kafkaTopicDeduplicatedProcessedSpat: topic.DeduplicatedProcessedSpat -enableProcessedSpatDeduplication: true - - -# Amount of time to wait to try and increase batching -kafka.linger_ms: 50 - -# Custom kafka properties -kafka.topics: - autoCreateTopics: true # Override auto-create in test properties - numPartitions: 1 - numReplicas: 1 - createTopics: - - name: ${kafkaTopicProcessedMap} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicDeduplicatedProcessedMap} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicProcessedMapWKT} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicDeduplicatedProcessedMapWKT} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicOdeMapJson} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicDeduplicatedOdeMapJson} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicOdeTimJson} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicDeduplicatedOdeTimJson} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicProcessedSpat} - cleanupPolicy: delete - retentionMs: 300000 - - name: ${kafkaTopicDeduplicatedProcessedSpat} - cleanupPolicy: delete - retentionMs: 300000 - - \ No newline at end of file diff --git a/jpo-deduplicator/src/main/resources/logback.xml b/jpo-deduplicator/src/main/resources/logback.xml deleted file mode 100644 index 860df158..00000000 --- a/jpo-deduplicator/src/main/resources/logback.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - %date{"yyyy-MM-dd HH:mm:ss", UTC} [%thread] %-5level %logger{0} - %msg %n - - - - - - - - - - - - - diff --git a/jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java deleted file mode 100644 index 98d62047..00000000 --- a/jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package deduplicator; - - - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KeyValue; -import org.apache.kafka.streams.TestInputTopic; -import org.apache.kafka.streams.TestOutputTopic; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.TopologyTestDriver; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.BsmDeduplicatorTopology; -import us.dot.its.jpo.ode.model.OdeBsmData; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; - - -public class BsmDeduplicatorTopologyTest { - - String inputTopic = "topic.OdeBsmJson"; - String outputTopic = "topic.DeduplicatedOdeBsmJson"; - ObjectMapper objectMapper; - - String inputBsm1 = "{\"metadata\":{\"bsmSource\":\"RV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"\",\"longitude\":\"\",\"elevation\":\"\",\"speed\":\"\",\"heading\":\"\"},\"rxSource\":\"RV\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"f1bfed26-d986-4a0c-b8a4-68b1e5ac1348\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-07-01T15:00:52.597Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"originIp\":\"10.164.6.18\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":7,\"id\":\"E79423A3\",\"secMark\":52597,\"position\":{\"latitude\":40.2970849,\"longitude\":-111.6956069,\"elevation\":1439},\"accelSet\":{\"accelLat\":2001,\"accelLong\":0,\"accelVert\":-127,\"accelYaw\":0},\"accuracy\":{\"semiMajor\":2,\"semiMinor\":2,\"orientation\":44.49530799},\"transmission\":\"FORWARDGEARS\",\"speed\":0,\"heading\":24.2,\"angle\":0,\"brakes\":{\"wheelBrakes\":{\"leftFront\":true,\"rightFront\":true,\"unavailable\":false,\"leftRear\":true,\"rightRear\":true},\"traction\":\"on\",\"abs\":\"on\",\"scs\":\"on\",\"brakeBoost\":\"off\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":230,\"length\":500}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"events\":null,\"pathHistory\":{\"initialPosition\":null,\"currGNSSstatus\":null,\"crumbData\":[{\"elevationOffset\":-0.5,\"heading\":null,\"latOffset\":0.0000038,\"lonOffset\":0.0001137,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":31.41},{\"elevationOffset\":-0.4,\"heading\":null,\"latOffset\":0.0000339,\"lonOffset\":0.0001695,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":32.05},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.000184,\"lonOffset\":0.0002106,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":36.29},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.0003092,\"lonOffset\":0.0003081,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":37.22},{\"elevationOffset\":0.4,\"heading\":null,\"latOffset\":0.0004354,\"lonOffset\":0.0003906,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":38.15},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0007727,\"lonOffset\":0.0004391,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":40.39},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.00084,\"lonOffset\":0.0004778,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":41.61},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0008649,\"lonOffset\":0.0005765,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":43.48},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0008086,\"lonOffset\":0.0015482,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":68.53},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0007738,\"lonOffset\":0.0015944,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":72.09},{\"elevationOffset\":2.1,\"heading\":null,\"latOffset\":0.0007349,\"lonOffset\":0.0015747,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":76.97}]},\"pathPrediction\":{\"confidence\":100,\"radiusOfCurve\":0},\"lights\":null}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classification\":66,\"classDetails\":{\"fuelType\":null,\"hpmsType\":\"none\",\"iso3883\":null,\"keyType\":66,\"responderType\":null,\"responseEquip\":null,\"role\":null,\"vehicleType\":null},\"vehicleData\":{\"bumpers\":null,\"height\":1.8,\"mass\":2800,\"trailerWeight\":null},\"weatherReport\":{\"friction\":null,\"isRaining\":\"ERROR\",\"precipSituation\":\"UNKNOWN\",\"rainRate\":null,\"roadFriction\":0,\"solarRadiation\":null},\"weatherProbe\":{\"airPressure\":860,\"airTemp\":71,\"rainRates\":null},\"obstacle\":null,\"status\":null,\"speedProfile\":null,\"theRTCM\":null}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; - - // Same as BSM 1 - No Message should be generated - String inputBsm2 = "{\"metadata\":{\"bsmSource\":\"RV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"\",\"longitude\":\"\",\"elevation\":\"\",\"speed\":\"\",\"heading\":\"\"},\"rxSource\":\"RV\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"f1bfed26-d986-4a0c-b8a4-68b1e5ac1348\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-07-01T15:00:52.697Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"originIp\":\"10.164.6.18\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":7,\"id\":\"E79423A3\",\"secMark\":52597,\"position\":{\"latitude\":40.2970849,\"longitude\":-111.6956069,\"elevation\":1439},\"accelSet\":{\"accelLat\":2001,\"accelLong\":0,\"accelVert\":-127,\"accelYaw\":0},\"accuracy\":{\"semiMajor\":2,\"semiMinor\":2,\"orientation\":44.49530799},\"transmission\":\"FORWARDGEARS\",\"speed\":0,\"heading\":24.2,\"angle\":0,\"brakes\":{\"wheelBrakes\":{\"leftFront\":true,\"rightFront\":true,\"unavailable\":false,\"leftRear\":true,\"rightRear\":true},\"traction\":\"on\",\"abs\":\"on\",\"scs\":\"on\",\"brakeBoost\":\"off\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":230,\"length\":500}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"events\":null,\"pathHistory\":{\"initialPosition\":null,\"currGNSSstatus\":null,\"crumbData\":[{\"elevationOffset\":-0.5,\"heading\":null,\"latOffset\":0.0000038,\"lonOffset\":0.0001137,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":31.41},{\"elevationOffset\":-0.4,\"heading\":null,\"latOffset\":0.0000339,\"lonOffset\":0.0001695,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":32.05},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.000184,\"lonOffset\":0.0002106,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":36.29},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.0003092,\"lonOffset\":0.0003081,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":37.22},{\"elevationOffset\":0.4,\"heading\":null,\"latOffset\":0.0004354,\"lonOffset\":0.0003906,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":38.15},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0007727,\"lonOffset\":0.0004391,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":40.39},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.00084,\"lonOffset\":0.0004778,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":41.61},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0008649,\"lonOffset\":0.0005765,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":43.48},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0008086,\"lonOffset\":0.0015482,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":68.53},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0007738,\"lonOffset\":0.0015944,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":72.09},{\"elevationOffset\":2.1,\"heading\":null,\"latOffset\":0.0007349,\"lonOffset\":0.0015747,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":76.97}]},\"pathPrediction\":{\"confidence\":100,\"radiusOfCurve\":0},\"lights\":null}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classification\":66,\"classDetails\":{\"fuelType\":null,\"hpmsType\":\"none\",\"iso3883\":null,\"keyType\":66,\"responderType\":null,\"responseEquip\":null,\"role\":null,\"vehicleType\":null},\"vehicleData\":{\"bumpers\":null,\"height\":1.8,\"mass\":2800,\"trailerWeight\":null},\"weatherReport\":{\"friction\":null,\"isRaining\":\"ERROR\",\"precipSituation\":\"UNKNOWN\",\"rainRate\":null,\"roadFriction\":0,\"solarRadiation\":null},\"weatherProbe\":{\"airPressure\":860,\"airTemp\":71,\"rainRates\":null},\"obstacle\":null,\"status\":null,\"speedProfile\":null,\"theRTCM\":null}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; - - // Increase Time from Bsm 1 - String inputBsm3 = "{\"metadata\":{\"bsmSource\":\"RV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"\",\"longitude\":\"\",\"elevation\":\"\",\"speed\":\"\",\"heading\":\"\"},\"rxSource\":\"RV\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"f1bfed26-d986-4a0c-b8a4-68b1e5ac1348\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-07-01T15:01:02.797Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"originIp\":\"10.164.6.18\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":7,\"id\":\"E79423A3\",\"secMark\":52597,\"position\":{\"latitude\":40.2970849,\"longitude\":-111.6956069,\"elevation\":1439},\"accelSet\":{\"accelLat\":2001,\"accelLong\":0,\"accelVert\":-127,\"accelYaw\":0},\"accuracy\":{\"semiMajor\":2,\"semiMinor\":2,\"orientation\":44.49530799},\"transmission\":\"FORWARDGEARS\",\"speed\":0,\"heading\":24.2,\"angle\":0,\"brakes\":{\"wheelBrakes\":{\"leftFront\":true,\"rightFront\":true,\"unavailable\":false,\"leftRear\":true,\"rightRear\":true},\"traction\":\"on\",\"abs\":\"on\",\"scs\":\"on\",\"brakeBoost\":\"off\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":230,\"length\":500}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"events\":null,\"pathHistory\":{\"initialPosition\":null,\"currGNSSstatus\":null,\"crumbData\":[{\"elevationOffset\":-0.5,\"heading\":null,\"latOffset\":0.0000038,\"lonOffset\":0.0001137,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":31.41},{\"elevationOffset\":-0.4,\"heading\":null,\"latOffset\":0.0000339,\"lonOffset\":0.0001695,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":32.05},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.000184,\"lonOffset\":0.0002106,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":36.29},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.0003092,\"lonOffset\":0.0003081,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":37.22},{\"elevationOffset\":0.4,\"heading\":null,\"latOffset\":0.0004354,\"lonOffset\":0.0003906,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":38.15},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0007727,\"lonOffset\":0.0004391,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":40.39},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.00084,\"lonOffset\":0.0004778,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":41.61},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0008649,\"lonOffset\":0.0005765,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":43.48},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0008086,\"lonOffset\":0.0015482,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":68.53},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0007738,\"lonOffset\":0.0015944,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":72.09},{\"elevationOffset\":2.1,\"heading\":null,\"latOffset\":0.0007349,\"lonOffset\":0.0015747,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":76.97}]},\"pathPrediction\":{\"confidence\":100,\"radiusOfCurve\":0},\"lights\":null}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classification\":66,\"classDetails\":{\"fuelType\":null,\"hpmsType\":\"none\",\"iso3883\":null,\"keyType\":66,\"responderType\":null,\"responseEquip\":null,\"role\":null,\"vehicleType\":null},\"vehicleData\":{\"bumpers\":null,\"height\":1.8,\"mass\":2800,\"trailerWeight\":null},\"weatherReport\":{\"friction\":null,\"isRaining\":\"ERROR\",\"precipSituation\":\"UNKNOWN\",\"rainRate\":null,\"roadFriction\":0,\"solarRadiation\":null},\"weatherProbe\":{\"airPressure\":860,\"airTemp\":71,\"rainRates\":null},\"obstacle\":null,\"status\":null,\"speedProfile\":null,\"theRTCM\":null}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; - - // Vehicle Speed not 0 - String inputBsm4 = "{\"metadata\":{\"bsmSource\":\"RV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"\",\"longitude\":\"\",\"elevation\":\"\",\"speed\":\"\",\"heading\":\"\"},\"rxSource\":\"RV\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"f1bfed26-d986-4a0c-b8a4-68b1e5ac1348\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-07-01T15:01:02.897Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"originIp\":\"10.164.6.18\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":7,\"id\":\"E79423A3\",\"secMark\":52597,\"position\":{\"latitude\":40.2970849,\"longitude\":-111.6956069,\"elevation\":1439},\"accelSet\":{\"accelLat\":2001,\"accelLong\":0,\"accelVert\":-127,\"accelYaw\":0},\"accuracy\":{\"semiMajor\":2,\"semiMinor\":2,\"orientation\":44.49530799},\"transmission\":\"FORWARDGEARS\",\"speed\":10,\"heading\":24.2,\"angle\":0,\"brakes\":{\"wheelBrakes\":{\"leftFront\":true,\"rightFront\":true,\"unavailable\":false,\"leftRear\":true,\"rightRear\":true},\"traction\":\"on\",\"abs\":\"on\",\"scs\":\"on\",\"brakeBoost\":\"off\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":230,\"length\":500}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"events\":null,\"pathHistory\":{\"initialPosition\":null,\"currGNSSstatus\":null,\"crumbData\":[{\"elevationOffset\":-0.5,\"heading\":null,\"latOffset\":0.0000038,\"lonOffset\":0.0001137,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":31.41},{\"elevationOffset\":-0.4,\"heading\":null,\"latOffset\":0.0000339,\"lonOffset\":0.0001695,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":32.05},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.000184,\"lonOffset\":0.0002106,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":36.29},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.0003092,\"lonOffset\":0.0003081,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":37.22},{\"elevationOffset\":0.4,\"heading\":null,\"latOffset\":0.0004354,\"lonOffset\":0.0003906,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":38.15},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0007727,\"lonOffset\":0.0004391,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":40.39},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.00084,\"lonOffset\":0.0004778,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":41.61},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0008649,\"lonOffset\":0.0005765,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":43.48},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0008086,\"lonOffset\":0.0015482,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":68.53},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0007738,\"lonOffset\":0.0015944,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":72.09},{\"elevationOffset\":2.1,\"heading\":null,\"latOffset\":0.0007349,\"lonOffset\":0.0015747,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":76.97}]},\"pathPrediction\":{\"confidence\":100,\"radiusOfCurve\":0},\"lights\":null}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classification\":66,\"classDetails\":{\"fuelType\":null,\"hpmsType\":\"none\",\"iso3883\":null,\"keyType\":66,\"responderType\":null,\"responseEquip\":null,\"role\":null,\"vehicleType\":null},\"vehicleData\":{\"bumpers\":null,\"height\":1.8,\"mass\":2800,\"trailerWeight\":null},\"weatherReport\":{\"friction\":null,\"isRaining\":\"ERROR\",\"precipSituation\":\"UNKNOWN\",\"rainRate\":null,\"roadFriction\":0,\"solarRadiation\":null},\"weatherProbe\":{\"airPressure\":860,\"airTemp\":71,\"rainRates\":null},\"obstacle\":null,\"status\":null,\"speedProfile\":null,\"theRTCM\":null}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; - - // Vehicle Position has changed - String inputBsm5 = "{\"metadata\":{\"bsmSource\":\"RV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"\",\"longitude\":\"\",\"elevation\":\"\",\"speed\":\"\",\"heading\":\"\"},\"rxSource\":\"RV\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"f1bfed26-d986-4a0c-b8a4-68b1e5ac1348\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-07-01T15:01:02.997Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"originIp\":\"10.164.6.18\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":7,\"id\":\"E79423A3\",\"secMark\":52597,\"position\":{\"latitude\":40.2970949,\"longitude\":-111.6956169,\"elevation\":1439},\"accelSet\":{\"accelLat\":2001,\"accelLong\":0,\"accelVert\":-127,\"accelYaw\":0},\"accuracy\":{\"semiMajor\":2,\"semiMinor\":2,\"orientation\":44.49530799},\"transmission\":\"FORWARDGEARS\",\"speed\":0,\"heading\":24.2,\"angle\":0,\"brakes\":{\"wheelBrakes\":{\"leftFront\":true,\"rightFront\":true,\"unavailable\":false,\"leftRear\":true,\"rightRear\":true},\"traction\":\"on\",\"abs\":\"on\",\"scs\":\"on\",\"brakeBoost\":\"off\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":230,\"length\":500}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"events\":null,\"pathHistory\":{\"initialPosition\":null,\"currGNSSstatus\":null,\"crumbData\":[{\"elevationOffset\":-0.5,\"heading\":null,\"latOffset\":0.0000038,\"lonOffset\":0.0001137,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":31.41},{\"elevationOffset\":-0.4,\"heading\":null,\"latOffset\":0.0000339,\"lonOffset\":0.0001695,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":32.05},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.000184,\"lonOffset\":0.0002106,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":36.29},{\"elevationOffset\":0,\"heading\":null,\"latOffset\":0.0003092,\"lonOffset\":0.0003081,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":37.22},{\"elevationOffset\":0.4,\"heading\":null,\"latOffset\":0.0004354,\"lonOffset\":0.0003906,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":38.15},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0007727,\"lonOffset\":0.0004391,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":40.39},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.00084,\"lonOffset\":0.0004778,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":41.61},{\"elevationOffset\":1.4,\"heading\":null,\"latOffset\":0.0008649,\"lonOffset\":0.0005765,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":43.48},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0008086,\"lonOffset\":0.0015482,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":68.53},{\"elevationOffset\":1.7,\"heading\":null,\"latOffset\":0.0007738,\"lonOffset\":0.0015944,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":72.09},{\"elevationOffset\":2.1,\"heading\":null,\"latOffset\":0.0007349,\"lonOffset\":0.0015747,\"posAccuracy\":null,\"speed\":null,\"timeOffset\":76.97}]},\"pathPrediction\":{\"confidence\":100,\"radiusOfCurve\":0},\"lights\":null}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classification\":66,\"classDetails\":{\"fuelType\":null,\"hpmsType\":\"none\",\"iso3883\":null,\"keyType\":66,\"responderType\":null,\"responseEquip\":null,\"role\":null,\"vehicleType\":null},\"vehicleData\":{\"bumpers\":null,\"height\":1.8,\"mass\":2800,\"trailerWeight\":null},\"weatherReport\":{\"friction\":null,\"isRaining\":\"ERROR\",\"precipSituation\":\"UNKNOWN\",\"rainRate\":null,\"roadFriction\":0,\"solarRadiation\":null},\"weatherProbe\":{\"airPressure\":860,\"airTemp\":71,\"rainRates\":null},\"obstacle\":null,\"status\":null,\"speedProfile\":null,\"theRTCM\":null}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; - - - @Autowired - DeduplicatorProperties props; - - - - @Test - public void testTopology() { - - - - - - props = new DeduplicatorProperties(); - props.setAlwaysIncludeAtSpeed(1); - props.setenableOdeBsmDeduplication(true); - props.setMaximumPositionDelta(1); - props.setMaximumTimeDelta(10000); - props.setkafkaTopicOdeBsmJson(inputTopic); - props.setkafkaTopicDeduplicatedOdeBsmJson(outputTopic); - - BsmDeduplicatorTopology bsmDeduplicatorTopology = new BsmDeduplicatorTopology(props); - Topology topology = bsmDeduplicatorTopology.buildTopology(); - - try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { - - - TestInputTopic inputOdeBsmData = driver.createInputTopic( - inputTopic, - Serdes.Void().serializer(), - Serdes.String().serializer()); - - - TestOutputTopic outputOdeBsmData = driver.createOutputTopic( - outputTopic, - Serdes.String().deserializer(), - JsonSerdes.OdeBsm().deserializer()); - - inputOdeBsmData.pipeInput(null, inputBsm1); - inputOdeBsmData.pipeInput(null, inputBsm2); - inputOdeBsmData.pipeInput(null, inputBsm3); - inputOdeBsmData.pipeInput(null, inputBsm4); - inputOdeBsmData.pipeInput(null, inputBsm5); - - List> bsmDeduplicationResults = outputOdeBsmData.readKeyValuesToList(); - - // validate that only 3 messages make it through - assertEquals(4, bsmDeduplicationResults.size()); - - objectMapper = new ObjectMapper(); - OdeBsmData bsm1 = objectMapper.readValue(inputBsm1, OdeBsmData.class); - OdeBsmData bsm3 = objectMapper.readValue(inputBsm3, OdeBsmData.class); - OdeBsmData bsm4 = objectMapper.readValue(inputBsm4, OdeBsmData.class); - OdeBsmData bsm5 = objectMapper.readValue(inputBsm5, OdeBsmData.class); - - - assertEquals(bsm1.getMetadata().getOdeReceivedAt(), bsmDeduplicationResults.get(0).value.getMetadata().getOdeReceivedAt()); - assertEquals(bsm3.getMetadata().getOdeReceivedAt(), bsmDeduplicationResults.get(1).value.getMetadata().getOdeReceivedAt()); - assertEquals(bsm4.getMetadata().getOdeReceivedAt(), bsmDeduplicationResults.get(2).value.getMetadata().getOdeReceivedAt()); - assertEquals(bsm5.getMetadata().getOdeReceivedAt(), bsmDeduplicationResults.get(3).value.getMetadata().getOdeReceivedAt()); - - } catch (JsonMappingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JsonProcessingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/test/java/deduplicator/MapDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/MapDeduplicatorTopologyTest.java deleted file mode 100644 index a3396772..00000000 --- a/jpo-deduplicator/src/test/java/deduplicator/MapDeduplicatorTopologyTest.java +++ /dev/null @@ -1,96 +0,0 @@ -package deduplicator; - - - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KeyValue; -import org.apache.kafka.streams.TestInputTopic; -import org.apache.kafka.streams.TestOutputTopic; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.TopologyTestDriver; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.MapDeduplicatorTopology; -import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; -import us.dot.its.jpo.ode.model.OdeMapData; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; - - -public class MapDeduplicatorTopologyTest { - - String inputTopic = "topic.OdeMapJson"; - String outputTopic = "topic.DeduplicatedOdeMapJson"; - ObjectMapper objectMapper; - - String inputMap1 = "{\"metadata\":{\"logFileName\":\"\",\"recordType\":\"mapTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":null,\"rxSource\":\"NA\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeMapPayload\",\"serialId\":{\"streamId\":\"139ba3af-e501-4854-9327-b9e1a2ed8dfb\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-02-22T21:12:44.308Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"mapSource\":\"RSU\",\"originIp\":\"10.11.81.12\"},\"payload\":{\"data\":{\"timeStamp\":null,\"msgIssueRevision\":2,\"layerType\":\"intersectionData\",\"layerID\":0,\"intersections\":{\"intersectionGeometry\":[{\"name\":null,\"id\":{\"region\":null,\"id\":12109},\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"laneWidth\":366,\"speedLimits\":null,\"laneSet\":{\"GenericLane\":[{\"laneID\":1,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":1511,\"y\":-1514},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":723,\"y\":-3116},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":892,\"y\":-3818},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":702,\"y\":-2507},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":681,\"y\":-2412},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":827,\"y\":-2798},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1176,\"y\":-3614},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":683,\"y\":-1992},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1000,\"y\":-2818},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":466,\"y\":-1295},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2505,\"y\":-6164},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":6037,\"y\":-13380},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":2,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":1192,\"y\":-1619},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":807,\"y\":-3733},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":1010,\"y\":-4226},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":1612,\"y\":-5477},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1142,\"y\":-3648},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1131,\"y\":-3343},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2259,\"y\":-6170},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2359,\"y\":-5737},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":5300,\"y\":-11774},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":50}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":3,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":805,\"y\":-1704},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":380,\"y\":-1813},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":832,\"y\":-3451},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":{\"x\":202,\"y\":-872},\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":{\"x\":340,\"y\":-482},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":6,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-988,\"y\":-2151},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":{\"x\":69,\"y\":-329},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":5,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-630,\"y\":-2062},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":76,\"y\":-377},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":4,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-245,\"y\":-2001},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":76,\"y\":-349},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":10,\"name\":null,\"ingressApproach\":null,\"egressApproach\":4,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2374,\"y\":232},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":-357,\"y\":-96},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":8,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2246,\"y\":-514},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2644,\"y\":-581},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2887,\"y\":-442},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3583,\"y\":-339},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3757,\"y\":27},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3249,\"y\":361},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2050,\"y\":478},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3893,\"y\":1184},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2625,\"y\":766},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2524,\"y\":607},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2280,\"y\":325},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":4,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":7,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2216,\"y\":-915},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2322,\"y\":-471},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1877,\"y\":-349},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1787,\"y\":-235},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2666,\"y\":-102},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":null,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":9,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2295,\"y\":-169},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2420,\"y\":-499},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1968,\"y\":-339},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1843,\"y\":-256},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2121,\"y\":-339},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":4,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":12,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1364,\"y\":1705},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-885,\"y\":4854},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-410,\"y\":2559},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-333,\"y\":1847},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-319,\"y\":3244},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-500,\"y\":4510},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-333,\"y\":3403},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-268,\"y\":2982},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-758,\"y\":11212},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-323,\"y\":11176},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":6,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":13,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-992,\"y\":1735},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-896,\"y\":4816},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-326,\"y\":2227},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-333,\"y\":2366},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-410,\"y\":3030},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-326,\"y\":3009},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-271,\"y\":2518},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-264,\"y\":2857},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-243,\"y\":2504},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-740,\"y\":11165},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-253,\"y\":11359},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":6,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":11,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1744,\"y\":1607},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-563,\"y\":3136},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-352,\"y\":2336},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-223,\"y\":1407},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-155,\"y\":1778},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":null,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":14,\"name\":null,\"ingressApproach\":null,\"egressApproach\":6,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":398,\"y\":1931},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":{\"x\":-76,\"y\":356},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":15,\"name\":null,\"ingressApproach\":null,\"egressApproach\":6,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":838,\"y\":1985},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":{\"x\":-89,\"y\":349},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null}]}}]},\"roadSegments\":null,\"dataParameters\":null,\"restrictionList\":null},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735MAP\"}}"; - String inputMap2 = "{\"metadata\":{\"logFileName\":\"\",\"recordType\":\"mapTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":null,\"rxSource\":\"NA\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeMapPayload\",\"serialId\":{\"streamId\":\"139ba3af-e501-4854-9327-b9e1a2ed8dfb\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-02-22T21:12:45.322Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"mapSource\":\"RSU\",\"originIp\":\"10.11.81.12\"},\"payload\":{\"data\":{\"timeStamp\":null,\"msgIssueRevision\":2,\"layerType\":\"intersectionData\",\"layerID\":0,\"intersections\":{\"intersectionGeometry\":[{\"name\":null,\"id\":{\"region\":null,\"id\":12109},\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"laneWidth\":366,\"speedLimits\":null,\"laneSet\":{\"GenericLane\":[{\"laneID\":1,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":1511,\"y\":-1514},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":723,\"y\":-3116},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":892,\"y\":-3818},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":702,\"y\":-2507},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":681,\"y\":-2412},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":827,\"y\":-2798},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1176,\"y\":-3614},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":683,\"y\":-1992},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1000,\"y\":-2818},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":466,\"y\":-1295},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2505,\"y\":-6164},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":6037,\"y\":-13380},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":2,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":1192,\"y\":-1619},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":807,\"y\":-3733},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":1010,\"y\":-4226},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":1612,\"y\":-5477},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1142,\"y\":-3648},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1131,\"y\":-3343},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2259,\"y\":-6170},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2359,\"y\":-5737},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":5300,\"y\":-11774},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":50}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":3,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":805,\"y\":-1704},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":380,\"y\":-1813},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":832,\"y\":-3451},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":{\"x\":202,\"y\":-872},\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":{\"x\":340,\"y\":-482},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":6,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-988,\"y\":-2151},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":{\"x\":69,\"y\":-329},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":5,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-630,\"y\":-2062},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":76,\"y\":-377},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":4,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-245,\"y\":-2001},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":76,\"y\":-349},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":10,\"name\":null,\"ingressApproach\":null,\"egressApproach\":4,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2374,\"y\":232},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":-357,\"y\":-96},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":8,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2246,\"y\":-514},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2644,\"y\":-581},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2887,\"y\":-442},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3583,\"y\":-339},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3757,\"y\":27},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3249,\"y\":361},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2050,\"y\":478},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3893,\"y\":1184},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2625,\"y\":766},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2524,\"y\":607},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2280,\"y\":325},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":4,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":7,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2216,\"y\":-915},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2322,\"y\":-471},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1877,\"y\":-349},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1787,\"y\":-235},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2666,\"y\":-102},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":null,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":9,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2295,\"y\":-169},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2420,\"y\":-499},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1968,\"y\":-339},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1843,\"y\":-256},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2121,\"y\":-339},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":4,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":12,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1364,\"y\":1705},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-885,\"y\":4854},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-410,\"y\":2559},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-333,\"y\":1847},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-319,\"y\":3244},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-500,\"y\":4510},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-333,\"y\":3403},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-268,\"y\":2982},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-758,\"y\":11212},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-323,\"y\":11176},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":6,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":13,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-992,\"y\":1735},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-896,\"y\":4816},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-326,\"y\":2227},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-333,\"y\":2366},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-410,\"y\":3030},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-326,\"y\":3009},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-271,\"y\":2518},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-264,\"y\":2857},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-243,\"y\":2504},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-740,\"y\":11165},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-253,\"y\":11359},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":6,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":11,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1744,\"y\":1607},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-563,\"y\":3136},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-352,\"y\":2336},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-223,\"y\":1407},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-155,\"y\":1778},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":null,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":14,\"name\":null,\"ingressApproach\":null,\"egressApproach\":6,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":398,\"y\":1931},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":{\"x\":-76,\"y\":356},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":15,\"name\":null,\"ingressApproach\":null,\"egressApproach\":6,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":838,\"y\":1985},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":{\"x\":-89,\"y\":349},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null}]}}]},\"roadSegments\":null,\"dataParameters\":null,\"restrictionList\":null},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735MAP\"}}"; - String inputMap3 = "{\"metadata\":{\"logFileName\":\"\",\"recordType\":\"mapTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":null,\"rxSource\":\"NA\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeMapPayload\",\"serialId\":{\"streamId\":\"139ba3af-e501-4854-9327-b9e1a2ed8dfb\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-02-22T21:12:48.355Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"mapSource\":\"RSU\",\"originIp\":\"10.11.81.12\"},\"payload\":{\"data\":{\"timeStamp\":null,\"msgIssueRevision\":2,\"layerType\":\"intersectionData\",\"layerID\":0,\"intersections\":{\"intersectionGeometry\":[{\"name\":null,\"id\":{\"region\":null,\"id\":12109},\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1500},\"laneWidth\":366,\"speedLimits\":null,\"laneSet\":{\"GenericLane\":[{\"laneID\":1,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":1511,\"y\":-1514},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":723,\"y\":-3116},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":892,\"y\":-3818},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":702,\"y\":-2507},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":681,\"y\":-2412},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":827,\"y\":-2798},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1176,\"y\":-3614},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":683,\"y\":-1992},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1000,\"y\":-2818},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":466,\"y\":-1295},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2505,\"y\":-6164},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":6037,\"y\":-13380},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":2,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":1192,\"y\":-1619},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":807,\"y\":-3733},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":1010,\"y\":-4226},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":1612,\"y\":-5477},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1142,\"y\":-3648},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1131,\"y\":-3343},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2259,\"y\":-6170},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2359,\"y\":-5737},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":5300,\"y\":-11774},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":50}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":3,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":805,\"y\":-1704},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":380,\"y\":-1813},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":832,\"y\":-3451},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":{\"x\":202,\"y\":-872},\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":{\"x\":340,\"y\":-482},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":6,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-988,\"y\":-2151},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":{\"x\":69,\"y\":-329},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":5,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-630,\"y\":-2062},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":76,\"y\":-377},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":4,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-245,\"y\":-2001},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":76,\"y\":-349},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":10,\"name\":null,\"ingressApproach\":null,\"egressApproach\":4,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2374,\"y\":232},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":-357,\"y\":-96},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":8,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2246,\"y\":-514},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2644,\"y\":-581},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2887,\"y\":-442},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3583,\"y\":-339},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3757,\"y\":27},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3249,\"y\":361},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2050,\"y\":478},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3893,\"y\":1184},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2625,\"y\":766},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2524,\"y\":607},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2280,\"y\":325},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":4,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":7,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2216,\"y\":-915},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2322,\"y\":-471},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1877,\"y\":-349},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1787,\"y\":-235},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2666,\"y\":-102},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":null,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":9,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2295,\"y\":-169},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2420,\"y\":-499},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1968,\"y\":-339},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1843,\"y\":-256},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2121,\"y\":-339},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":4,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":12,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1364,\"y\":1705},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-885,\"y\":4854},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-410,\"y\":2559},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-333,\"y\":1847},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-319,\"y\":3244},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-500,\"y\":4510},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-333,\"y\":3403},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-268,\"y\":2982},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-758,\"y\":11212},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-323,\"y\":11176},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":6,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":13,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-992,\"y\":1735},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-896,\"y\":4816},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-326,\"y\":2227},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-333,\"y\":2366},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-410,\"y\":3030},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-326,\"y\":3009},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-271,\"y\":2518},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-264,\"y\":2857},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-243,\"y\":2504},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-740,\"y\":11165},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-253,\"y\":11359},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":6,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":11,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1744,\"y\":1607},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-563,\"y\":3136},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-352,\"y\":2336},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-223,\"y\":1407},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-155,\"y\":1778},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":null,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":14,\"name\":null,\"ingressApproach\":null,\"egressApproach\":6,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":398,\"y\":1931},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":{\"x\":-76,\"y\":356},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":15,\"name\":null,\"ingressApproach\":null,\"egressApproach\":6,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":838,\"y\":1985},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":{\"x\":-89,\"y\":349},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null}]}}]},\"roadSegments\":null,\"dataParameters\":null,\"restrictionList\":null},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735MAP\"}}"; - String inputMap4 = "{\"metadata\":{\"logFileName\":\"\",\"recordType\":\"mapTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":null,\"rxSource\":\"NA\"},\"encodings\":null,\"payloadType\":\"us.dot.its.jpo.ode.model.OdeMapPayload\",\"serialId\":{\"streamId\":\"139ba3af-e501-4854-9327-b9e1a2ed8dfb\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2024-02-22T22:12:49.362Z\",\"schemaVersion\":6,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":null,\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"mapSource\":\"RSU\",\"originIp\":\"10.11.81.12\"},\"payload\":{\"data\":{\"timeStamp\":null,\"msgIssueRevision\":2,\"layerType\":\"intersectionData\",\"layerID\":0,\"intersections\":{\"intersectionGeometry\":[{\"name\":null,\"id\":{\"region\":null,\"id\":12109},\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1500},\"laneWidth\":366,\"speedLimits\":null,\"laneSet\":{\"GenericLane\":[{\"laneID\":1,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":1511,\"y\":-1514},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":723,\"y\":-3116},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":892,\"y\":-3818},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":702,\"y\":-2507},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":681,\"y\":-2412},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":827,\"y\":-2798},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1176,\"y\":-3614},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":683,\"y\":-1992},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1000,\"y\":-2818},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":466,\"y\":-1295},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2505,\"y\":-6164},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":6037,\"y\":-13380},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":2,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":1192,\"y\":-1619},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":807,\"y\":-3733},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":1010,\"y\":-4226},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":1612,\"y\":-5477},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1142,\"y\":-3648},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":1131,\"y\":-3343},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2259,\"y\":-6170},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":2359,\"y\":-5737},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":5300,\"y\":-11774},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":50}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":3,\"name\":null,\"ingressApproach\":1,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":805,\"y\":-1704},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":380,\"y\":-1813},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":832,\"y\":-3451},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":{\"x\":202,\"y\":-872},\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":{\"x\":340,\"y\":-482},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":2,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":6,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-988,\"y\":-2151},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":20}},{\"delta\":{\"nodeXY1\":{\"x\":69,\"y\":-329},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":5,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-630,\"y\":-2062},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":76,\"y\":-377},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":4,\"name\":null,\"ingressApproach\":null,\"egressApproach\":2,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-245,\"y\":-2001},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":76,\"y\":-349},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":10,\"name\":null,\"ingressApproach\":null,\"egressApproach\":4,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2374,\"y\":232},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":{\"x\":-357,\"y\":-96},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":8,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2246,\"y\":-514},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2644,\"y\":-581},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2887,\"y\":-442},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3583,\"y\":-339},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3757,\"y\":27},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3249,\"y\":361},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2050,\"y\":478},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-3893,\"y\":1184},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2625,\"y\":766},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2524,\"y\":607},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2280,\"y\":325},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":4,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":7,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2216,\"y\":-915},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2322,\"y\":-471},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1877,\"y\":-349},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1787,\"y\":-235},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2666,\"y\":-102},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":null,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":9,\"name\":null,\"ingressApproach\":3,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2295,\"y\":-169},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2420,\"y\":-499},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1968,\"y\":-339},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1843,\"y\":-256},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-2121,\"y\":-339},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":4,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":12,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1364,\"y\":1705},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-885,\"y\":4854},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-410,\"y\":2559},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-333,\"y\":1847},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-319,\"y\":3244},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-500,\"y\":4510},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-333,\"y\":3403},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-268,\"y\":2982},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-758,\"y\":11212},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-323,\"y\":11176},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":6,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":13,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-992,\"y\":1735},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":{\"x\":-896,\"y\":4816},\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-326,\"y\":2227},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-333,\"y\":2366},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-410,\"y\":3030},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-326,\"y\":3009},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-271,\"y\":2518},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-264,\"y\":2857},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-243,\"y\":2504},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-740,\"y\":11165},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-30}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":{\"x\":-253,\"y\":11359},\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-70}}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":6,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":11,\"name\":null,\"ingressApproach\":5,\"egressApproach\":null,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":true,\"egressPath\":false},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-1744,\"y\":1607},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-563,\"y\":3136},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":{\"x\":-352,\"y\":2336},\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-223,\"y\":1407},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":10}},{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":-155,\"y\":1778},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":{\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"remoteIntersection\":null,\"signalGroup\":null,\"userClass\":null,\"connectionID\":1}]},\"overlays\":null},{\"laneID\":14,\"name\":null,\"ingressApproach\":null,\"egressApproach\":6,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":398,\"y\":1931},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-10}},{\"delta\":{\"nodeXY1\":{\"x\":-76,\"y\":356},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null},{\"laneID\":15,\"name\":null,\"ingressApproach\":null,\"egressApproach\":6,\"laneAttributes\":{\"directionalUse\":{\"ingressPath\":false,\"egressPath\":true},\"shareWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false},\"crosswalk\":null,\"bikeLane\":null,\"sidewalk\":null,\"median\":null,\"striping\":null,\"trackedVehicle\":null,\"parking\":null}},\"maneuvers\":null,\"nodeList\":{\"computed\":null,\"nodes\":{\"NodeXY\":[{\"delta\":{\"nodeXY1\":null,\"nodeXY2\":null,\"nodeXY3\":{\"x\":838,\"y\":1985},\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":{\"localNode\":null,\"disabled\":null,\"enabled\":null,\"data\":null,\"dWidth\":null,\"dElevation\":-20}},{\"delta\":{\"nodeXY1\":{\"x\":-89,\"y\":349},\"nodeXY2\":null,\"nodeXY3\":null,\"nodeXY4\":null,\"nodeXY5\":null,\"nodeXY6\":null,\"nodeLatLon\":null},\"attributes\":null}]}},\"connectsTo\":null,\"overlays\":null}]}}]},\"roadSegments\":null,\"dataParameters\":null,\"restrictionList\":null},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735MAP\"}}"; - - @Autowired - DeduplicatorProperties props; - - - - @Test - public void testTopology() { - - props = new DeduplicatorProperties(); - props.setKafkaTopicOdeMapJson(inputTopic); - props.setKafkaTopicDeduplicatedOdeMapJson(outputTopic); - - MapDeduplicatorTopology mapDeduplicatorTopology = new MapDeduplicatorTopology(props, null); - - Topology topology = mapDeduplicatorTopology.buildTopology(); - - try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { - - - TestInputTopic inputOdeMapData = driver.createInputTopic( - inputTopic, - Serdes.Void().serializer(), - Serdes.String().serializer()); - - - TestOutputTopic outputOdeMapData = driver.createOutputTopic( - outputTopic, - Serdes.String().deserializer(), - JsonSerdes.OdeMap().deserializer()); - - inputOdeMapData.pipeInput(null, inputMap1); - inputOdeMapData.pipeInput(null, inputMap2); - inputOdeMapData.pipeInput(null, inputMap3); - inputOdeMapData.pipeInput(null, inputMap4); - - List> mapDeduplicationResults = outputOdeMapData.readKeyValuesToList(); - - // validate that only 3 messages make it through - assertEquals(3, mapDeduplicationResults.size()); - - objectMapper = new ObjectMapper(); - OdeMapData map1 = objectMapper.readValue(inputMap1, OdeMapData.class); - OdeMapData map3 = objectMapper.readValue(inputMap3, OdeMapData.class); - OdeMapData map4 = objectMapper.readValue(inputMap4, OdeMapData.class); - - - assertEquals(map1.getMetadata().getOdeReceivedAt(), mapDeduplicationResults.get(0).value.getMetadata().getOdeReceivedAt()); - assertEquals(map3.getMetadata().getOdeReceivedAt(), mapDeduplicationResults.get(1).value.getMetadata().getOdeReceivedAt()); - assertEquals(map4.getMetadata().getOdeReceivedAt(), mapDeduplicationResults.get(2).value.getMetadata().getOdeReceivedAt()); - - } catch (JsonMappingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JsonProcessingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java deleted file mode 100644 index 4b618d9f..00000000 --- a/jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java +++ /dev/null @@ -1,89 +0,0 @@ -package deduplicator; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KeyValue; -import org.apache.kafka.streams.TestInputTopic; -import org.apache.kafka.streams.TestOutputTopic; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.TopologyTestDriver; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.OdeRawEncodedTimDeduplicatorTopology; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; - - -public class OdeRawEncodedTimDeduplicatorTopologyTest { - - String inputTopic = "topic.OdeRawEncodedTIMJson"; - String outputTopic = "topic.DeduplicatedOdeRawEncodedTIMJson"; - - ObjectMapper objectMapper = new ObjectMapper(); - - // Original Message - String inputTim1 = "{ \"metadata\": { \"securityResultCode\": \"success\", \"recordGeneratedBy\": \"RSU\", \"schemaVersion\": 6, \"payloadType\": \"us.dot.its.jpo.ode.model.OdeAsn1Payload\", \"serialId\": { \"recordId\": 0, \"serialNumber\": 0, \"streamId\": \"5f470323-7770-4810-b225-8c45aa672103\", \"bundleSize\": 1, \"bundleId\": 0 }, \"sanitized\": false, \"recordType\": \"timMsg\", \"maxDurationTime\": 0, \"odeReceivedAt\": \"2024-07-22T23:23:29.553Z\", \"originIp\": \"10.16.28.53\" }, \"payload\": { \"data\": { \"bytes\": \"001F63701409FF38D05CD47AF567A4570F775D9B0301C269D16DD9656F9637FFF93F421D3B001EA007F99937E1CF5AD1BB0BF4A9D5BEC5BB25CC5B2E64E173162DA00000000269D16DD9656F9631388C100021000EBF7272441F8CFDED60004008027BBAECD8A1A81EF1C153853DD08B394DDCE85F7F4F2222BE087C98000801004F775D9B002F378A81FD1358540F893502C0B711D815FF7883E0A9AACF804536FC9E2A39A67D4289155859ABA8ACBD4997855D345BA429991568E1CA702BA1D8ADFF4805456C0A46862B7F41BE614A122DFB8B0FA019FC52FC8AFF62A7DA3D3F1C9A00BC220AA6B0DC20571A23C142A8C0368F14D181D9B8E2FA859714531606FF8197DC2D81469C97540A33D8D25850D7CA7E82916C1F82142D3A8A20A4884311C320C8EB2290AD1BAC0C84856E8A1B1D760C51BE458B8189591FF0C64E68D0004008027BBAECD8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\" }, \"dataType\": \"us.dot.its.jpo.ode.model.OdeHexByteArray\" }}"; - - // Shifted Forward .1 seconds - Should be deduplicated - String inputTim2 = "{ \"metadata\": { \"securityResultCode\": \"success\", \"recordGeneratedBy\": \"RSU\", \"schemaVersion\": 6, \"payloadType\": \"us.dot.its.jpo.ode.model.OdeAsn1Payload\", \"serialId\": { \"recordId\": 0, \"serialNumber\": 0, \"streamId\": \"5f470323-7770-4810-b225-8c45aa672103\", \"bundleSize\": 1, \"bundleId\": 0 }, \"sanitized\": false, \"recordType\": \"timMsg\", \"maxDurationTime\": 0, \"odeReceivedAt\": \"2024-07-22T23:23:29.653Z\", \"originIp\": \"10.16.28.53\" }, \"payload\": { \"data\": { \"bytes\": \"001F63701409FF38D05CD47AF567A4570F775D9B0301C269D16DD9656F9637FFF93F421D3B001EA007F99937E1CF5AD1BB0BF4A9D5BEC5BB25CC5B2E64E173162DA00000000269D16DD9656F9631388C100021000EBF7272441F8CFDED60004008027BBAECD8A1A81EF1C153853DD08B394DDCE85F7F4F2222BE087C98000801004F775D9B002F378A81FD1358540F893502C0B711D815FF7883E0A9AACF804536FC9E2A39A67D4289155859ABA8ACBD4997855D345BA429991568E1CA702BA1D8ADFF4805456C0A46862B7F41BE614A122DFB8B0FA019FC52FC8AFF62A7DA3D3F1C9A00BC220AA6B0DC20571A23C142A8C0368F14D181D9B8E2FA859714531606FF8197DC2D81469C97540A33D8D25850D7CA7E82916C1F82142D3A8A20A4884311C320C8EB2290AD1BAC0C84856E8A1B1D760C51BE458B8189591FF0C64E68D0004008027BBAECD8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\" }, \"dataType\": \"us.dot.its.jpo.ode.model.OdeHexByteArray\" }}"; - - // Shifted Forward 1 hour Should be allowed to pass through - String inputTim3 = "{ \"metadata\": { \"securityResultCode\": \"success\", \"recordGeneratedBy\": \"RSU\", \"schemaVersion\": 6, \"payloadType\": \"us.dot.its.jpo.ode.model.OdeAsn1Payload\", \"serialId\": { \"recordId\": 0, \"serialNumber\": 0, \"streamId\": \"5f470323-7770-4810-b225-8c45aa672103\", \"bundleSize\": 1, \"bundleId\": 0 }, \"sanitized\": false, \"recordType\": \"timMsg\", \"maxDurationTime\": 0, \"odeReceivedAt\": \"2024-07-23T00:23:29.653Z\", \"originIp\": \"10.16.28.53\" }, \"payload\": { \"data\": { \"bytes\": \"001F63701409FF38D05CD47AF567A4570F775D9B0301C269D16DD9656F9637FFF93F421D3B001EA007F99937E1CF5AD1BB0BF4A9D5BEC5BB25CC5B2E64E173162DA00000000269D16DD9656F9631388C100021000EBF7272441F8CFDED60004008027BBAECD8A1A81EF1C153853DD08B394DDCE85F7F4F2222BE087C98000801004F775D9B002F378A81FD1358540F893502C0B711D815FF7883E0A9AACF804536FC9E2A39A67D4289155859ABA8ACBD4997855D345BA429991568E1CA702BA1D8ADFF4805456C0A46862B7F41BE614A122DFB8B0FA019FC52FC8AFF62A7DA3D3F1C9A00BC220AA6B0DC20571A23C142A8C0368F14D181D9B8E2FA859714531606FF8197DC2D81469C97540A33D8D25850D7CA7E82916C1F82142D3A8A20A4884311C320C8EB2290AD1BAC0C84856E8A1B1D760C51BE458B8189591FF0C64E68D0004008027BBAECD8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\" }, \"dataType\": \"us.dot.its.jpo.ode.model.OdeHexByteArray\" }}"; - - // Has a different payload ID. Should be allowed through - String inputTim4 = "{ \"metadata\": { \"securityResultCode\": \"success\", \"recordGeneratedBy\": \"RSU\", \"schemaVersion\": 6, \"payloadType\": \"us.dot.its.jpo.ode.model.OdeAsn1Payload\", \"serialId\": { \"recordId\": 0, \"serialNumber\": 0, \"streamId\": \"5f470323-7770-4810-b225-8c45aa672103\", \"bundleSize\": 1, \"bundleId\": 0 }, \"sanitized\": false, \"recordType\": \"timMsg\", \"maxDurationTime\": 0, \"odeReceivedAt\": \"2024-07-22T23:23:29.553Z\", \"originIp\": \"10.16.28.53\" }, \"payload\": { \"data\": { \"bytes\": \"001F63701409FF38D05CD47AF567A4570F775D9B0301C269D16DD9656F9637FFF93F421D3B001EA007F99937E1CF5AD1BB0BF4A9D5BEC5BB25CC5B2E64E173162DA00000000269D16DD9656F9631388C100021000EBF7272441F8CFDED60004008027BBAECD8A1A81EF1C153853DD08B394DDCE85F7F4F2222BE087C98000801004F775D9B002F378A81FD1358540F893502C0B711D815FF7883E0A9AACF804536FC9E2A39A67D4289155859ABA8ACBD4997855D345BA429991568E1CA702BA1D8ADFF4805456C0A46862B7F41BE614A122DFB8B0FA019FC52FC8AFF62A7DA3D3F1C9A00BC220AA6B0DC20571A23C142A8C0368F14D181D9B8E2FA859714531606FF8197DC2D81469C97540A33D8D25850D7CA7E82916C1F82142D3A8A20A4884311C320C8EB2290AD1BAC0C84856E8A1B1D760C51BE458B8189591FF0C64E68D0004008027BBAECD9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\" }, \"dataType\": \"us.dot.its.jpo.ode.model.OdeHexByteArray\" }}"; - - @Autowired - DeduplicatorProperties props; - - @Test - public void testTopology() { - - props = new DeduplicatorProperties(); - props.setKafkaTopicOdeRawEncodedTimJson(inputTopic); - props.setKafkaTopicDeduplicatedOdeRawEncodedTimJson(outputTopic); - - OdeRawEncodedTimDeduplicatorTopology TimDeduplicatorTopology = new OdeRawEncodedTimDeduplicatorTopology(props, null); - - Topology topology = TimDeduplicatorTopology.buildTopology(); - objectMapper.registerModule(new JavaTimeModule()); - - try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { - - - TestInputTopic inputTimData = driver.createInputTopic( - inputTopic, - Serdes.Void().serializer(), - Serdes.String().serializer()); - - - TestOutputTopic outputTimData = driver.createOutputTopic( - outputTopic, - Serdes.String().deserializer(), - Serdes.String().deserializer()); - - inputTimData.pipeInput(null, inputTim1); - inputTimData.pipeInput(null, inputTim2); - inputTimData.pipeInput(null, inputTim3); - inputTimData.pipeInput(null, inputTim4); - - List> timDeduplicatedResults = outputTimData.readKeyValuesToList(); - - // validate that only 3 messages make it through - assertEquals(3, timDeduplicatedResults.size()); - inputTim1 = inputTim1.strip(); - - assertEquals(inputTim1.replace(" ", ""), timDeduplicatedResults.get(0).value.replace(" ", "")); - assertEquals(inputTim3.replace(" ", ""), timDeduplicatedResults.get(1).value.replace(" ", "")); - assertEquals(inputTim4.replace(" ", ""), timDeduplicatedResults.get(2).value.replace(" ", "")); - - }catch(Exception e){ - e.printStackTrace(); - } - } -} diff --git a/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapDeduplicatorTopologyTest.java deleted file mode 100644 index 331bfdcd..00000000 --- a/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapDeduplicatorTopologyTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package deduplicator; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KeyValue; -import org.apache.kafka.streams.TestInputTopic; -import org.apache.kafka.streams.TestOutputTopic; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.TopologyTestDriver; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedMapDeduplicatorTopology; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; -import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; - - -public class ProcessedMapDeduplicatorTopologyTest { - - String inputTopic = "topic.ProcessedMap"; - String outputTopic = "topic.DeduplicatedProcessedMap"; - - - TypeReference> typeReference = new TypeReference<>(){}; - ObjectMapper objectMapper = new ObjectMapper(); - - String inputProcessedMap1 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0906245,39.5876246],[-105.0905203,39.587281],[-105.0904383,39.5870554],[-105.0903588,39.5868383],[-105.0902622,39.5865865],[-105.0901249,39.5862612],[-105.0900451,39.5860819],[-105.0899283,39.5858283],[-105.0898739,39.5857117],[-105.0895814,39.5851569],[-105.0888764,39.5839527]]},\"properties\":{\"nodes\":[{\"delta\":[1511,-1514]},{\"delta\":[723,-3116],\"delevation\":10},{\"delta\":[892,-3818],\"delevation\":20},{\"delta\":[702,-2507],\"delevation\":20},{\"delta\":[681,-2412],\"delevation\":10},{\"delta\":[827,-2798],\"delevation\":10},{\"delta\":[1176,-3614],\"delevation\":20},{\"delta\":[683,-1992]},{\"delta\":[1000,-2818],\"delevation\":10},{\"delta\":[466,-1295],\"delevation\":20},{\"delta\":[2505,-6164],\"delevation\":20},{\"delta\":[6037,-13380],\"delevation\":70}],\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.090652,39.5875596],[-105.090534,39.5871793],[-105.0903457,39.5866864],[-105.0902123,39.5863581],[-105.0900802,39.5860572],[-105.0898164,39.5855019],[-105.0895409,39.5849856],[-105.088922,39.5839259]]},\"properties\":{\"nodes\":[{\"delta\":[1192,-1619]},{\"delta\":[807,-3733],\"delevation\":30},{\"delta\":[1010,-4226],\"delevation\":10},{\"delta\":[1612,-5477],\"delevation\":30},{\"delta\":[1142,-3648],\"delevation\":20},{\"delta\":[1131,-3343],\"delevation\":10},{\"delta\":[2259,-6170],\"delevation\":30},{\"delta\":[2359,-5737],\"delevation\":30},{\"delta\":[5300,-11774],\"delevation\":50}],\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.090747,39.5877247],[-105.0906498,39.5874141],[-105.0906262,39.5873356],[-105.0905865,39.5872922]]},\"properties\":{\"nodes\":[{\"delta\":[805,-1704],\"delevation\":10},{\"delta\":[380,-1813]},{\"delta\":[832,-3451],\"delevation\":30},{\"delta\":[202,-872]},{\"delta\":[340,-482],\"delevation\":-10}],\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910008,39.5878477],[-105.0909927,39.5878181]]},\"properties\":{\"nodes\":[{\"delta\":[-988,-2151],\"delevation\":20},{\"delta\":[69,-329]}],\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090959,39.5878557],[-105.0909501,39.5878218]]},\"properties\":{\"nodes\":[{\"delta\":[-630,-2062],\"delevation\":10},{\"delta\":[76,-377],\"delevation\":10}],\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090914,39.5878612],[-105.0909051,39.5878298]]},\"properties\":{\"nodes\":[{\"delta\":[-245,-2001],\"delevation\":10},{\"delta\":[76,-349]}],\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911626,39.5880622],[-105.0912043,39.5880536]]},\"properties\":{\"nodes\":[{\"delta\":[-2374,232],\"delevation\":10},{\"delta\":[-357,-96]}],\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0914565,39.5879427],[-105.0917937,39.5879029],[-105.0922121,39.5878724],[-105.0926509,39.5878748],[-105.0930303,39.5879073],[-105.0932697,39.5879503],[-105.0937243,39.5880569],[-105.0940309,39.5881258],[-105.0943257,39.5881804],[-105.094592,39.5882097]]},\"properties\":{\"nodes\":[{\"delta\":[-2246,-514],\"delevation\":10},{\"delta\":[-2644,-581]},{\"delta\":[-2887,-442],\"delevation\":10},{\"delta\":[-3583,-339],\"delevation\":10},{\"delta\":[-3757,27]},{\"delta\":[-3249,361],\"delevation\":-10},{\"delta\":[-2050,478]},{\"delta\":[-3893,1184]},{\"delta\":[-2625,766],\"delevation\":-10},{\"delta\":[-2524,607],\"delevation\":10},{\"delta\":[-2280,325],\"delevation\":10}],\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0914154,39.5879165],[-105.0916346,39.5878851],[-105.0918433,39.5878639],[-105.0921546,39.5878547]]},\"properties\":{\"nodes\":[{\"delta\":[-2216,-915],\"delevation\":10},{\"delta\":[-2322,-471]},{\"delta\":[-1877,-349],\"delevation\":10},{\"delta\":[-1787,-235]},{\"delta\":[-2666,-102],\"delevation\":10}],\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.091436,39.5879812],[-105.0916658,39.5879507],[-105.091881,39.5879277],[-105.0921287,39.5878972]]},\"properties\":{\"nodes\":[{\"delta\":[-2295,-169],\"delevation\":10},{\"delta\":[-2420,-499]},{\"delta\":[-1968,-339],\"delevation\":10},{\"delta\":[-1843,-256]},{\"delta\":[-2121,-339]}],\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.0911481,39.5886317],[-105.091196,39.588862],[-105.0912349,39.5890282],[-105.0912722,39.5893202],[-105.0913306,39.5897261],[-105.0913695,39.5900324],[-105.0914008,39.5903008],[-105.0914893,39.5913099],[-105.091527,39.5923157]]},\"properties\":{\"nodes\":[{\"delta\":[-1364,1705],\"delevation\":10},{\"delta\":[-885,4854],\"delevation\":-30},{\"delta\":[-410,2559],\"delevation\":10},{\"delta\":[-333,1847],\"delevation\":-10},{\"delta\":[-319,3244],\"delevation\":-20},{\"delta\":[-500,4510]},{\"delta\":[-333,3403],\"delevation\":-30},{\"delta\":[-268,2982]},{\"delta\":[-758,11212],\"delevation\":-30},{\"delta\":[-323,11176],\"delevation\":-70}],\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.0911059,39.5886309],[-105.091144,39.5888313],[-105.0911829,39.5890442],[-105.0912308,39.5893169],[-105.0912689,39.5895877],[-105.0913005,39.5898143],[-105.0913313,39.5900714],[-105.0913597,39.5902968],[-105.0914461,39.5913017],[-105.0914756,39.592324]]},\"properties\":{\"nodes\":[{\"delta\":[-992,1735],\"delevation\":10},{\"delta\":[-896,4816],\"delevation\":-30},{\"delta\":[-326,2227],\"delevation\":10},{\"delta\":[-333,2366]},{\"delta\":[-410,3030],\"delevation\":-20},{\"delta\":[-326,3009],\"delevation\":-10},{\"delta\":[-271,2518],\"delevation\":-10},{\"delta\":[-264,2857],\"delevation\":-20},{\"delta\":[-243,2504]},{\"delta\":[-740,11165],\"delevation\":-30},{\"delta\":[-253,11359],\"delevation\":-70}],\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911549,39.5884681],[-105.091196,39.5886783],[-105.091222,39.5888049],[-105.0912401,39.5889649]]},\"properties\":{\"nodes\":[{\"delta\":[-1744,1607],\"delevation\":10},{\"delta\":[-563,3136],\"delevation\":-20},{\"delta\":[-352,2336],\"delevation\":-10},{\"delta\":[-223,1407],\"delevation\":10},{\"delta\":[-155,1778]}],\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0908389,39.5882151],[-105.0908478,39.5882471]]},\"properties\":{\"nodes\":[{\"delta\":[398,1931],\"delevation\":-10},{\"delta\":[-76,356]}],\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907875,39.58822],[-105.0907979,39.5882514]]},\"properties\":{\"nodes\":[{\"delta\":[838,1985],\"delevation\":-20},{\"delta\":[-89,349]}],\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.0911626,39.5880622]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0910008,39.5878477]]},\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.090959,39.5878557]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.090914,39.5878612]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911626,39.5880622]]},\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-02-22T23:26:21.06Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits\",\"schemaPath\":\"#/$defs/J2735SpeedLimitList_Wrapper/type\"}],\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-02-22T23:26:21.06Z\"}}"; - String inputProcessedMap2 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0906245,39.5876246],[-105.0905203,39.587281],[-105.0904383,39.5870554],[-105.0903588,39.5868383],[-105.0902622,39.5865865],[-105.0901249,39.5862612],[-105.0900451,39.5860819],[-105.0899283,39.5858283],[-105.0898739,39.5857117],[-105.0895814,39.5851569],[-105.0888764,39.5839527]]},\"properties\":{\"nodes\":[{\"delta\":[1511,-1514]},{\"delta\":[723,-3116],\"delevation\":10},{\"delta\":[892,-3818],\"delevation\":20},{\"delta\":[702,-2507],\"delevation\":20},{\"delta\":[681,-2412],\"delevation\":10},{\"delta\":[827,-2798],\"delevation\":10},{\"delta\":[1176,-3614],\"delevation\":20},{\"delta\":[683,-1992]},{\"delta\":[1000,-2818],\"delevation\":10},{\"delta\":[466,-1295],\"delevation\":20},{\"delta\":[2505,-6164],\"delevation\":20},{\"delta\":[6037,-13380],\"delevation\":70}],\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.090652,39.5875596],[-105.090534,39.5871793],[-105.0903457,39.5866864],[-105.0902123,39.5863581],[-105.0900802,39.5860572],[-105.0898164,39.5855019],[-105.0895409,39.5849856],[-105.088922,39.5839259]]},\"properties\":{\"nodes\":[{\"delta\":[1192,-1619]},{\"delta\":[807,-3733],\"delevation\":30},{\"delta\":[1010,-4226],\"delevation\":10},{\"delta\":[1612,-5477],\"delevation\":30},{\"delta\":[1142,-3648],\"delevation\":20},{\"delta\":[1131,-3343],\"delevation\":10},{\"delta\":[2259,-6170],\"delevation\":30},{\"delta\":[2359,-5737],\"delevation\":30},{\"delta\":[5300,-11774],\"delevation\":50}],\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.090747,39.5877247],[-105.0906498,39.5874141],[-105.0906262,39.5873356],[-105.0905865,39.5872922]]},\"properties\":{\"nodes\":[{\"delta\":[805,-1704],\"delevation\":10},{\"delta\":[380,-1813]},{\"delta\":[832,-3451],\"delevation\":30},{\"delta\":[202,-872]},{\"delta\":[340,-482],\"delevation\":-10}],\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910008,39.5878477],[-105.0909927,39.5878181]]},\"properties\":{\"nodes\":[{\"delta\":[-988,-2151],\"delevation\":20},{\"delta\":[69,-329]}],\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090959,39.5878557],[-105.0909501,39.5878218]]},\"properties\":{\"nodes\":[{\"delta\":[-630,-2062],\"delevation\":10},{\"delta\":[76,-377],\"delevation\":10}],\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090914,39.5878612],[-105.0909051,39.5878298]]},\"properties\":{\"nodes\":[{\"delta\":[-245,-2001],\"delevation\":10},{\"delta\":[76,-349]}],\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911626,39.5880622],[-105.0912043,39.5880536]]},\"properties\":{\"nodes\":[{\"delta\":[-2374,232],\"delevation\":10},{\"delta\":[-357,-96]}],\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0914565,39.5879427],[-105.0917937,39.5879029],[-105.0922121,39.5878724],[-105.0926509,39.5878748],[-105.0930303,39.5879073],[-105.0932697,39.5879503],[-105.0937243,39.5880569],[-105.0940309,39.5881258],[-105.0943257,39.5881804],[-105.094592,39.5882097]]},\"properties\":{\"nodes\":[{\"delta\":[-2246,-514],\"delevation\":10},{\"delta\":[-2644,-581]},{\"delta\":[-2887,-442],\"delevation\":10},{\"delta\":[-3583,-339],\"delevation\":10},{\"delta\":[-3757,27]},{\"delta\":[-3249,361],\"delevation\":-10},{\"delta\":[-2050,478]},{\"delta\":[-3893,1184]},{\"delta\":[-2625,766],\"delevation\":-10},{\"delta\":[-2524,607],\"delevation\":10},{\"delta\":[-2280,325],\"delevation\":10}],\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0914154,39.5879165],[-105.0916346,39.5878851],[-105.0918433,39.5878639],[-105.0921546,39.5878547]]},\"properties\":{\"nodes\":[{\"delta\":[-2216,-915],\"delevation\":10},{\"delta\":[-2322,-471]},{\"delta\":[-1877,-349],\"delevation\":10},{\"delta\":[-1787,-235]},{\"delta\":[-2666,-102],\"delevation\":10}],\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.091436,39.5879812],[-105.0916658,39.5879507],[-105.091881,39.5879277],[-105.0921287,39.5878972]]},\"properties\":{\"nodes\":[{\"delta\":[-2295,-169],\"delevation\":10},{\"delta\":[-2420,-499]},{\"delta\":[-1968,-339],\"delevation\":10},{\"delta\":[-1843,-256]},{\"delta\":[-2121,-339]}],\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.0911481,39.5886317],[-105.091196,39.588862],[-105.0912349,39.5890282],[-105.0912722,39.5893202],[-105.0913306,39.5897261],[-105.0913695,39.5900324],[-105.0914008,39.5903008],[-105.0914893,39.5913099],[-105.091527,39.5923157]]},\"properties\":{\"nodes\":[{\"delta\":[-1364,1705],\"delevation\":10},{\"delta\":[-885,4854],\"delevation\":-30},{\"delta\":[-410,2559],\"delevation\":10},{\"delta\":[-333,1847],\"delevation\":-10},{\"delta\":[-319,3244],\"delevation\":-20},{\"delta\":[-500,4510]},{\"delta\":[-333,3403],\"delevation\":-30},{\"delta\":[-268,2982]},{\"delta\":[-758,11212],\"delevation\":-30},{\"delta\":[-323,11176],\"delevation\":-70}],\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.0911059,39.5886309],[-105.091144,39.5888313],[-105.0911829,39.5890442],[-105.0912308,39.5893169],[-105.0912689,39.5895877],[-105.0913005,39.5898143],[-105.0913313,39.5900714],[-105.0913597,39.5902968],[-105.0914461,39.5913017],[-105.0914756,39.592324]]},\"properties\":{\"nodes\":[{\"delta\":[-992,1735],\"delevation\":10},{\"delta\":[-896,4816],\"delevation\":-30},{\"delta\":[-326,2227],\"delevation\":10},{\"delta\":[-333,2366]},{\"delta\":[-410,3030],\"delevation\":-20},{\"delta\":[-326,3009],\"delevation\":-10},{\"delta\":[-271,2518],\"delevation\":-10},{\"delta\":[-264,2857],\"delevation\":-20},{\"delta\":[-243,2504]},{\"delta\":[-740,11165],\"delevation\":-30},{\"delta\":[-253,11359],\"delevation\":-70}],\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911549,39.5884681],[-105.091196,39.5886783],[-105.091222,39.5888049],[-105.0912401,39.5889649]]},\"properties\":{\"nodes\":[{\"delta\":[-1744,1607],\"delevation\":10},{\"delta\":[-563,3136],\"delevation\":-20},{\"delta\":[-352,2336],\"delevation\":-10},{\"delta\":[-223,1407],\"delevation\":10},{\"delta\":[-155,1778]}],\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0908389,39.5882151],[-105.0908478,39.5882471]]},\"properties\":{\"nodes\":[{\"delta\":[398,1931],\"delevation\":-10},{\"delta\":[-76,356]}],\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907875,39.58822],[-105.0907979,39.5882514]]},\"properties\":{\"nodes\":[{\"delta\":[838,1985],\"delevation\":-20},{\"delta\":[-89,349]}],\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.0911626,39.5880622]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0910008,39.5878477]]},\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.090959,39.5878557]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.090914,39.5878612]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911626,39.5880622]]},\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-02-22T23:26:22.074Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits\",\"schemaPath\":\"#/$defs/J2735SpeedLimitList_Wrapper/type\"}],\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-02-22T23:26:22.074Z\"}}"; - String inputProcessedMap3 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0906245,39.5876246],[-105.0905203,39.587281],[-105.0904383,39.5870554],[-105.0903588,39.5868383],[-105.0902622,39.5865865],[-105.0901249,39.5862612],[-105.0900451,39.5860819],[-105.0899283,39.5858283],[-105.0898739,39.5857117],[-105.0895814,39.5851569],[-105.0888764,39.5839527]]},\"properties\":{\"nodes\":[{\"delta\":[1511,-1514]},{\"delta\":[723,-3116],\"delevation\":10},{\"delta\":[892,-3818],\"delevation\":20},{\"delta\":[702,-2507],\"delevation\":20},{\"delta\":[681,-2412],\"delevation\":10},{\"delta\":[827,-2798],\"delevation\":10},{\"delta\":[1176,-3614],\"delevation\":20},{\"delta\":[683,-1992]},{\"delta\":[1000,-2818],\"delevation\":10},{\"delta\":[466,-1295],\"delevation\":20},{\"delta\":[2505,-6164],\"delevation\":20},{\"delta\":[6037,-13380],\"delevation\":70}],\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.090652,39.5875596],[-105.090534,39.5871793],[-105.0903457,39.5866864],[-105.0902123,39.5863581],[-105.0900802,39.5860572],[-105.0898164,39.5855019],[-105.0895409,39.5849856],[-105.088922,39.5839259]]},\"properties\":{\"nodes\":[{\"delta\":[1192,-1619]},{\"delta\":[807,-3733],\"delevation\":30},{\"delta\":[1010,-4226],\"delevation\":10},{\"delta\":[1612,-5477],\"delevation\":30},{\"delta\":[1142,-3648],\"delevation\":20},{\"delta\":[1131,-3343],\"delevation\":10},{\"delta\":[2259,-6170],\"delevation\":30},{\"delta\":[2359,-5737],\"delevation\":30},{\"delta\":[5300,-11774],\"delevation\":50}],\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.090747,39.5877247],[-105.0906498,39.5874141],[-105.0906262,39.5873356],[-105.0905865,39.5872922]]},\"properties\":{\"nodes\":[{\"delta\":[805,-1704],\"delevation\":10},{\"delta\":[380,-1813]},{\"delta\":[832,-3451],\"delevation\":30},{\"delta\":[202,-872]},{\"delta\":[340,-482],\"delevation\":-10}],\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910008,39.5878477],[-105.0909927,39.5878181]]},\"properties\":{\"nodes\":[{\"delta\":[-988,-2151],\"delevation\":20},{\"delta\":[69,-329]}],\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090959,39.5878557],[-105.0909501,39.5878218]]},\"properties\":{\"nodes\":[{\"delta\":[-630,-2062],\"delevation\":10},{\"delta\":[76,-377],\"delevation\":10}],\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090914,39.5878612],[-105.0909051,39.5878298]]},\"properties\":{\"nodes\":[{\"delta\":[-245,-2001],\"delevation\":10},{\"delta\":[76,-349]}],\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911626,39.5880622],[-105.0912043,39.5880536]]},\"properties\":{\"nodes\":[{\"delta\":[-2374,232],\"delevation\":10},{\"delta\":[-357,-96]}],\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0914565,39.5879427],[-105.0917937,39.5879029],[-105.0922121,39.5878724],[-105.0926509,39.5878748],[-105.0930303,39.5879073],[-105.0932697,39.5879503],[-105.0937243,39.5880569],[-105.0940309,39.5881258],[-105.0943257,39.5881804],[-105.094592,39.5882097]]},\"properties\":{\"nodes\":[{\"delta\":[-2246,-514],\"delevation\":10},{\"delta\":[-2644,-581]},{\"delta\":[-2887,-442],\"delevation\":10},{\"delta\":[-3583,-339],\"delevation\":10},{\"delta\":[-3757,27]},{\"delta\":[-3249,361],\"delevation\":-10},{\"delta\":[-2050,478]},{\"delta\":[-3893,1184]},{\"delta\":[-2625,766],\"delevation\":-10},{\"delta\":[-2524,607],\"delevation\":10},{\"delta\":[-2280,325],\"delevation\":10}],\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0914154,39.5879165],[-105.0916346,39.5878851],[-105.0918433,39.5878639],[-105.0921546,39.5878547]]},\"properties\":{\"nodes\":[{\"delta\":[-2216,-915],\"delevation\":10},{\"delta\":[-2322,-471]},{\"delta\":[-1877,-349],\"delevation\":10},{\"delta\":[-1787,-235]},{\"delta\":[-2666,-102],\"delevation\":10}],\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.091436,39.5879812],[-105.0916658,39.5879507],[-105.091881,39.5879277],[-105.0921287,39.5878972]]},\"properties\":{\"nodes\":[{\"delta\":[-2295,-169],\"delevation\":10},{\"delta\":[-2420,-499]},{\"delta\":[-1968,-339],\"delevation\":10},{\"delta\":[-1843,-256]},{\"delta\":[-2121,-339]}],\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.0911481,39.5886317],[-105.091196,39.588862],[-105.0912349,39.5890282],[-105.0912722,39.5893202],[-105.0913306,39.5897261],[-105.0913695,39.5900324],[-105.0914008,39.5903008],[-105.0914893,39.5913099],[-105.091527,39.5923157]]},\"properties\":{\"nodes\":[{\"delta\":[-1364,1705],\"delevation\":10},{\"delta\":[-885,4854],\"delevation\":-30},{\"delta\":[-410,2559],\"delevation\":10},{\"delta\":[-333,1847],\"delevation\":-10},{\"delta\":[-319,3244],\"delevation\":-20},{\"delta\":[-500,4510]},{\"delta\":[-333,3403],\"delevation\":-30},{\"delta\":[-268,2982]},{\"delta\":[-758,11212],\"delevation\":-30},{\"delta\":[-323,11176],\"delevation\":-70}],\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.0911059,39.5886309],[-105.091144,39.5888313],[-105.0911829,39.5890442],[-105.0912308,39.5893169],[-105.0912689,39.5895877],[-105.0913005,39.5898143],[-105.0913313,39.5900714],[-105.0913597,39.5902968],[-105.0914461,39.5913017],[-105.0914756,39.592324]]},\"properties\":{\"nodes\":[{\"delta\":[-992,1735],\"delevation\":10},{\"delta\":[-896,4816],\"delevation\":-30},{\"delta\":[-326,2227],\"delevation\":10},{\"delta\":[-333,2366]},{\"delta\":[-410,3030],\"delevation\":-20},{\"delta\":[-326,3009],\"delevation\":-10},{\"delta\":[-271,2518],\"delevation\":-10},{\"delta\":[-264,2857],\"delevation\":-20},{\"delta\":[-243,2504]},{\"delta\":[-740,11165],\"delevation\":-30},{\"delta\":[-253,11359],\"delevation\":-70}],\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911549,39.5884681],[-105.091196,39.5886783],[-105.091222,39.5888049],[-105.0912401,39.5889649]]},\"properties\":{\"nodes\":[{\"delta\":[-1744,1607],\"delevation\":10},{\"delta\":[-563,3136],\"delevation\":-20},{\"delta\":[-352,2336],\"delevation\":-10},{\"delta\":[-223,1407],\"delevation\":10},{\"delta\":[-155,1778]}],\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0908389,39.5882151],[-105.0908478,39.5882471]]},\"properties\":{\"nodes\":[{\"delta\":[398,1931],\"delevation\":-10},{\"delta\":[-76,356]}],\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907875,39.58822],[-105.0907979,39.5882514]]},\"properties\":{\"nodes\":[{\"delta\":[838,1985],\"delevation\":-20},{\"delta\":[-89,349]}],\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.0911626,39.5880622]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0910008,39.5878477]]},\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.090959,39.5878557]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.090914,39.5878612]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911626,39.5880622]]},\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-02-22T23:26:25.107Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1500},\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits\",\"schemaPath\":\"#/$defs/J2735SpeedLimitList_Wrapper/type\"}],\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-02-22T23:26:25.107Z\"}}"; - String inputProcessedMap4 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0906245,39.5876246],[-105.0905203,39.587281],[-105.0904383,39.5870554],[-105.0903588,39.5868383],[-105.0902622,39.5865865],[-105.0901249,39.5862612],[-105.0900451,39.5860819],[-105.0899283,39.5858283],[-105.0898739,39.5857117],[-105.0895814,39.5851569],[-105.0888764,39.5839527]]},\"properties\":{\"nodes\":[{\"delta\":[1511,-1514]},{\"delta\":[723,-3116],\"delevation\":10},{\"delta\":[892,-3818],\"delevation\":20},{\"delta\":[702,-2507],\"delevation\":20},{\"delta\":[681,-2412],\"delevation\":10},{\"delta\":[827,-2798],\"delevation\":10},{\"delta\":[1176,-3614],\"delevation\":20},{\"delta\":[683,-1992]},{\"delta\":[1000,-2818],\"delevation\":10},{\"delta\":[466,-1295],\"delevation\":20},{\"delta\":[2505,-6164],\"delevation\":20},{\"delta\":[6037,-13380],\"delevation\":70}],\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.090652,39.5875596],[-105.090534,39.5871793],[-105.0903457,39.5866864],[-105.0902123,39.5863581],[-105.0900802,39.5860572],[-105.0898164,39.5855019],[-105.0895409,39.5849856],[-105.088922,39.5839259]]},\"properties\":{\"nodes\":[{\"delta\":[1192,-1619]},{\"delta\":[807,-3733],\"delevation\":30},{\"delta\":[1010,-4226],\"delevation\":10},{\"delta\":[1612,-5477],\"delevation\":30},{\"delta\":[1142,-3648],\"delevation\":20},{\"delta\":[1131,-3343],\"delevation\":10},{\"delta\":[2259,-6170],\"delevation\":30},{\"delta\":[2359,-5737],\"delevation\":30},{\"delta\":[5300,-11774],\"delevation\":50}],\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.090747,39.5877247],[-105.0906498,39.5874141],[-105.0906262,39.5873356],[-105.0905865,39.5872922]]},\"properties\":{\"nodes\":[{\"delta\":[805,-1704],\"delevation\":10},{\"delta\":[380,-1813]},{\"delta\":[832,-3451],\"delevation\":30},{\"delta\":[202,-872]},{\"delta\":[340,-482],\"delevation\":-10}],\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910008,39.5878477],[-105.0909927,39.5878181]]},\"properties\":{\"nodes\":[{\"delta\":[-988,-2151],\"delevation\":20},{\"delta\":[69,-329]}],\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090959,39.5878557],[-105.0909501,39.5878218]]},\"properties\":{\"nodes\":[{\"delta\":[-630,-2062],\"delevation\":10},{\"delta\":[76,-377],\"delevation\":10}],\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090914,39.5878612],[-105.0909051,39.5878298]]},\"properties\":{\"nodes\":[{\"delta\":[-245,-2001],\"delevation\":10},{\"delta\":[76,-349]}],\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911626,39.5880622],[-105.0912043,39.5880536]]},\"properties\":{\"nodes\":[{\"delta\":[-2374,232],\"delevation\":10},{\"delta\":[-357,-96]}],\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0914565,39.5879427],[-105.0917937,39.5879029],[-105.0922121,39.5878724],[-105.0926509,39.5878748],[-105.0930303,39.5879073],[-105.0932697,39.5879503],[-105.0937243,39.5880569],[-105.0940309,39.5881258],[-105.0943257,39.5881804],[-105.094592,39.5882097]]},\"properties\":{\"nodes\":[{\"delta\":[-2246,-514],\"delevation\":10},{\"delta\":[-2644,-581]},{\"delta\":[-2887,-442],\"delevation\":10},{\"delta\":[-3583,-339],\"delevation\":10},{\"delta\":[-3757,27]},{\"delta\":[-3249,361],\"delevation\":-10},{\"delta\":[-2050,478]},{\"delta\":[-3893,1184]},{\"delta\":[-2625,766],\"delevation\":-10},{\"delta\":[-2524,607],\"delevation\":10},{\"delta\":[-2280,325],\"delevation\":10}],\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0914154,39.5879165],[-105.0916346,39.5878851],[-105.0918433,39.5878639],[-105.0921546,39.5878547]]},\"properties\":{\"nodes\":[{\"delta\":[-2216,-915],\"delevation\":10},{\"delta\":[-2322,-471]},{\"delta\":[-1877,-349],\"delevation\":10},{\"delta\":[-1787,-235]},{\"delta\":[-2666,-102],\"delevation\":10}],\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.091436,39.5879812],[-105.0916658,39.5879507],[-105.091881,39.5879277],[-105.0921287,39.5878972]]},\"properties\":{\"nodes\":[{\"delta\":[-2295,-169],\"delevation\":10},{\"delta\":[-2420,-499]},{\"delta\":[-1968,-339],\"delevation\":10},{\"delta\":[-1843,-256]},{\"delta\":[-2121,-339]}],\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.0911481,39.5886317],[-105.091196,39.588862],[-105.0912349,39.5890282],[-105.0912722,39.5893202],[-105.0913306,39.5897261],[-105.0913695,39.5900324],[-105.0914008,39.5903008],[-105.0914893,39.5913099],[-105.091527,39.5923157]]},\"properties\":{\"nodes\":[{\"delta\":[-1364,1705],\"delevation\":10},{\"delta\":[-885,4854],\"delevation\":-30},{\"delta\":[-410,2559],\"delevation\":10},{\"delta\":[-333,1847],\"delevation\":-10},{\"delta\":[-319,3244],\"delevation\":-20},{\"delta\":[-500,4510]},{\"delta\":[-333,3403],\"delevation\":-30},{\"delta\":[-268,2982]},{\"delta\":[-758,11212],\"delevation\":-30},{\"delta\":[-323,11176],\"delevation\":-70}],\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.0911059,39.5886309],[-105.091144,39.5888313],[-105.0911829,39.5890442],[-105.0912308,39.5893169],[-105.0912689,39.5895877],[-105.0913005,39.5898143],[-105.0913313,39.5900714],[-105.0913597,39.5902968],[-105.0914461,39.5913017],[-105.0914756,39.592324]]},\"properties\":{\"nodes\":[{\"delta\":[-992,1735],\"delevation\":10},{\"delta\":[-896,4816],\"delevation\":-30},{\"delta\":[-326,2227],\"delevation\":10},{\"delta\":[-333,2366]},{\"delta\":[-410,3030],\"delevation\":-20},{\"delta\":[-326,3009],\"delevation\":-10},{\"delta\":[-271,2518],\"delevation\":-10},{\"delta\":[-264,2857],\"delevation\":-20},{\"delta\":[-243,2504]},{\"delta\":[-740,11165],\"delevation\":-30},{\"delta\":[-253,11359],\"delevation\":-70}],\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911549,39.5884681],[-105.091196,39.5886783],[-105.091222,39.5888049],[-105.0912401,39.5889649]]},\"properties\":{\"nodes\":[{\"delta\":[-1744,1607],\"delevation\":10},{\"delta\":[-563,3136],\"delevation\":-20},{\"delta\":[-352,2336],\"delevation\":-10},{\"delta\":[-223,1407],\"delevation\":10},{\"delta\":[-155,1778]}],\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0908389,39.5882151],[-105.0908478,39.5882471]]},\"properties\":{\"nodes\":[{\"delta\":[398,1931],\"delevation\":-10},{\"delta\":[-76,356]}],\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907875,39.58822],[-105.0907979,39.5882514]]},\"properties\":{\"nodes\":[{\"delta\":[838,1985],\"delevation\":-20},{\"delta\":[-89,349]}],\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.0911626,39.5880622]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0910008,39.5878477]]},\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.090959,39.5878557]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.090914,39.5878612]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911626,39.5880622]]},\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-02-22T23:26:26.114Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits\",\"schemaPath\":\"#/$defs/J2735SpeedLimitList_Wrapper/type\"}],\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-02-22T23:26:26.114Z\"}}"; - - - String key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; - - @Autowired - DeduplicatorProperties props; - - - @Test - public void testTopology() { - - props = new DeduplicatorProperties(); - props.setKafkaTopicProcessedMap(inputTopic); - props.setKafkaTopicDeduplicatedProcessedMap(outputTopic); - - ProcessedMapDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapDeduplicatorTopology(props, null); - - Topology topology = processedMapDeduplicatorTopology.buildTopology(); - objectMapper.registerModule(new JavaTimeModule()); - - try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { - - - TestInputTopic inputProcessedMapData = driver.createInputTopic( - inputTopic, - Serdes.String().serializer(), - Serdes.String().serializer()); - - - TestOutputTopic> outputProcessedMapData = driver.createOutputTopic( - outputTopic, - Serdes.String().deserializer(), - JsonSerdes.ProcessedMapGeoJson().deserializer()); - - inputProcessedMapData.pipeInput(key, inputProcessedMap1); - inputProcessedMapData.pipeInput(key, inputProcessedMap2); - inputProcessedMapData.pipeInput(key, inputProcessedMap3); - inputProcessedMapData.pipeInput(key, inputProcessedMap4); - - List>> mapDeduplicatorResults = outputProcessedMapData.readKeyValuesToList(); - - // validate that only 3 messages make it through - assertEquals(3, mapDeduplicatorResults.size()); - - ProcessedMap map1 = objectMapper.readValue(inputProcessedMap1, typeReference); - ProcessedMap map3 = objectMapper.readValue(inputProcessedMap3, typeReference); - ProcessedMap map4 = objectMapper.readValue(inputProcessedMap4, typeReference); - - assertEquals(map1.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(0).value.getProperties().getOdeReceivedAt()); - assertEquals(map3.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(1).value.getProperties().getOdeReceivedAt()); - assertEquals(map4.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(2).value.getProperties().getOdeReceivedAt()); - - } catch (JsonMappingException e) { - e.printStackTrace(); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - } -} diff --git a/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java deleted file mode 100644 index 7b1d2fb0..00000000 --- a/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java +++ /dev/null @@ -1,101 +0,0 @@ -package deduplicator; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KeyValue; -import org.apache.kafka.streams.TestInputTopic; -import org.apache.kafka.streams.TestOutputTopic; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.TopologyTestDriver; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedMapWktDeduplicatorTopology; -import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; -import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; - -public class ProcessedMapWktDeduplicatorTopologyTest { - - String inputTopic = "topic.ProcessedMapWKT"; - String outputTopic = "topic.DeduplicatedProcessedMapWKT"; - - - TypeReference> typeReference = new TypeReference<>(){}; - ObjectMapper objectMapper = new ObjectMapper(); - - String inputProcessedMapWkt1 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":\"LINESTRING (-105.0907089 39.587905, -105.0906245 39.5876246, -105.0905203 39.587281, -105.0904383 39.5870554, -105.0903588 39.5868383, -105.0902622 39.5865865, -105.0901249 39.5862612, -105.0900451 39.5860819, -105.0899283 39.5858283, -105.0898739 39.5857117, -105.0895814 39.5851569, -105.0888764 39.5839527)\",\"properties\":{\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":\"LINESTRING (-105.0907462 39.5878956, -105.090652 39.5875596, -105.090534 39.5871793, -105.0903457 39.5866864, -105.0902123 39.5863581, -105.0900802 39.5860572, -105.0898164 39.5855019, -105.0895409 39.5849856, -105.088922 39.5839259)\",\"properties\":{\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":\"LINESTRING (-105.0907914 39.5878879, -105.090747 39.5877247, -105.0906498 39.5874141, -105.0906262 39.5873356, -105.0905865 39.5872922)\",\"properties\":{\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":\"LINESTRING (-105.0910008 39.5878477, -105.0909927 39.5878181)\",\"properties\":{\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":\"LINESTRING (-105.090959 39.5878557, -105.0909501 39.5878218)\",\"properties\":{\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":\"LINESTRING (-105.090914 39.5878612, -105.0909051 39.5878298)\",\"properties\":{\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":\"LINESTRING (-105.0911626 39.5880622, -105.0912043 39.5880536)\",\"properties\":{\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":\"LINESTRING (-105.0911477 39.587995, -105.0914565 39.5879427, -105.0917937 39.5879029, -105.0922121 39.5878724, -105.0926509 39.5878748, -105.0930303 39.5879073, -105.0932697 39.5879503, -105.0937243 39.5880569, -105.0940309 39.5881258, -105.0943257 39.5881804, -105.094592 39.5882097)\",\"properties\":{\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":\"LINESTRING (-105.0911442 39.5879589, -105.0914154 39.5879165, -105.0916346 39.5878851, -105.0918433 39.5878639, -105.0921546 39.5878547)\",\"properties\":{\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":\"LINESTRING (-105.0911534 39.5880261, -105.091436 39.5879812, -105.0916658 39.5879507, -105.091881 39.5879277, -105.0921287 39.5878972)\",\"properties\":{\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":\"LINESTRING (-105.0910447 39.5881948, -105.0911481 39.5886317, -105.091196 39.588862, -105.0912349 39.5890282, -105.0912722 39.5893202, -105.0913306 39.5897261, -105.0913695 39.5900324, -105.0914008 39.5903008, -105.0914893 39.5913099, -105.091527 39.5923157)\",\"properties\":{\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":\"LINESTRING (-105.0910013 39.5881975, -105.0911059 39.5886309, -105.091144 39.5888313, -105.0911829 39.5890442, -105.0912308 39.5893169, -105.0912689 39.5895877, -105.0913005 39.5898143, -105.0913313 39.5900714, -105.0913597 39.5902968, -105.0914461 39.5913017, -105.0914756 39.592324)\",\"properties\":{\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":\"LINESTRING (-105.0910891 39.5881859, -105.0911549 39.5884681, -105.091196 39.5886783, -105.091222 39.5888049, -105.0912401 39.5889649)\",\"properties\":{\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":\"LINESTRING (-105.0908389 39.5882151, -105.0908478 39.5882471)\",\"properties\":{\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":\"LINESTRING (-105.0907875 39.58822, -105.0907979 39.5882514)\",\"properties\":{\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":\"LINESTRING (-105.0907089 39.587905, -105.0907875 39.58822)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":\"LINESTRING (-105.0907462 39.5878956, -105.0908389 39.5882151)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":\"LINESTRING (-105.0907914 39.5878879, -105.0911626 39.5880622)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":\"LINESTRING (-105.0911477 39.587995, -105.0907875 39.58822)\",\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":\"LINESTRING (-105.0911442 39.5879589, -105.0910008 39.5878477)\",\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":\"LINESTRING (-105.0911534 39.5880261, -105.0908389 39.5882151)\",\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":\"LINESTRING (-105.0910447 39.5881948, -105.090959 39.5878557)\",\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":\"LINESTRING (-105.0910013 39.5881975, -105.090914 39.5878612)\",\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":\"LINESTRING (-105.0910891 39.5881859, -105.0911626 39.5880622)\",\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-05-06T21:35:21.713Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1500},\"cti4501Conformant\":false,\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-05-06T21:35:21.713Z\"}}"; - - - //String inputProcessedMapWkt1 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0906245,39.5876246],[-105.0905203,39.587281],[-105.0904383,39.5870554],[-105.0903588,39.5868383],[-105.0902622,39.5865865],[-105.0901249,39.5862612],[-105.0900451,39.5860819],[-105.0899283,39.5858283],[-105.0898739,39.5857117],[-105.0895814,39.5851569],[-105.0888764,39.5839527]]},\"properties\":{\"nodes\":[{\"delta\":[1511,-1514]},{\"delta\":[723,-3116],\"delevation\":10},{\"delta\":[892,-3818],\"delevation\":20},{\"delta\":[702,-2507],\"delevation\":20},{\"delta\":[681,-2412],\"delevation\":10},{\"delta\":[827,-2798],\"delevation\":10},{\"delta\":[1176,-3614],\"delevation\":20},{\"delta\":[683,-1992]},{\"delta\":[1000,-2818],\"delevation\":10},{\"delta\":[466,-1295],\"delevation\":20},{\"delta\":[2505,-6164],\"delevation\":20},{\"delta\":[6037,-13380],\"delevation\":70}],\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.090652,39.5875596],[-105.090534,39.5871793],[-105.0903457,39.5866864],[-105.0902123,39.5863581],[-105.0900802,39.5860572],[-105.0898164,39.5855019],[-105.0895409,39.5849856],[-105.088922,39.5839259]]},\"properties\":{\"nodes\":[{\"delta\":[1192,-1619]},{\"delta\":[807,-3733],\"delevation\":30},{\"delta\":[1010,-4226],\"delevation\":10},{\"delta\":[1612,-5477],\"delevation\":30},{\"delta\":[1142,-3648],\"delevation\":20},{\"delta\":[1131,-3343],\"delevation\":10},{\"delta\":[2259,-6170],\"delevation\":30},{\"delta\":[2359,-5737],\"delevation\":30},{\"delta\":[5300,-11774],\"delevation\":50}],\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.090747,39.5877247],[-105.0906498,39.5874141],[-105.0906262,39.5873356],[-105.0905865,39.5872922]]},\"properties\":{\"nodes\":[{\"delta\":[805,-1704],\"delevation\":10},{\"delta\":[380,-1813]},{\"delta\":[832,-3451],\"delevation\":30},{\"delta\":[202,-872]},{\"delta\":[340,-482],\"delevation\":-10}],\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910008,39.5878477],[-105.0909927,39.5878181]]},\"properties\":{\"nodes\":[{\"delta\":[-988,-2151],\"delevation\":20},{\"delta\":[69,-329]}],\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090959,39.5878557],[-105.0909501,39.5878218]]},\"properties\":{\"nodes\":[{\"delta\":[-630,-2062],\"delevation\":10},{\"delta\":[76,-377],\"delevation\":10}],\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.090914,39.5878612],[-105.0909051,39.5878298]]},\"properties\":{\"nodes\":[{\"delta\":[-245,-2001],\"delevation\":10},{\"delta\":[76,-349]}],\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911626,39.5880622],[-105.0912043,39.5880536]]},\"properties\":{\"nodes\":[{\"delta\":[-2374,232],\"delevation\":10},{\"delta\":[-357,-96]}],\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0914565,39.5879427],[-105.0917937,39.5879029],[-105.0922121,39.5878724],[-105.0926509,39.5878748],[-105.0930303,39.5879073],[-105.0932697,39.5879503],[-105.0937243,39.5880569],[-105.0940309,39.5881258],[-105.0943257,39.5881804],[-105.094592,39.5882097]]},\"properties\":{\"nodes\":[{\"delta\":[-2246,-514],\"delevation\":10},{\"delta\":[-2644,-581]},{\"delta\":[-2887,-442],\"delevation\":10},{\"delta\":[-3583,-339],\"delevation\":10},{\"delta\":[-3757,27]},{\"delta\":[-3249,361],\"delevation\":-10},{\"delta\":[-2050,478]},{\"delta\":[-3893,1184]},{\"delta\":[-2625,766],\"delevation\":-10},{\"delta\":[-2524,607],\"delevation\":10},{\"delta\":[-2280,325],\"delevation\":10}],\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0914154,39.5879165],[-105.0916346,39.5878851],[-105.0918433,39.5878639],[-105.0921546,39.5878547]]},\"properties\":{\"nodes\":[{\"delta\":[-2216,-915],\"delevation\":10},{\"delta\":[-2322,-471]},{\"delta\":[-1877,-349],\"delevation\":10},{\"delta\":[-1787,-235]},{\"delta\":[-2666,-102],\"delevation\":10}],\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.091436,39.5879812],[-105.0916658,39.5879507],[-105.091881,39.5879277],[-105.0921287,39.5878972]]},\"properties\":{\"nodes\":[{\"delta\":[-2295,-169],\"delevation\":10},{\"delta\":[-2420,-499]},{\"delta\":[-1968,-339],\"delevation\":10},{\"delta\":[-1843,-256]},{\"delta\":[-2121,-339]}],\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.0911481,39.5886317],[-105.091196,39.588862],[-105.0912349,39.5890282],[-105.0912722,39.5893202],[-105.0913306,39.5897261],[-105.0913695,39.5900324],[-105.0914008,39.5903008],[-105.0914893,39.5913099],[-105.091527,39.5923157]]},\"properties\":{\"nodes\":[{\"delta\":[-1364,1705],\"delevation\":10},{\"delta\":[-885,4854],\"delevation\":-30},{\"delta\":[-410,2559],\"delevation\":10},{\"delta\":[-333,1847],\"delevation\":-10},{\"delta\":[-319,3244],\"delevation\":-20},{\"delta\":[-500,4510]},{\"delta\":[-333,3403],\"delevation\":-30},{\"delta\":[-268,2982]},{\"delta\":[-758,11212],\"delevation\":-30},{\"delta\":[-323,11176],\"delevation\":-70}],\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.0911059,39.5886309],[-105.091144,39.5888313],[-105.0911829,39.5890442],[-105.0912308,39.5893169],[-105.0912689,39.5895877],[-105.0913005,39.5898143],[-105.0913313,39.5900714],[-105.0913597,39.5902968],[-105.0914461,39.5913017],[-105.0914756,39.592324]]},\"properties\":{\"nodes\":[{\"delta\":[-992,1735],\"delevation\":10},{\"delta\":[-896,4816],\"delevation\":-30},{\"delta\":[-326,2227],\"delevation\":10},{\"delta\":[-333,2366]},{\"delta\":[-410,3030],\"delevation\":-20},{\"delta\":[-326,3009],\"delevation\":-10},{\"delta\":[-271,2518],\"delevation\":-10},{\"delta\":[-264,2857],\"delevation\":-20},{\"delta\":[-243,2504]},{\"delta\":[-740,11165],\"delevation\":-30},{\"delta\":[-253,11359],\"delevation\":-70}],\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911549,39.5884681],[-105.091196,39.5886783],[-105.091222,39.5888049],[-105.0912401,39.5889649]]},\"properties\":{\"nodes\":[{\"delta\":[-1744,1607],\"delevation\":10},{\"delta\":[-563,3136],\"delevation\":-20},{\"delta\":[-352,2336],\"delevation\":-10},{\"delta\":[-223,1407],\"delevation\":10},{\"delta\":[-155,1778]}],\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0908389,39.5882151],[-105.0908478,39.5882471]]},\"properties\":{\"nodes\":[{\"delta\":[398,1931],\"delevation\":-10},{\"delta\":[-76,356]}],\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907875,39.58822],[-105.0907979,39.5882514]]},\"properties\":{\"nodes\":[{\"delta\":[838,1985],\"delevation\":-20},{\"delta\":[-89,349]}],\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907089,39.587905],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907462,39.5878956],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0907914,39.5878879],[-105.0911626,39.5880622]]},\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911477,39.587995],[-105.0907875,39.58822]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911442,39.5879589],[-105.0910008,39.5878477]]},\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0911534,39.5880261],[-105.0908389,39.5882151]]},\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910447,39.5881948],[-105.090959,39.5878557]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910013,39.5881975],[-105.090914,39.5878612]]},\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":{\"type\":\"LineString\",\"coordinates\":[[-105.0910891,39.5881859],[-105.0911626,39.5880622]]},\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-02-22T23:26:26.114Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].id.region: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].id.region\",\"schemaPath\":\"#/$defs/J2735RoadRegulatorID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[3].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup: null found, integer expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0].signalGroup\",\"schemaPath\":\"#/$defs/J2735SignalGroupID/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[13].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].connectsTo\",\"schemaPath\":\"#/$defs/J2735ConnectsToList_Wrapper/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[14].maneuvers\",\"schemaPath\":\"#/$defs/J2735AllowedManeuvers/type\"},{\"message\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits: null found, object expected\",\"jsonPath\":\"$.payload.data.intersections.intersectionGeometry[0].speedLimits\",\"schemaPath\":\"#/$defs/J2735SpeedLimitList_Wrapper/type\"}],\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-02-22T23:26:26.114Z\"}}"; - String inputProcessedMapWkt2 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":\"LINESTRING (-105.0907089 39.587905, -105.0906245 39.5876246, -105.0905203 39.587281, -105.0904383 39.5870554, -105.0903588 39.5868383, -105.0902622 39.5865865, -105.0901249 39.5862612, -105.0900451 39.5860819, -105.0899283 39.5858283, -105.0898739 39.5857117, -105.0895814 39.5851569, -105.0888764 39.5839527)\",\"properties\":{\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":\"LINESTRING (-105.0907462 39.5878956, -105.090652 39.5875596, -105.090534 39.5871793, -105.0903457 39.5866864, -105.0902123 39.5863581, -105.0900802 39.5860572, -105.0898164 39.5855019, -105.0895409 39.5849856, -105.088922 39.5839259)\",\"properties\":{\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":\"LINESTRING (-105.0907914 39.5878879, -105.090747 39.5877247, -105.0906498 39.5874141, -105.0906262 39.5873356, -105.0905865 39.5872922)\",\"properties\":{\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":\"LINESTRING (-105.0910008 39.5878477, -105.0909927 39.5878181)\",\"properties\":{\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":\"LINESTRING (-105.090959 39.5878557, -105.0909501 39.5878218)\",\"properties\":{\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":\"LINESTRING (-105.090914 39.5878612, -105.0909051 39.5878298)\",\"properties\":{\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":\"LINESTRING (-105.0911626 39.5880622, -105.0912043 39.5880536)\",\"properties\":{\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":\"LINESTRING (-105.0911477 39.587995, -105.0914565 39.5879427, -105.0917937 39.5879029, -105.0922121 39.5878724, -105.0926509 39.5878748, -105.0930303 39.5879073, -105.0932697 39.5879503, -105.0937243 39.5880569, -105.0940309 39.5881258, -105.0943257 39.5881804, -105.094592 39.5882097)\",\"properties\":{\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":\"LINESTRING (-105.0911442 39.5879589, -105.0914154 39.5879165, -105.0916346 39.5878851, -105.0918433 39.5878639, -105.0921546 39.5878547)\",\"properties\":{\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":\"LINESTRING (-105.0911534 39.5880261, -105.091436 39.5879812, -105.0916658 39.5879507, -105.091881 39.5879277, -105.0921287 39.5878972)\",\"properties\":{\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":\"LINESTRING (-105.0910447 39.5881948, -105.0911481 39.5886317, -105.091196 39.588862, -105.0912349 39.5890282, -105.0912722 39.5893202, -105.0913306 39.5897261, -105.0913695 39.5900324, -105.0914008 39.5903008, -105.0914893 39.5913099, -105.091527 39.5923157)\",\"properties\":{\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":\"LINESTRING (-105.0910013 39.5881975, -105.0911059 39.5886309, -105.091144 39.5888313, -105.0911829 39.5890442, -105.0912308 39.5893169, -105.0912689 39.5895877, -105.0913005 39.5898143, -105.0913313 39.5900714, -105.0913597 39.5902968, -105.0914461 39.5913017, -105.0914756 39.592324)\",\"properties\":{\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":\"LINESTRING (-105.0910891 39.5881859, -105.0911549 39.5884681, -105.091196 39.5886783, -105.091222 39.5888049, -105.0912401 39.5889649)\",\"properties\":{\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":\"LINESTRING (-105.0908389 39.5882151, -105.0908478 39.5882471)\",\"properties\":{\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":\"LINESTRING (-105.0907875 39.58822, -105.0907979 39.5882514)\",\"properties\":{\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":\"LINESTRING (-105.0907089 39.587905, -105.0907875 39.58822)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":\"LINESTRING (-105.0907462 39.5878956, -105.0908389 39.5882151)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":\"LINESTRING (-105.0907914 39.5878879, -105.0911626 39.5880622)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":\"LINESTRING (-105.0911477 39.587995, -105.0907875 39.58822)\",\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":\"LINESTRING (-105.0911442 39.5879589, -105.0910008 39.5878477)\",\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":\"LINESTRING (-105.0911534 39.5880261, -105.0908389 39.5882151)\",\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":\"LINESTRING (-105.0910447 39.5881948, -105.090959 39.5878557)\",\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":\"LINESTRING (-105.0910013 39.5881975, -105.090914 39.5878612)\",\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":\"LINESTRING (-105.0910891 39.5881859, -105.0911626 39.5880622)\",\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-05-03T20:58:48.748Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-05-03T20:58:48.748Z\"}}"; - String inputProcessedMapWkt3 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":\"LINESTRING (-105.0907089 39.587905, -105.0906245 39.5876246, -105.0905203 39.587281, -105.0904383 39.5870554, -105.0903588 39.5868383, -105.0902622 39.5865865, -105.0901249 39.5862612, -105.0900451 39.5860819, -105.0899283 39.5858283, -105.0898739 39.5857117, -105.0895814 39.5851569, -105.0888764 39.5839527)\",\"properties\":{\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":\"LINESTRING (-105.0907462 39.5878956, -105.090652 39.5875596, -105.090534 39.5871793, -105.0903457 39.5866864, -105.0902123 39.5863581, -105.0900802 39.5860572, -105.0898164 39.5855019, -105.0895409 39.5849856, -105.088922 39.5839259)\",\"properties\":{\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":\"LINESTRING (-105.0907914 39.5878879, -105.090747 39.5877247, -105.0906498 39.5874141, -105.0906262 39.5873356, -105.0905865 39.5872922)\",\"properties\":{\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":\"LINESTRING (-105.0910008 39.5878477, -105.0909927 39.5878181)\",\"properties\":{\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":\"LINESTRING (-105.090959 39.5878557, -105.0909501 39.5878218)\",\"properties\":{\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":\"LINESTRING (-105.090914 39.5878612, -105.0909051 39.5878298)\",\"properties\":{\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":\"LINESTRING (-105.0911626 39.5880622, -105.0912043 39.5880536)\",\"properties\":{\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":\"LINESTRING (-105.0911477 39.587995, -105.0914565 39.5879427, -105.0917937 39.5879029, -105.0922121 39.5878724, -105.0926509 39.5878748, -105.0930303 39.5879073, -105.0932697 39.5879503, -105.0937243 39.5880569, -105.0940309 39.5881258, -105.0943257 39.5881804, -105.094592 39.5882097)\",\"properties\":{\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":\"LINESTRING (-105.0911442 39.5879589, -105.0914154 39.5879165, -105.0916346 39.5878851, -105.0918433 39.5878639, -105.0921546 39.5878547)\",\"properties\":{\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":\"LINESTRING (-105.0911534 39.5880261, -105.091436 39.5879812, -105.0916658 39.5879507, -105.091881 39.5879277, -105.0921287 39.5878972)\",\"properties\":{\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":\"LINESTRING (-105.0910447 39.5881948, -105.0911481 39.5886317, -105.091196 39.588862, -105.0912349 39.5890282, -105.0912722 39.5893202, -105.0913306 39.5897261, -105.0913695 39.5900324, -105.0914008 39.5903008, -105.0914893 39.5913099, -105.091527 39.5923157)\",\"properties\":{\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":\"LINESTRING (-105.0910013 39.5881975, -105.0911059 39.5886309, -105.091144 39.5888313, -105.0911829 39.5890442, -105.0912308 39.5893169, -105.0912689 39.5895877, -105.0913005 39.5898143, -105.0913313 39.5900714, -105.0913597 39.5902968, -105.0914461 39.5913017, -105.0914756 39.592324)\",\"properties\":{\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":\"LINESTRING (-105.0910891 39.5881859, -105.0911549 39.5884681, -105.091196 39.5886783, -105.091222 39.5888049, -105.0912401 39.5889649)\",\"properties\":{\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":\"LINESTRING (-105.0908389 39.5882151, -105.0908478 39.5882471)\",\"properties\":{\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":\"LINESTRING (-105.0907875 39.58822, -105.0907979 39.5882514)\",\"properties\":{\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":\"LINESTRING (-105.0907089 39.587905, -105.0907875 39.58822)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":\"LINESTRING (-105.0907462 39.5878956, -105.0908389 39.5882151)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":\"LINESTRING (-105.0907914 39.5878879, -105.0911626 39.5880622)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":\"LINESTRING (-105.0911477 39.587995, -105.0907875 39.58822)\",\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":\"LINESTRING (-105.0911442 39.5879589, -105.0910008 39.5878477)\",\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":\"LINESTRING (-105.0911534 39.5880261, -105.0908389 39.5882151)\",\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":\"LINESTRING (-105.0910447 39.5881948, -105.090959 39.5878557)\",\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":\"LINESTRING (-105.0910013 39.5881975, -105.090914 39.5878612)\",\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":\"LINESTRING (-105.0910891 39.5881859, -105.0911626 39.5880622)\",\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-05-03T20:58:48.748Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-05-03T20:59:48.748Z\"}}"; - String inputProcessedMapWkt4 = "{\"mapFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"geometry\":\"LINESTRING (-105.0907089 39.587905, -105.0906245 39.5876246, -105.0905203 39.587281, -105.0904383 39.5870554, -105.0903588 39.5868383, -105.0902622 39.5865865, -105.0901249 39.5862612, -105.0900451 39.5860819, -105.0899283 39.5858283, -105.0898739 39.5857117, -105.0895814 39.5851569, -105.0888764 39.5839527)\",\"properties\":{\"laneId\":1,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":2,\"geometry\":\"LINESTRING (-105.0907462 39.5878956, -105.090652 39.5875596, -105.090534 39.5871793, -105.0903457 39.5866864, -105.0902123 39.5863581, -105.0900802 39.5860572, -105.0898164 39.5855019, -105.0895409 39.5849856, -105.088922 39.5839259)\",\"properties\":{\"laneId\":2,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":3,\"geometry\":\"LINESTRING (-105.0907914 39.5878879, -105.090747 39.5877247, -105.0906498 39.5874141, -105.0906262 39.5873356, -105.0905865 39.5872922)\",\"properties\":{\"laneId\":3,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":1,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":2,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":6,\"geometry\":\"LINESTRING (-105.0910008 39.5878477, -105.0909927 39.5878181)\",\"properties\":{\"laneId\":6,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":5,\"geometry\":\"LINESTRING (-105.090959 39.5878557, -105.0909501 39.5878218)\",\"properties\":{\"laneId\":5,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":4,\"geometry\":\"LINESTRING (-105.090914 39.5878612, -105.0909051 39.5878298)\",\"properties\":{\"laneId\":4,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":2,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":10,\"geometry\":\"LINESTRING (-105.0911626 39.5880622, -105.0912043 39.5880536)\",\"properties\":{\"laneId\":10,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":4,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":8,\"geometry\":\"LINESTRING (-105.0911477 39.587995, -105.0914565 39.5879427, -105.0917937 39.5879029, -105.0922121 39.5878724, -105.0926509 39.5878748, -105.0930303 39.5879073, -105.0932697 39.5879503, -105.0937243 39.5880569, -105.0940309 39.5881258, -105.0943257 39.5881804, -105.094592 39.5882097)\",\"properties\":{\"laneId\":8,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":15,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":7,\"geometry\":\"LINESTRING (-105.0911442 39.5879589, -105.0914154 39.5879165, -105.0916346 39.5878851, -105.0918433 39.5878639, -105.0921546 39.5878547)\",\"properties\":{\"laneId\":7,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":6,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":9,\"geometry\":\"LINESTRING (-105.0911534 39.5880261, -105.091436 39.5879812, -105.0916658 39.5879507, -105.091881 39.5879277, -105.0921287 39.5878972)\",\"properties\":{\"laneId\":9,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":3,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":14,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":true,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":4,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":12,\"geometry\":\"LINESTRING (-105.0910447 39.5881948, -105.0911481 39.5886317, -105.091196 39.588862, -105.0912349 39.5890282, -105.0912722 39.5893202, -105.0913306 39.5897261, -105.0913695 39.5900324, -105.0914008 39.5903008, -105.0914893 39.5913099, -105.091527 39.5923157)\",\"properties\":{\"laneId\":12,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":5,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":13,\"geometry\":\"LINESTRING (-105.0910013 39.5881975, -105.0911059 39.5886309, -105.091144 39.5888313, -105.0911829 39.5890442, -105.0912308 39.5893169, -105.0912689 39.5895877, -105.0913005 39.5898143, -105.0913313 39.5900714, -105.0913597 39.5902968, -105.0914461 39.5913017, -105.0914756 39.592324)\",\"properties\":{\"laneId\":13,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":4,\"maneuver\":{\"maneuverStraightAllowed\":true,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":false,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"signalGroup\":6,\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":11,\"geometry\":\"LINESTRING (-105.0910891 39.5881859, -105.0911549 39.5884681, -105.091196 39.5886783, -105.091222 39.5888049, -105.0912401 39.5889649)\",\"properties\":{\"laneId\":11,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":0,\"ingressApproach\":5,\"ingressPath\":true,\"egressPath\":false,\"maneuvers\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false},\"connectsTo\":[{\"connectingLane\":{\"lane\":10,\"maneuver\":{\"maneuverStraightAllowed\":false,\"maneuverNoStoppingAllowed\":false,\"goWithHalt\":false,\"maneuverLeftAllowed\":false,\"maneuverUTurnAllowed\":false,\"maneuverLeftTurnOnRedAllowed\":false,\"reserved1\":false,\"maneuverRightAllowed\":true,\"maneuverLaneChangeAllowed\":false,\"yieldAllwaysRequired\":false,\"maneuverRightTurnOnRedAllowed\":false,\"caution\":false}},\"connectionID\":1}]}},{\"type\":\"Feature\",\"id\":14,\"geometry\":\"LINESTRING (-105.0908389 39.5882151, -105.0908478 39.5882471)\",\"properties\":{\"laneId\":14,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}},{\"type\":\"Feature\",\"id\":15,\"geometry\":\"LINESTRING (-105.0907875 39.58822, -105.0907979 39.5882514)\",\"properties\":{\"laneId\":15,\"laneType\":{\"vehicle\":{\"isVehicleRevocableLane\":false,\"isVehicleFlyOverLane\":false,\"permissionOnRequest\":false,\"hasIRbeaconCoverage\":false,\"restrictedToBusUse\":false,\"restrictedToTaxiUse\":false,\"restrictedFromPublicUse\":false,\"hovLaneUseOnly\":false}},\"sharedWith\":{\"busVehicleTraffic\":false,\"trackedVehicleTraffic\":false,\"individualMotorizedVehicleTraffic\":false,\"taxiVehicleTraffic\":false,\"overlappingLaneDescriptionProvided\":false,\"cyclistVehicleTraffic\":false,\"otherNonMotorizedTrafficTypes\":false,\"multipleLanesTreatedAsOneLane\":false,\"pedestrianTraffic\":false,\"pedestriansTraffic\":false},\"egressApproach\":6,\"ingressApproach\":0,\"ingressPath\":false,\"egressPath\":true}}]},\"connectingLanesFeatureCollection\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":\"1-15\",\"geometry\":\"LINESTRING (-105.0907089 39.587905, -105.0907875 39.58822)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":1,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"2-14\",\"geometry\":\"LINESTRING (-105.0907462 39.5878956, -105.0908389 39.5882151)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":2,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"3-10\",\"geometry\":\"LINESTRING (-105.0907914 39.5878879, -105.0911626 39.5880622)\",\"properties\":{\"signalGroupId\":2,\"ingressLaneId\":3,\"egressLaneId\":10}},{\"type\":\"Feature\",\"id\":\"8-15\",\"geometry\":\"LINESTRING (-105.0911477 39.587995, -105.0907875 39.58822)\",\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":8,\"egressLaneId\":15}},{\"type\":\"Feature\",\"id\":\"7-6\",\"geometry\":\"LINESTRING (-105.0911442 39.5879589, -105.0910008 39.5878477)\",\"properties\":{\"ingressLaneId\":7,\"egressLaneId\":6}},{\"type\":\"Feature\",\"id\":\"9-14\",\"geometry\":\"LINESTRING (-105.0911534 39.5880261, -105.0908389 39.5882151)\",\"properties\":{\"signalGroupId\":4,\"ingressLaneId\":9,\"egressLaneId\":14}},{\"type\":\"Feature\",\"id\":\"12-5\",\"geometry\":\"LINESTRING (-105.0910447 39.5881948, -105.090959 39.5878557)\",\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":12,\"egressLaneId\":5}},{\"type\":\"Feature\",\"id\":\"13-4\",\"geometry\":\"LINESTRING (-105.0910013 39.5881975, -105.090914 39.5878612)\",\"properties\":{\"signalGroupId\":6,\"ingressLaneId\":13,\"egressLaneId\":4}},{\"type\":\"Feature\",\"id\":\"11-10\",\"geometry\":\"LINESTRING (-105.0910891 39.5881859, -105.0911626 39.5880622)\",\"properties\":{\"ingressLaneId\":11,\"egressLaneId\":10}}]},\"properties\":{\"messageType\":\"MAP\",\"odeReceivedAt\":\"2024-05-03T20:58:48.748Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":2,\"refPoint\":{\"latitude\":39.5880413,\"longitude\":-105.0908854,\"elevation\":1691},\"cti4501Conformant\":false,\"laneWidth\":366,\"mapSource\":\"RSU\",\"timeStamp\":\"2024-05-03T22:00:48.748Z\"}}"; - - String key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; - - @Autowired - DeduplicatorProperties props; - - - @Test - public void testTopology() { - - props = new DeduplicatorProperties(); - props.setKafkaTopicProcessedMapWKT(inputTopic); - props.setKafkaTopicDeduplicatedProcessedMapWKT(outputTopic); - - ProcessedMapWktDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapWktDeduplicatorTopology(props, null); - - Topology topology = processedMapDeduplicatorTopology.buildTopology(); - objectMapper.registerModule(new JavaTimeModule()); - - try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { - - - TestInputTopic inputProcessedMapData = driver.createInputTopic( - inputTopic, - Serdes.String().serializer(), - Serdes.String().serializer()); - - - TestOutputTopic> outputProcessedMapData = driver.createOutputTopic( - outputTopic, - Serdes.String().deserializer(), - JsonSerdes.ProcessedMapWKT().deserializer()); - - inputProcessedMapData.pipeInput(key, inputProcessedMapWkt1); - inputProcessedMapData.pipeInput(key, inputProcessedMapWkt2); - inputProcessedMapData.pipeInput(key, inputProcessedMapWkt3); - inputProcessedMapData.pipeInput(key, inputProcessedMapWkt4); - - List>> mapDeduplicatorResults = outputProcessedMapData.readKeyValuesToList(); - - // validate that only 3 messages make it through - assertEquals(3, mapDeduplicatorResults.size()); - - ProcessedMap map1 = objectMapper.readValue(inputProcessedMapWkt1, typeReference); - ProcessedMap map2 = objectMapper.readValue(inputProcessedMapWkt2, typeReference); - ProcessedMap map4 = objectMapper.readValue(inputProcessedMapWkt4, typeReference); - - assertEquals(map1.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(0).value.getProperties().getOdeReceivedAt()); - assertEquals(map2.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(1).value.getProperties().getOdeReceivedAt()); - assertEquals(map4.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(2).value.getProperties().getOdeReceivedAt()); - - - - } catch (JsonMappingException e) { - e.printStackTrace(); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - } -} diff --git a/jpo-deduplicator/src/test/java/deduplicator/ProcessedSpatDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/ProcessedSpatDeduplicatorTopologyTest.java deleted file mode 100644 index 96fd9146..00000000 --- a/jpo-deduplicator/src/test/java/deduplicator/ProcessedSpatDeduplicatorTopologyTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package deduplicator; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KeyValue; -import org.apache.kafka.streams.TestInputTopic; -import org.apache.kafka.streams.TestOutputTopic; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.TopologyTestDriver; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedSpatDeduplicatorTopology; -import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; -import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; - - -public class ProcessedSpatDeduplicatorTopologyTest { - - String inputTopic = "topic.ProcessedSpat"; - String outputTopic = "topic.DeduplicatedProcessedSpat"; - - - TypeReference typeReference = new TypeReference<>(){}; - ObjectMapper objectMapper = new ObjectMapper(); - - String inputProcessedSpat1 = "{\"schemaVersion\":-1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2024-11-01T15:49:05.278Z\",\"originIp\":\"10.164.6.16\",\"name\":\"N State St & E Center St\",\"intersectionId\":6311,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id\",\"schemaPath\":\"#/$defs/J2735IntersectionReferenceID/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.maxEndTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"}],\"revision\":102,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":false,\"fixedTimeOperation\":false,\"trafficDependentOperation\":false,\"standbyOperation\":false,\"failureMode\":false,\"off\":false,\"recentMAPmessageUpdate\":true,\"recentChangeInMAPassignedLanesIDsUsed\":true,\"noValidMAPisAvailableAtThisTime\":false,\"noValidSPATisAvailableAtThisTime\":false},\"utcTimeStamp\":\"2024-11-01T15:49:05.278Z\",\"enabledLanes\":[],\"states\":[{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:04.237Z\",\"maxEndTime\":\"2024-11-01T15:50:04.237Z\"}}]},{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":3,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"PERMISSIVE_CLEARANCE\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:06.137Z\",\"maxEndTime\":\"2024-11-01T15:49:06.137Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:44.237Z\",\"maxEndTime\":\"2024-11-01T15:49:44.237Z\"}}]},{\"signalGroup\":7,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:05.237Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]}]}"; - String inputProcessedSpat2 = "{\"schemaVersion\":-1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2024-11-01T15:49:05.278Z\",\"originIp\":\"10.164.6.16\",\"name\":\"N State St & E Center St\",\"intersectionId\":6311,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id\",\"schemaPath\":\"#/$defs/J2735IntersectionReferenceID/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.maxEndTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"}],\"revision\":102,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":false,\"fixedTimeOperation\":false,\"trafficDependentOperation\":false,\"standbyOperation\":false,\"failureMode\":false,\"off\":false,\"recentMAPmessageUpdate\":true,\"recentChangeInMAPassignedLanesIDsUsed\":true,\"noValidMAPisAvailableAtThisTime\":false,\"noValidSPATisAvailableAtThisTime\":false},\"utcTimeStamp\":\"2024-11-01T15:49:05.378Z\",\"enabledLanes\":[],\"states\":[{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:04.237Z\",\"maxEndTime\":\"2024-11-01T15:50:04.237Z\"}}]},{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":3,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"PERMISSIVE_CLEARANCE\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:06.137Z\",\"maxEndTime\":\"2024-11-01T15:49:06.137Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:44.237Z\",\"maxEndTime\":\"2024-11-01T15:49:44.237Z\"}}]},{\"signalGroup\":7,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:05.237Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]}]}"; - String inputProcessedSpat3 = "{\"schemaVersion\":-1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2024-11-01T15:49:05.278Z\",\"originIp\":\"10.164.6.16\",\"name\":\"N State St & E Center St\",\"intersectionId\":6311,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id\",\"schemaPath\":\"#/$defs/J2735IntersectionReferenceID/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.maxEndTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"}],\"revision\":102,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":false,\"fixedTimeOperation\":false,\"trafficDependentOperation\":false,\"standbyOperation\":false,\"failureMode\":false,\"off\":false,\"recentMAPmessageUpdate\":true,\"recentChangeInMAPassignedLanesIDsUsed\":true,\"noValidMAPisAvailableAtThisTime\":false,\"noValidSPATisAvailableAtThisTime\":false},\"utcTimeStamp\":\"2024-11-01T15:50:05.478Z\",\"enabledLanes\":[],\"states\":[{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:04.237Z\",\"maxEndTime\":\"2024-11-01T15:50:04.237Z\"}}]},{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":3,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"PERMISSIVE_CLEARANCE\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:06.137Z\",\"maxEndTime\":\"2024-11-01T15:49:06.137Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:44.237Z\",\"maxEndTime\":\"2024-11-01T15:49:44.237Z\"}}]},{\"signalGroup\":7,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:05.237Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]}]}"; - String inputProcessedSpat4 = "{\"schemaVersion\":-1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2024-11-01T15:49:05.278Z\",\"originIp\":\"10.164.6.16\",\"name\":\"N State St & E Center St\",\"intersectionId\":6311,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id\",\"schemaPath\":\"#/$defs/J2735IntersectionReferenceID/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.maxEndTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"}],\"revision\":102,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":false,\"fixedTimeOperation\":false,\"trafficDependentOperation\":false,\"standbyOperation\":false,\"failureMode\":false,\"off\":false,\"recentMAPmessageUpdate\":true,\"recentChangeInMAPassignedLanesIDsUsed\":true,\"noValidMAPisAvailableAtThisTime\":false,\"noValidSPATisAvailableAtThisTime\":false},\"utcTimeStamp\":\"2024-11-01T15:50:05.578Z\",\"enabledLanes\":[],\"states\":[{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:04.237Z\",\"maxEndTime\":\"2024-11-01T15:50:04.237Z\"}}]},{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":3,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"PERMISSIVE_CLEARANCE\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:06.137Z\",\"maxEndTime\":\"2024-11-01T15:49:06.137Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:44.237Z\",\"maxEndTime\":\"2024-11-01T15:49:44.237Z\"}}]},{\"signalGroup\":7,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:05.237Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]}]}"; - String inputProcessedSpat5 = "{\"schemaVersion\":-1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2024-11-01T15:49:05.278Z\",\"originIp\":\"10.164.6.16\",\"name\":\"N State St & E Center St\",\"intersectionId\":6311,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id\",\"schemaPath\":\"#/$defs/J2735IntersectionReferenceID/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.maxEndTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"}],\"revision\":102,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":false,\"fixedTimeOperation\":false,\"trafficDependentOperation\":false,\"standbyOperation\":false,\"failureMode\":false,\"off\":false,\"recentMAPmessageUpdate\":true,\"recentChangeInMAPassignedLanesIDsUsed\":true,\"noValidMAPisAvailableAtThisTime\":false,\"noValidSPATisAvailableAtThisTime\":false},\"utcTimeStamp\":\"2024-11-01T15:50:05.678Z\",\"enabledLanes\":[],\"states\":[{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:04.237Z\",\"maxEndTime\":\"2024-11-01T15:50:04.237Z\"}}]},{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":3,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"PERMISSIVE_CLEARANCE\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:06.137Z\",\"maxEndTime\":\"2024-11-01T15:49:06.137Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:44.237Z\",\"maxEndTime\":\"2024-11-01T15:49:44.237Z\"}}]},{\"signalGroup\":7,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:05.237Z\"}}]}]}"; - String inputProcessedSpat6 = "{\"schemaVersion\":-1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2024-11-01T15:49:05.278Z\",\"originIp\":\"10.164.6.16\",\"name\":\"N State St & E Center St\",\"intersectionId\":6311,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id.region: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].id\",\"schemaPath\":\"#/$defs/J2735IntersectionReferenceID/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[0].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[1].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[2].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[3].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[4].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[5].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.maxEndTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[6].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.startTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"},{\"message\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing.nextTime: is missing but it is required\",\"jsonPath\":\"$.payload.data.intersectionStateList.intersectionStatelist[0].states.movementList[7].state_time_speed.movementEventList[0].timing\",\"schemaPath\":\"#/$defs/J2735TimeChangeDetails/required\"}],\"revision\":102,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":false,\"fixedTimeOperation\":false,\"trafficDependentOperation\":false,\"standbyOperation\":false,\"failureMode\":false,\"off\":false,\"recentMAPmessageUpdate\":true,\"recentChangeInMAPassignedLanesIDsUsed\":true,\"noValidMAPisAvailableAtThisTime\":false,\"noValidSPATisAvailableAtThisTime\":false},\"utcTimeStamp\":\"2024-11-01T15:50:05.778Z\",\"enabledLanes\":[],\"states\":[{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:04.237Z\",\"maxEndTime\":\"2024-11-01T15:50:04.237Z\"}}]},{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":3,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:50:24.237Z\",\"maxEndTime\":\"2024-11-01T15:50:24.237Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"PERMISSIVE_CLEARANCE\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:06.137Z\",\"maxEndTime\":\"2024-11-01T15:49:06.137Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:08.337Z\",\"maxEndTime\":\"2024-11-01T15:49:08.337Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:44.237Z\",\"maxEndTime\":\"2024-11-01T15:49:44.237Z\"}}]},{\"signalGroup\":9,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2024-11-01T15:49:05.237Z\"}}]}]}"; - - String key = "{\"rsuId\": \"10.164.6.16\", \"intersectionId\": 6311, \"region\": -1}"; - - @Autowired - DeduplicatorProperties props; - - - @Test - public void testTopology() { - - props = new DeduplicatorProperties(); - props.setKafkaTopicProcessedSpat(inputTopic); - props.setKafkaTopicDeduplicatedProcessedSpat(outputTopic); - - ProcessedSpatDeduplicatorTopology processedSpatDeduplicatorTopology = new ProcessedSpatDeduplicatorTopology(props, null); - - Topology topology = processedSpatDeduplicatorTopology.buildTopology(); - objectMapper.registerModule(new JavaTimeModule()); - - try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { - - - TestInputTopic inputProcessedSpatData = driver.createInputTopic( - inputTopic, - Serdes.String().serializer(), - Serdes.String().serializer()); - - - TestOutputTopic outputProcessedSpatData = driver.createOutputTopic( - outputTopic, - Serdes.String().deserializer(), - JsonSerdes.ProcessedSpat().deserializer()); - - inputProcessedSpatData.pipeInput(key, inputProcessedSpat1); - inputProcessedSpatData.pipeInput(key, inputProcessedSpat2); - inputProcessedSpatData.pipeInput(key, inputProcessedSpat3); - inputProcessedSpatData.pipeInput(key, inputProcessedSpat4); - inputProcessedSpatData.pipeInput(key, inputProcessedSpat5); - inputProcessedSpatData.pipeInput(key, inputProcessedSpat6); - - List> spatDeduplicatorResults = outputProcessedSpatData.readKeyValuesToList(); - - // validate that only 5 messages make it through - assertEquals(5, spatDeduplicatorResults.size()); - - ProcessedSpat spat1 = objectMapper.readValue(inputProcessedSpat1, typeReference); - ProcessedSpat spat3 = objectMapper.readValue(inputProcessedSpat3, typeReference); // forwarded because the time on the message changes by 1 minute - ProcessedSpat spat4 = objectMapper.readValue(inputProcessedSpat4, typeReference); // forwarded because the signal state changes - ProcessedSpat spat5 = objectMapper.readValue(inputProcessedSpat5, typeReference); // forwarded because the number of signal groups changed - ProcessedSpat spat6 = objectMapper.readValue(inputProcessedSpat6, typeReference); // forwarded because a signal group ID changed - - assertEquals(spat1.getUtcTimeStamp(), spatDeduplicatorResults.get(0).value.getUtcTimeStamp()); - assertEquals(spat3.getUtcTimeStamp(), spatDeduplicatorResults.get(1).value.getUtcTimeStamp()); - assertEquals(spat4.getUtcTimeStamp(), spatDeduplicatorResults.get(2).value.getUtcTimeStamp()); - assertEquals(spat5.getUtcTimeStamp(), spatDeduplicatorResults.get(3).value.getUtcTimeStamp()); - assertEquals(spat6.getUtcTimeStamp(), spatDeduplicatorResults.get(4).value.getUtcTimeStamp()); - - - } catch (JsonMappingException e) { - e.printStackTrace(); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - } -} diff --git a/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java deleted file mode 100644 index 164dd220..00000000 --- a/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java +++ /dev/null @@ -1,89 +0,0 @@ -package deduplicator; - -import org.apache.kafka.common.serialization.Serdes; -import org.apache.kafka.streams.KeyValue; -import org.apache.kafka.streams.TestInputTopic; -import org.apache.kafka.streams.TestOutputTopic; -import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.TopologyTestDriver; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - -import us.dot.its.jpo.deduplicator.DeduplicatorProperties; -import us.dot.its.jpo.deduplicator.deduplicator.topologies.TimDeduplicatorTopology; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; - - -public class TimDeduplicatorTopologyTest { - - String inputTopic = "topic.OdeTimJson"; - String outputTopic = "topic.DeduplicatedOdeTimJson"; - - ObjectMapper objectMapper = new ObjectMapper(); - - //Original Message - String inputTim1 = "{\"metadata\":{\"securityResultCode\":\"success\",\"recordGeneratedBy\":\"RSU\",\"schemaVersion\":\"6\",\"odePacketID\":\"\",\"sanitized\":\"false\",\"recordType\":\"timMsg\",\"recordGeneratedAt\":\"\",\"maxDurationTime\":\"0\",\"odeTimStartDateTime\":\"\",\"receivedMessageDetails\":\"\",\"payloadType\":\"us.dot.its.jpo.ode.model.OdeTimPayload\",\"serialId\":{\"recordId\":\"0\",\"serialNumber\":\"0\",\"streamId\":\"d052115a-5289-4da3-bc9f-12edca1d2c46\",\"bundleSize\":\"1\",\"bundleId\":\"0\"},\"logFileName\":\"\",\"odeReceivedAt\":\"2024-07-23T18:33:17.328Z\",\"originIp\":\"10.16.28.54\"},\"payload\":{\"data\":{\"MessageFrame\":{\"messageId\":\"31\",\"value\":{\"TravelerInformation\":{\"timeStamp\":\"264703\",\"packetID\":\"0350C30EB1A83736D8\",\"urlB\":\"null\",\"dataFrames\":{\"TravelerDataFrame\":{\"durationTime\":\"30\",\"regions\":{\"GeographicalPath\":{\"closedPath\":{\"false\":\"\"},\"anchor\":{\"lat\":\"395658598\",\"long\":\"-1050401840\"},\"name\":\"I_CO-470_RSU_172.16.28.116\",\"laneWidth\":\"5000\",\"directionality\":{\"both\":\"\"},\"description\":{\"path\":{\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":[{\"delta\":{\"node-LL1\":{\"lon\":\"1527\",\"lat\":\"-659\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"5545\",\"lat\":\"-2394\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"9493\",\"lat\":\"-2736\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"7465\",\"lat\":\"-1304\"}}},{\"delta\":{\"node-LL4\":{\"lon\":\"34464\",\"lat\":\"-4324\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"9994\",\"lat\":\"-1119\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"20051\",\"lat\":\"-2246\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"31738\",\"lat\":\"-1775\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"5744\",\"lat\":\"-315\"}}}]}}},\"scale\":\"0\"}},\"id\":{\"id\":\"0\",\"region\":\"0\"},\"direction\":\"0000110000000000\"}},\"startYear\":\"2024\",\"notUsed2\":\"0\",\"msgId\":{\"roadSignID\":{\"viewAngle\":\"1111111111111111\",\"mutcdCode\":{\"warning\":\"\"},\"position\":{\"lat\":\"395658598\",\"long\":\"-1050401840\"}}},\"notUsed3\":\"0\",\"notUsed1\":\"0\",\"priority\":\"5\",\"content\":{\"workZone\":{\"SEQUENCE\":{\"item\":{\"itis\":\"1025\"}}}},\"url\":\"null\",\"notUsed\":\"0\",\"frameType\":{\"advisory\":\"\"},\"startTime\":\"277110\"}},\"msgCnt\":\"1\"}}}},\"dataType\":\"TravelerInformation\"}}"; - - // Shifted Forward .1 seconds - Should be deduplicated - String inputTim2 = "{\"metadata\":{\"securityResultCode\":\"success\",\"recordGeneratedBy\":\"RSU\",\"schemaVersion\":\"6\",\"odePacketID\":\"\",\"sanitized\":\"false\",\"recordType\":\"timMsg\",\"recordGeneratedAt\":\"\",\"maxDurationTime\":\"0\",\"odeTimStartDateTime\":\"\",\"receivedMessageDetails\":\"\",\"payloadType\":\"us.dot.its.jpo.ode.model.OdeTimPayload\",\"serialId\":{\"recordId\":\"0\",\"serialNumber\":\"0\",\"streamId\":\"d052115a-5289-4da3-bc9f-12edca1d2c46\",\"bundleSize\":\"1\",\"bundleId\":\"0\"},\"logFileName\":\"\",\"odeReceivedAt\":\"2024-07-23T18:33:17.428Z\",\"originIp\":\"10.16.28.54\"},\"payload\":{\"data\":{\"MessageFrame\":{\"messageId\":\"31\",\"value\":{\"TravelerInformation\":{\"timeStamp\":\"264703\",\"packetID\":\"0350C30EB1A83736D8\",\"urlB\":\"null\",\"dataFrames\":{\"TravelerDataFrame\":{\"durationTime\":\"30\",\"regions\":{\"GeographicalPath\":{\"closedPath\":{\"false\":\"\"},\"anchor\":{\"lat\":\"395658598\",\"long\":\"-1050401840\"},\"name\":\"I_CO-470_RSU_172.16.28.116\",\"laneWidth\":\"5000\",\"directionality\":{\"both\":\"\"},\"description\":{\"path\":{\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":[{\"delta\":{\"node-LL1\":{\"lon\":\"1527\",\"lat\":\"-659\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"5545\",\"lat\":\"-2394\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"9493\",\"lat\":\"-2736\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"7465\",\"lat\":\"-1304\"}}},{\"delta\":{\"node-LL4\":{\"lon\":\"34464\",\"lat\":\"-4324\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"9994\",\"lat\":\"-1119\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"20051\",\"lat\":\"-2246\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"31738\",\"lat\":\"-1775\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"5744\",\"lat\":\"-315\"}}}]}}},\"scale\":\"0\"}},\"id\":{\"id\":\"0\",\"region\":\"0\"},\"direction\":\"0000110000000000\"}},\"startYear\":\"2024\",\"notUsed2\":\"0\",\"msgId\":{\"roadSignID\":{\"viewAngle\":\"1111111111111111\",\"mutcdCode\":{\"warning\":\"\"},\"position\":{\"lat\":\"395658598\",\"long\":\"-1050401840\"}}},\"notUsed3\":\"0\",\"notUsed1\":\"0\",\"priority\":\"5\",\"content\":{\"workZone\":{\"SEQUENCE\":{\"item\":{\"itis\":\"1025\"}}}},\"url\":\"null\",\"notUsed\":\"0\",\"frameType\":{\"advisory\":\"\"},\"startTime\":\"277110\"}},\"msgCnt\":\"1\"}}}},\"dataType\":\"TravelerInformation\"}}"; - - // Shifted Forward 1 hour Should be allowed to pass through - String inputTim3 = "{\"metadata\":{\"securityResultCode\":\"success\",\"recordGeneratedBy\":\"RSU\",\"schemaVersion\":\"6\",\"odePacketID\":\"\",\"sanitized\":\"false\",\"recordType\":\"timMsg\",\"recordGeneratedAt\":\"\",\"maxDurationTime\":\"0\",\"odeTimStartDateTime\":\"\",\"receivedMessageDetails\":\"\",\"payloadType\":\"us.dot.its.jpo.ode.model.OdeTimPayload\",\"serialId\":{\"recordId\":\"0\",\"serialNumber\":\"0\",\"streamId\":\"d052115a-5289-4da3-bc9f-12edca1d2c46\",\"bundleSize\":\"1\",\"bundleId\":\"0\"},\"logFileName\":\"\",\"odeReceivedAt\":\"2024-07-23T19:33:17.428Z\",\"originIp\":\"10.16.28.54\"},\"payload\":{\"data\":{\"MessageFrame\":{\"messageId\":\"31\",\"value\":{\"TravelerInformation\":{\"timeStamp\":\"264703\",\"packetID\":\"0350C30EB1A83736D8\",\"urlB\":\"null\",\"dataFrames\":{\"TravelerDataFrame\":{\"durationTime\":\"30\",\"regions\":{\"GeographicalPath\":{\"closedPath\":{\"false\":\"\"},\"anchor\":{\"lat\":\"395658598\",\"long\":\"-1050401840\"},\"name\":\"I_CO-470_RSU_172.16.28.116\",\"laneWidth\":\"5000\",\"directionality\":{\"both\":\"\"},\"description\":{\"path\":{\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":[{\"delta\":{\"node-LL1\":{\"lon\":\"1527\",\"lat\":\"-659\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"5545\",\"lat\":\"-2394\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"9493\",\"lat\":\"-2736\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"7465\",\"lat\":\"-1304\"}}},{\"delta\":{\"node-LL4\":{\"lon\":\"34464\",\"lat\":\"-4324\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"9994\",\"lat\":\"-1119\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"20051\",\"lat\":\"-2246\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"31738\",\"lat\":\"-1775\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"5744\",\"lat\":\"-315\"}}}]}}},\"scale\":\"0\"}},\"id\":{\"id\":\"0\",\"region\":\"0\"},\"direction\":\"0000110000000000\"}},\"startYear\":\"2024\",\"notUsed2\":\"0\",\"msgId\":{\"roadSignID\":{\"viewAngle\":\"1111111111111111\",\"mutcdCode\":{\"warning\":\"\"},\"position\":{\"lat\":\"395658598\",\"long\":\"-1050401840\"}}},\"notUsed3\":\"0\",\"notUsed1\":\"0\",\"priority\":\"5\",\"content\":{\"workZone\":{\"SEQUENCE\":{\"item\":{\"itis\":\"1025\"}}}},\"url\":\"null\",\"notUsed\":\"0\",\"frameType\":{\"advisory\":\"\"},\"startTime\":\"277110\"}},\"msgCnt\":\"1\"}}}},\"dataType\":\"TravelerInformation\"}}"; - - // Has a different payload ID. Should be allowed through - String inputTim4 = "{\"metadata\":{\"securityResultCode\":\"success\",\"recordGeneratedBy\":\"RSU\",\"schemaVersion\":\"6\",\"odePacketID\":\"\",\"sanitized\":\"false\",\"recordType\":\"timMsg\",\"recordGeneratedAt\":\"\",\"maxDurationTime\":\"0\",\"odeTimStartDateTime\":\"\",\"receivedMessageDetails\":\"\",\"payloadType\":\"us.dot.its.jpo.ode.model.OdeTimPayload\",\"serialId\":{\"recordId\":\"0\",\"serialNumber\":\"0\",\"streamId\":\"d052115a-5289-4da3-bc9f-12edca1d2c46\",\"bundleSize\":\"1\",\"bundleId\":\"0\"},\"logFileName\":\"\",\"odeReceivedAt\":\"2024-07-23T19:34:17.328Z\",\"originIp\":\"10.16.28.54\"},\"payload\":{\"data\":{\"MessageFrame\":{\"messageId\":\"31\",\"value\":{\"TravelerInformation\":{\"timeStamp\":\"264703\",\"packetID\":\"0350C30EB1A83736D9\",\"urlB\":\"null\",\"dataFrames\":{\"TravelerDataFrame\":{\"durationTime\":\"30\",\"regions\":{\"GeographicalPath\":{\"closedPath\":{\"false\":\"\"},\"anchor\":{\"lat\":\"395658598\",\"long\":\"-1050401840\"},\"name\":\"I_CO-470_RSU_172.16.28.116\",\"laneWidth\":\"10000\",\"directionality\":{\"both\":\"\"},\"description\":{\"path\":{\"offset\":{\"ll\":{\"nodes\":{\"NodeLL\":[{\"delta\":{\"node-LL1\":{\"lon\":\"1527\",\"lat\":\"-659\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"5545\",\"lat\":\"-2394\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"9493\",\"lat\":\"-2736\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"7465\",\"lat\":\"-1304\"}}},{\"delta\":{\"node-LL4\":{\"lon\":\"34464\",\"lat\":\"-4324\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"9994\",\"lat\":\"-1119\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"20051\",\"lat\":\"-2246\"}}},{\"delta\":{\"node-LL3\":{\"lon\":\"31738\",\"lat\":\"-1775\"}}},{\"delta\":{\"node-LL2\":{\"lon\":\"5744\",\"lat\":\"-315\"}}}]}}},\"scale\":\"0\"}},\"id\":{\"id\":\"0\",\"region\":\"0\"},\"direction\":\"0000110000000000\"}},\"startYear\":\"2024\",\"notUsed2\":\"0\",\"msgId\":{\"roadSignID\":{\"viewAngle\":\"1111111111111111\",\"mutcdCode\":{\"warning\":\"\"},\"position\":{\"lat\":\"395658598\",\"long\":\"-1050401840\"}}},\"notUsed3\":\"0\",\"notUsed1\":\"0\",\"priority\":\"5\",\"content\":{\"workZone\":{\"SEQUENCE\":{\"item\":{\"itis\":\"1025\"}}}},\"url\":\"null\",\"notUsed\":\"0\",\"frameType\":{\"advisory\":\"\"},\"startTime\":\"277110\"}},\"msgCnt\":\"1\"}}}},\"dataType\":\"TravelerInformation\"}}"; - - @Autowired - DeduplicatorProperties props; - - @Test - public void testTopology() { - - props = new DeduplicatorProperties(); - props.setKafkaTopicOdeTimJson(inputTopic); - props.setKafkaTopicDeduplicatedOdeTimJson(outputTopic); - - TimDeduplicatorTopology TimDeduplicatorTopology = new TimDeduplicatorTopology(props, null); - - Topology topology = TimDeduplicatorTopology.buildTopology(); - objectMapper.registerModule(new JavaTimeModule()); - - try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { - - - TestInputTopic inputTimData = driver.createInputTopic( - inputTopic, - Serdes.Void().serializer(), - Serdes.String().serializer()); - - - TestOutputTopic outputTimData = driver.createOutputTopic( - outputTopic, - Serdes.String().deserializer(), - Serdes.String().deserializer()); - - inputTimData.pipeInput(null, inputTim1); - inputTimData.pipeInput(null, inputTim2); - inputTimData.pipeInput(null, inputTim3); - inputTimData.pipeInput(null, inputTim4); - - List> timDeduplicatedResults = outputTimData.readKeyValuesToList(); - - // validate that only 3 messages make it through - assertEquals(3, timDeduplicatedResults.size()); - inputTim1 = inputTim1.strip(); - - assertEquals(inputTim1.replace(" ", ""), timDeduplicatedResults.get(0).value.replace(" ", "")); - assertEquals(inputTim3.replace(" ", ""), timDeduplicatedResults.get(1).value.replace(" ", "")); - assertEquals(inputTim4.replace(" ", ""), timDeduplicatedResults.get(2).value.replace(" ", "")); - - }catch(Exception e){ - e.printStackTrace(); - } - } -} diff --git a/jpo-deduplicator/src/test/resources/application-testConfig.yaml b/jpo-deduplicator/src/test/resources/application-testConfig.yaml deleted file mode 100644 index 4f102d0a..00000000 --- a/jpo-deduplicator/src/test/resources/application-testConfig.yaml +++ /dev/null @@ -1 +0,0 @@ -spring.kafka.bootstrap-servers: localhost:10093 \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/logback-test.xml b/jpo-deduplicator/src/test/resources/logback-test.xml deleted file mode 100644 index cd07f49c..00000000 --- a/jpo-deduplicator/src/test/resources/logback-test.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - %msg%n - - - - - - - \ No newline at end of file From d407e565cf2373b848813008af30f8ddc5ce6d22 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Wed, 8 Jan 2025 12:05:04 -0700 Subject: [PATCH 15/25] Updating test-message-sender --- test-message-sender/message-sender/pom.xml | 4 ++-- test-message-sender/pom.xml | 4 ++-- test-message-sender/script-runner/pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test-message-sender/message-sender/pom.xml b/test-message-sender/message-sender/pom.xml index 89627f6c..94fddeb9 100644 --- a/test-message-sender/message-sender/pom.xml +++ b/test-message-sender/message-sender/pom.xml @@ -5,7 +5,7 @@ usdot.jpo.ode message-sender-parent - 1.0-SNAPSHOT + 1.1-SNAPSHOT message-sender message-sender @@ -49,7 +49,7 @@ usdot.jpo.ode jpo-geojsonconverter - 1.4.2 + 2.0.0 ch.qos.logback diff --git a/test-message-sender/pom.xml b/test-message-sender/pom.xml index 195ddb55..32ee375f 100644 --- a/test-message-sender/pom.xml +++ b/test-message-sender/pom.xml @@ -6,14 +6,14 @@ org.springframework.boot spring-boot-starter-parent - 3.2.3 + 3.2.12 usdot.jpo.ode message-sender-parent pom - 1.0-SNAPSHOT + 1.1-SNAPSHOT test-message-sender Parent project for ODE test message sender diff --git a/test-message-sender/script-runner/pom.xml b/test-message-sender/script-runner/pom.xml index 52dccce9..6b57eb16 100644 --- a/test-message-sender/script-runner/pom.xml +++ b/test-message-sender/script-runner/pom.xml @@ -6,7 +6,7 @@ usdot.jpo.ode message-sender-parent - 1.0-SNAPSHOT + 1.1-SNAPSHOT script-runner script-runner From 6f3061a2fc8b0830d3bff4a492710c90c3eeb168 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:47:05 -0700 Subject: [PATCH 16/25] Update agg code --- ...smMessageCountProgressionAggregationKey.java | 6 +++--- .../BsmMessageCountProgressionProcessor.java | 17 +++++++++-------- .../BsmMessageCountProgressionTopology.java | 17 +++++++++-------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/aggregation/bsm_message_count_progression/BsmMessageCountProgressionAggregationKey.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/aggregation/bsm_message_count_progression/BsmMessageCountProgressionAggregationKey.java index 9d095675..33646e69 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/aggregation/bsm_message_count_progression/BsmMessageCountProgressionAggregationKey.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/aggregation/bsm_message_count_progression/BsmMessageCountProgressionAggregationKey.java @@ -1,13 +1,13 @@ package us.dot.its.jpo.conflictmonitor.monitor.algorithms.aggregation.bsm_message_count_progression; import lombok.*; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; -import us.dot.its.jpo.geojsonconverter.partitioner.RsuIdKey; + +import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; @EqualsAndHashCode(callSuper = true) @Data @Generated -public class BsmMessageCountProgressionAggregationKey extends BsmRsuIdKey { +public class BsmMessageCountProgressionAggregationKey extends RsuLogKey { private String dataFrame; private String change; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java index 28bce71c..f1eff239 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/BsmMessageCountProgressionProcessor.java @@ -14,8 +14,9 @@ import org.apache.kafka.streams.state.VersionedRecordIterator; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_message_count_progression.BsmMessageCountProgressionParameters; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; + import us.dot.its.jpo.conflictmonitor.monitor.models.events.BsmMessageCountProgressionEvent; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.BsmProperties; @@ -25,10 +26,10 @@ // TODO Use RsuLogKey @Slf4j -public class BsmMessageCountProgressionProcessor extends ContextualProcessor, BsmRsuIdKey, BsmMessageCountProgressionEvent> { +public class BsmMessageCountProgressionProcessor extends ContextualProcessor, RsuLogKey, BsmMessageCountProgressionEvent> { - private VersionedKeyValueStore> stateStore; - private KeyValueStore> lastProcessedStateStore; + private VersionedKeyValueStore> stateStore; + private KeyValueStore> lastProcessedStateStore; private final BsmMessageCountProgressionParameters parameters; public BsmMessageCountProgressionProcessor(BsmMessageCountProgressionParameters parameters) { @@ -36,15 +37,15 @@ public BsmMessageCountProgressionProcessor(BsmMessageCountProgressionParameters } @Override - public void init(ProcessorContext context) { + public void init(ProcessorContext context) { super.init(context); stateStore = context.getStateStore(parameters.getProcessedBsmStateStoreName()); lastProcessedStateStore = context.getStateStore(parameters.getLatestBsmStateStoreName()); } @Override - public void process(Record> record) { - BsmRsuIdKey key = record.key(); + public void process(Record> record) { + RsuLogKey key = record.key(); ProcessedBsm value = record.value(); long timestamp = record.timestamp(); @@ -71,7 +72,7 @@ public void process(Record> record) { excludeGracePeriod = startTime; } - var query = MultiVersionedKeyQuery.>withKey(record.key()) + var query = MultiVersionedKeyQuery.>withKey(record.key()) .fromTime(startTime.minusMillis(1)) // Add a small buffer to include the exact startTime record .toTime(excludeGracePeriod) .withAscendingTimestamps(); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java index 107a3012..56c9615d 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmMessageCountProgressionTopology.java @@ -1,7 +1,7 @@ package us.dot.its.jpo.conflictmonitor.monitor.topologies; import lombok.extern.slf4j.Slf4j; -import org.apache.kafka.common.serialization.Serdes; + import org.apache.kafka.streams.StreamsBuilder; import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.kstream.Consumed; @@ -17,8 +17,9 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.aggregation.bsm_message_count_progression.BsmMessageCountProgressionAggregationStreamsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_message_count_progression.BsmMessageCountProgressionParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_message_count_progression.BsmMessageCountProgressionStreamsAlgorithm; -import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; + import us.dot.its.jpo.geojsonconverter.partitioner.RsuIdPartitioner; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuLogKey; import us.dot.its.jpo.geojsonconverter.pojos.geojson.bsm.ProcessedBsm; import us.dot.its.jpo.geojsonconverter.pojos.geojson.Point; import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; @@ -28,7 +29,6 @@ import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_message_count_progression.BsmMessageCountProgressionConstants.DEFAULT_BSM_MESSAGE_COUNT_PROGRESSION_ALGORITHM; -// TODO Use RsuLogKey @Component(DEFAULT_BSM_MESSAGE_COUNT_PROGRESSION_ALGORITHM) @Slf4j public class BsmMessageCountProgressionTopology @@ -53,7 +53,7 @@ public Topology buildTopology() { builder.addStateStore( Stores.versionedKeyValueStoreBuilder( Stores.persistentVersionedKeyValueStore(processedBsmStateStore, retentionTime), - us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.BsmRsuIdKey(), + JsonSerdes.RsuLogKey(), JsonSerdes.ProcessedBsm() ) ); @@ -61,13 +61,13 @@ public Topology buildTopology() { builder.addStateStore( Stores.keyValueStoreBuilder( Stores.persistentKeyValueStore(latestBsmStateStore), - us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.BsmRsuIdKey(), + JsonSerdes.RsuLogKey(), JsonSerdes.ProcessedBsm() ) ); - KStream> inputStream = builder.stream(parameters.getBsmInputTopicName(), + KStream> inputStream = builder.stream(parameters.getBsmInputTopicName(), Consumed.with( - us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.BsmRsuIdKey(), + JsonSerdes.RsuLogKey(), JsonSerdes.ProcessedBsm())); @@ -81,6 +81,7 @@ public Topology buildTopology() { var aggKey = new BsmMessageCountProgressionAggregationKey(); aggKey.setRsuId(key.getRsuId()); aggKey.setBsmId(key.getBsmId()); + aggKey.setLogId(key.getLogId()); // TODO: //aggKey.setDataFrame(value.getDataFrame()); //aggKey.setChange(value.getChange()); @@ -98,7 +99,7 @@ public Topology buildTopology() { // Don't aggregate events eventStream.to(parameters.getBsmMessageCountProgressionEventOutputTopicName(), Produced.with( - us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.BsmRsuIdKey(), + JsonSerdes.RsuLogKey(), us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.BsmMessageCountProgressionEvent())); } return builder.build(); From d7c683dbb5ac78483a0821cc7ec5df290702a6c4 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Wed, 8 Jan 2025 17:36:07 -0700 Subject: [PATCH 17/25] Update jpo-utils. Use specific image versions in docker compose. --- docker-compose-ode.yml | 6 +++--- docker-compose.yml | 4 ++-- jpo-utils | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docker-compose-ode.yml b/docker-compose-ode.yml index aaa7c6dc..1af39eab 100644 --- a/docker-compose-ode.yml +++ b/docker-compose-ode.yml @@ -7,7 +7,7 @@ services: - all - cm_full - ode_geojsonconverter - image: usdotjpoode/geojsonconverter:latest + image: usdotjpoode/geojsonconverter:2.0.0 restart: ${RESTART_POLICY} deploy: resources: @@ -36,7 +36,7 @@ services: - all - cm_full - ode_geojsonconverter - image: usdotjpoode/jpo-ode:latest + image: usdotjpoode/jpo-ode:4.0.0 restart: ${RESTART_POLICY} deploy: resources: @@ -82,7 +82,7 @@ services: - all - cm_full - ode_geojsonconverter - image: usdotjpoode/asn1_codec:latest + image: usdotjpoode/asn1_codec:3.0.0 restart: ${RESTART_POLICY} deploy: resources: diff --git a/docker-compose.yml b/docker-compose.yml index d12d26f5..a7de55ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ -#include: -# - docker-compose-ode.yml +include: + - docker-compose-ode.yml services: conflictmonitor-build: diff --git a/jpo-utils b/jpo-utils index 2c461202..4b6c7a7c 160000 --- a/jpo-utils +++ b/jpo-utils @@ -1 +1 @@ -Subproject commit 2c46120222e127d599663376134ab060d0e2587f +Subproject commit 4b6c7a7c7edee2475f7d5d5c9ff3681aeade783e From eb33f258e4ec6fee8f4bbfb7d59335aa3fa05b29 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Thu, 9 Jan 2025 13:55:54 -0700 Subject: [PATCH 18/25] Temporarily change maven repo --- settings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/settings.xml b/settings.xml index 825356ac..3595efbc 100644 --- a/settings.xml +++ b/settings.xml @@ -23,7 +23,8 @@ github GitHub JPO Conflict Monitor - https://maven.pkg.github.com/${env.MAVEN_GITHUB_ORG}/* + + https://maven.pkg.github.com/iyourshaw/* false From 2bf8d33a7d335c4bbcfa34916d92c546c6622367 Mon Sep 17 00:00:00 2001 From: Ivan Yourshaw <39739503+iyourshaw@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:36:45 -0700 Subject: [PATCH 19/25] Add ability to send ProcessdBsms to script runner --- .../scriptrunner/ScriptRunner.java | 72 +++++++++++++------ .../scriptrunner/SendMessageJob.java | 21 +++++- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptRunner.java b/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptRunner.java index 272a3e19..2f156183 100644 --- a/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptRunner.java +++ b/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptRunner.java @@ -2,11 +2,7 @@ import java.io.File; import java.io.FileNotFoundException; -import java.time.Duration; import java.time.Instant; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.util.Random; import java.util.Scanner; import java.util.regex.Matcher; @@ -27,7 +23,11 @@ public class ScriptRunner { private final static Logger logger = LoggerFactory.getLogger(ScriptRunner.class); - private final static Pattern linePattern = Pattern.compile("^(?BSM|SPAT|MAP|ProcessedMap|ProcessedSpat)(;(?[A-Za-z0-9.]+);(?\\d+))?,(?